來玩玩打地鼠遊戲,300行代碼不到

  • 2019 年 10 月 8 日
  • 筆記

所用到的圖片:

圖1代碼:

import javafx.animation.KeyFrame  import javafx.animation.Timeline  import javafx.event.ActionEvent  import javafx.event.EventHandler  import javafx.geometry.Pos  import javafx.scene.effect.DropShadow  import javafx.scene.image.Image  import javafx.scene.image.ImageView  import javafx.scene.layout.*  import javafx.scene.layout.BorderPane.setAlignment  import javafx.scene.paint.Color  import javafx.scene.paint.Color.rgb  import javafx.scene.shape.Line  import javafx.scene.text.Font  import javafx.scene.text.FontPosture  import javafx.scene.text.FontWeight  import javafx.util.Duration  import tornadofx.*    class MyMoleApp : App(MyMole::class) {      override fun stop() {          find<StartGame>().replaceWith<MyMole>()          super.stop()      }  }    class MyMole : View("打地鼠") {      override val root = borderpane {          setPrefSize(1000.0, 768.0)          val back = BackgroundImage(Image("whacAMole/mole.jpg", 1024.0, 768.0, false, true),                  BackgroundRepeat.REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, BackgroundSize.DEFAULT)          background = Background(back)          top = label("Whac A Mole") {              font = Font.font("Showcard Gothic", FontWeight.EXTRA_BOLD, FontPosture.REGULAR, 100.0)              textFill = rgb(150, 46, 5)              style = "-fx-text-border-color:rgb(138,95,69);"              alignment = Pos.BASELINE_CENTER          }          setAlignment(top, Pos.CENTER)          center = gridpane {              vgap = 5.0              hgap = 5.0              alignment = Pos.CENTER                button("Start") {                  background = null                  textFill = rgb(195, 46, 5)                  font = Font.font("Bauhaus 93", FontWeight.EXTRA_BOLD, FontPosture.ITALIC, 90.0)                  setOnMouseEntered {                      effect = DropShadow()                  }                  setOnMouseExited {                      effect = null                  }                  action {                      replaceWith(StartGame::class)                  }              }          }      }  }    class StartGame : View("打地鼠") {      private var count = 0  // 打中地鼠數量      private val tfCount = intProperty()  //顯示打中地鼠數量      private val msg = stringProperty()      private var hammerView by singleAssign<ImageView>()      private var ifHit = true //判斷是否可以打地鼠,true時能擊打      private var pause = false      val x1 = 256.0      val y1 = 192.0      val xx = 256.0      val yy = 160.0 //第一個地洞位置及間隔      //地鼠圖像      private val mouseList = (0..2).map {          imageview("whacAMole/mouse$it.png") {              fitWidth = 120.0              fitHeight = 210.0              x = x1 - 70              y = y1 - 90          }      }        override val root = pane {          val pane1 = this          setPrefSize(1024.0, 768.0)          val eventHandler = EventHandler<ActionEvent> {              //地鼠運動              val lineList = (0..2).map { MouseAppear() }              lineList.forEach { pane1.add(it) }                var i = 0              mouseList.forEach {                  //地鼠漸變                  it.fade(Duration.millis(4000.0 + i * 1000), 0) {                      fromValue = 1.0                      toValue = 0.1                      cycleCount = 1                  }                  //地鼠運動                  it.follow(Duration.millis(400.0 + i * 200), lineList[i]) {                      cycleCount = 2                      isAutoReverse = true                  }                    i++              }              //置為能打              ifHit=true              // 鎚子打下去、抬起來效果              pane1.setOnMouseReleased { e1 ->                  hammerView.rotateProperty().animate(endValue = 0.0, duration = 0.1.seconds)              }              //打中地鼠記錄次數 鼠標事件              pane1.setOnMousePressed { e1 ->                  hammerView.rotateProperty().animate(endValue = -40.0, duration = 0.1.seconds)                    var i = 0                  lineList.forEach {                      if (e1.x < it.endX + 80 && e1.x > it.endX - 80 && ifHit                              && e1.y < it.startY + 110 && e1.y > it.endY - 110) {                          count++                            //文本框輸出                          tfCount.value = count                          ifHit = false  //置為不能打                      }                      i++                  }              }          }            //動畫          val animation = Timeline(KeyFrame(Duration.millis(1300.0), eventHandler)) //地鼠速度          animation.cycleCount = 30  //地鼠鑽出次數          animation.play()          //地洞圖像          imageview("whacAMole/mole.jpg") {              fitWidth = 1024.0              fitHeight = 768.0          }          hbox(20.0) {              addStylesheet(MyStyle::class)              alignment = Pos.BOTTOM_CENTER              //重新開始按鈕              button("Quit") {                  background = null                  setOnMouseEntered {                      effect = DropShadow()                  }                  setOnMouseExited {                      effect = null                  }                  action {                      animation.stop()                      //animation1.stop();                      count = 0                      tfCount.value = 0                      msg.value = ""                      replaceWith(MyMole::class)                  }              }              //暫停按鈕              button("Pause/Continue") {                  background = null                  setOnMouseEntered {                      effect = DropShadow()                  }                  setOnMouseExited {                      effect = null                  }                  action {                      if (!pause) {                          animation.pause()                          pause = true                      } else {                          animation.play()                          pause = false                      }                  }              }              textfield(tfCount) {                  setPrefSize(200.0, 40.0)                  style = "-fx-text-fill:rgb(195,46,5);"                  background = null                  font = Font.font("Bauhaus 93", FontWeight.EXTRA_BOLD, FontPosture.ITALIC, 80.0)              }          }          text(msg) {              fill = rgb(222, 87, 61)              font = Font.font("Kristen ITC", FontWeight.BOLD, FontPosture.ITALIC, 45.0)              x = 280.0              y = 700.0          }          mouseList.forEach {              add(it)          }          //鎚子圖像          imageview("whacAMole/hammer.png") {              hammerView = this              fitWidth = 160.0              fitHeight = 200.0          }          //事件源必須設在pane上,不能設在圖片上,否則鼠標要放在圖片上才能動          setOnMouseMoved { e ->              hammerView.x = e.x - 60              hammerView.y = e.y - 80          }      }        private fun MouseAppear(): Line {          val ran = (Math.random() * 10.0 * 0.9).toInt()          var x0 = x1          var y0 = y1          when (ran) {              0 -> {                  x0 = x1                  y0 = y1              }              1 -> {                  x0 = x1 + xx - 20                  y0 = y1              }              2 -> {                  x0 = x1 + xx * 2 - 20                  y0 = y1              }              3 -> {                  x0 = x1 - 50                  y0 = y1 + yy - 15              }              4 -> {                  x0 = x1 + xx - 20                  y0 = y1 + yy              }              5 -> {                  x0 = x1 + xx * 2 - 20                  y0 = y1 + yy              }              6 -> {                  x0 = x1 - 60                  y0 = y1 + yy * 2 - 10              }              7 -> {                  x0 = x1 + xx - 20                  y0 = y1 + yy * 2              }              8 -> {                  x0 = x1 + xx * 2                  y0 = y1 + yy * 2              }          }          val line = Line(x0, y0 + 30, x0, y0 - 50)          line.stroke = Color.TRANSPARENT          return line      }  }    class MyStyle : Stylesheet() {      init {          button {              textFill = rgb(195, 46, 150)              prefWidth = 400.px              prefHeight = 80.px              font = Font.font("Showcard Gothic", FontWeight.EXTRA_BOLD, FontPosture.ITALIC, 30.0)          }      }  }

圖2代碼:

import javafx.animation.KeyFrame  import javafx.animation.Timeline  import javafx.event.ActionEvent  import javafx.event.EventHandler  import javafx.geometry.Pos  import javafx.scene.effect.DropShadow  import javafx.scene.image.ImageView  import javafx.scene.paint.Color  import javafx.scene.shape.Line  import javafx.scene.text.Font  import javafx.scene.text.FontPosture  import javafx.scene.text.FontWeight  import javafx.util.Duration  import tornadofx.*  class MyMoleApp1 : App(StartGame1::class)  class StartGame1 : View("打地鼠") {      private var count = 0  // 打中地鼠數量      private val tfCount = intProperty()  //顯示打中地鼠數量      private val msg = stringProperty()      private var hammerView by singleAssign<ImageView>()      private var ifHit = true //判斷是否可以打地鼠,true時能擊打      private var pause = false      val x1 = 256.0      val y1 = 192.0      val xx = 256.0      val yy = 160.0 //第一個地洞位置及間隔      //地鼠圖像      private val mouseList = (0..2).map {          imageview("whacAMole/mouse$it.png") {              fitWidth = 120.0              fitHeight = 110.0              x = x1 - 70              y = y1 -30          }      }        override val root = stackpane {          setPrefSize(1024.0, 768.0)          imageview("whacAMole/mole.jpg") {              fitWidth = 1024.0              fitHeight = 768.0          }          pane {              val pane1 = this              setPrefSize(1024.0, 768.0)              val eventHandler = EventHandler<ActionEvent> {                  //地鼠運動                  val lineList = (0..2).map { MouseAppear() }                  lineList.forEach { pane1.add(it) }                    var i = 0                  mouseList.forEach {                      //地鼠漸變                      it.fade(Duration.millis(4000.0 + i * 1000), 0) {                          fromValue = 1.0                          toValue = 0.1                          cycleCount = 1                      }                      //地鼠運動                      it.follow(Duration.millis(400.0 + i * 200), lineList[i]) {                          cycleCount = 2                          isAutoReverse = true                      }                        i++                  }                  //置為能打                  ifHit = true                  // 鎚子打下去、抬起來效果                  pane1.setOnMouseReleased { e1 ->                      hammerView.rotateProperty().animate(endValue = 0.0, duration = 0.1.seconds)                  }                  //打中地鼠記錄次數 鼠標事件                  pane1.setOnMousePressed { e1 ->                      hammerView.rotateProperty().animate(endValue = -40.0, duration = 0.1.seconds)                        var i = 0                      lineList.forEach {                          if (e1.x < it.endX + 80 && e1.x > it.endX - 80 && ifHit                                  && e1.y < it.startY + 110 && e1.y > it.endY - 110) {                              count++                                //文本框輸出                              tfCount.value = count                              ifHit = false  //置為不能打                          }                          i++                      }                  }              }                //動畫              val animation = Timeline(KeyFrame(Duration.millis(1300.0), eventHandler)) //地鼠速度              animation.cycleCount = 30  //地鼠鑽出次數              animation.play()              //地洞圖像              mouseList.forEach {                  add(it)              }                imageview("whacAMole/mask.png")              //鎚子圖像              imageview("whacAMole/hammer.png") {                  hammerView = this                  fitWidth = 160.0                  fitHeight = 200.0              }              //事件源必須設在pane上,不能設在圖片上,否則鼠標要放在圖片上才能動              setOnMouseMoved { e ->                  hammerView.x = e.x - 60                  hammerView.y = e.y - 80              }              hbox(20.0) {                  addStylesheet(MyStyle::class)                  alignment = Pos.BOTTOM_CENTER                  //重新開始按鈕                  button("Quit") {                      background = null                      setOnMouseEntered {                          effect = DropShadow()                      }                      setOnMouseExited {                          effect = null                      }                      action {                          animation.stop()                          //animation1.stop();                          count = 0                          tfCount.value = 0                          msg.value = ""                          replaceWith(MyMole::class)                      }                  }                  //暫停按鈕                  button("Pause/Continue") {                      background = null                      setOnMouseEntered {                          effect = DropShadow()                      }                      setOnMouseExited {                          effect = null                      }                      action {                          if (!pause) {                              animation.pause()                              pause = true                          } else {                              animation.play()                              pause = false                          }                      }                  }                  textfield(tfCount) {                      setPrefSize(200.0, 40.0)                      style = "-fx-text-fill:rgb(195,46,5);"                      background = null                      font = Font.font("Bauhaus 93", FontWeight.EXTRA_BOLD, FontPosture.ITALIC, 80.0)                  }              }              text(msg) {                  fill = Color.rgb(222, 87, 61)                  font = Font.font("Kristen ITC", FontWeight.BOLD, FontPosture.ITALIC, 45.0)                  x = 280.0                  y = 700.0              }              }      }        private fun MouseAppear(): Line {          val ran = (Math.random() * 10.0 * 0.9).toInt()          var x0 = x1          var y0 = y1          val offset=150          when (ran) {              0 -> {                  x0 = x1                  y0 = y1+offset              }              1 -> {                  x0 = x1 + xx - 20                  y0 = y1+offset              }              2 -> {                  x0 = x1 + xx * 2 - 20                  y0 = y1+offset              }              3 -> {                  x0 = x1 - 50                  y0 = y1 + yy - 15+offset              }              4 -> {                  x0 = x1 + xx - 20                  y0 = y1 + yy+offset              }              5 -> {                  x0 = x1 + xx * 2 - 20                  y0 = y1 + yy+offset              }              6 -> {                  x0 = x1 - 60                  y0 = y1 + yy * 2 - 10+offset              }              7 -> {                  x0 = x1 + xx - 20                  y0 = y1 + yy * 2+offset              }              8 -> {                  x0 = x1 + xx * 2                  y0 = y1 + yy * 2+offset              }          }          val line = Line(x0, y0 + 30, x0, y0 - 50)          line.stroke = Color.TRANSPARENT          return line      }  }    class MyStyle1 : Stylesheet() {      init {          Companion.button {              textFill = Color.rgb(195, 46, 150)              prefWidth = 400.px              prefHeight = 80.px              font = Font.font("Showcard Gothic", FontWeight.EXTRA_BOLD, FontPosture.ITALIC, 30.0)          }      }  }