import javafx.application.Application import javafx.stage.Stage import javafx.scene.paint.Color import javafx.scene.text.Font import javafx.scene.text.FontWeight import javafx.animation.AnimationTimer import javafx.beans.Observable import javafx.collections.ObservableList import javafx.geometry.Pos import javafx.scene.image.Image import javafx.scene.input.KeyEvent import javafx.scene.input.MouseEvent import javafx.util.Duration import tornadofx.* import kotlin.math.PI import kotlin.math.cos import kotlin.math.sin import kotlin.random.Random fun main(args: Array<String>) = Application.launch(eatFishApp::class.java, *args) class eatFishApp : App(eatFishView::class,Styles::class) { val v: eatFishView by inject() override fun start(stage: Stage) { super.start(stage) stage.scene.setOnKeyPressed(keyPressedHandler) stage.scene.setOnKeyReleased(keyReleasedHandler) } private val keyPressedHandler: (KeyEvent) -> Unit = { e -> val code = e.code.toString() if (!v.input.contains(code)) v.input.add(code) } private val keyReleasedHandler: (KeyEvent) -> Unit = { e -> v.input.remove(e.code.toString()) } } class eatFishView : View("我要吃了你!") { val lastNanoTime = longProperty(System.nanoTime()) val elapsedTime = doubleProperty() val canvasSize = 800.0 val score = intProperty(0) val input = mutableListOf<String>() val briefcase = Sprite("collectMoney/shayu.gif", 200.0, 0.0,80.0,80.0) var moneybagList = initFish() val canReset = booleanProperty(moneybagList.isEmpty()) val theFont = Font.font("Helvetica", FontWeight.BOLD, 24.0) var gc = canvas(canvasSize, canvasSize).graphicsContext2D override val root = borderpane { primaryStage.isResizable = false top = hbox(10) { alignment=Pos.CENTER paddingAll=10 imageview(Image("collectMoney/tiger.gif",50.0,50.0,false,true)) button("Reset") { prefHeight=50.0 prefWidth=200.0 enableWhen(canReset) action { moneybagList=initFish() run{ moneybagList.map { it.render(gc) } } score.value=0 } } label(score.stringBinding{"已經吃了: $it 條魚了"}) } val mouseMoveListener: (MouseEvent) -> Unit = { e -> briefcase.setPosition(e.x - 30, e.y - 60) } center = canvas(canvasSize+200, canvasSize) { gc = this.graphicsContext2D gc.font = theFont gc.fill = Color.GREEN gc.stroke = Color.BLACK gc.lineWidth = 1.0 setOnMouseMoved(mouseMoveListener) } } init { AnimT().start() } inner class AnimT : AnimationTimer() { override fun handle(currentNanoTime: Long) { // calculate time since last update. elapsedTime.value = (currentNanoTime - lastNanoTime.value) / 1000000000.0 lastNanoTime.value = currentNanoTime // game logic briefcase.setVelocity(0.0, 0.0) if (input.contains("LEFT")) briefcase.addVelocity(-100.0, 0.0) if (input.contains("RIGHT")) briefcase.addVelocity(100.0, 0.0) if (input.contains("UP")) briefcase.addVelocity(0.0, -100.0) if (input.contains("DOWN")) briefcase.addVelocity(0.0, 100.0) briefcase.update(elapsedTime.value) // collision detection val moneybagIter = moneybagList.iterator() while (moneybagIter.hasNext()) { val moneybag = moneybagIter.next() if (briefcase.intersects(moneybag)) { moneybagIter.remove() score.value++ } } canReset.value = moneybagList.isEmpty() // render gc.clearRect(0.0, 0.0, canvasSize+200, canvasSize) briefcase.render(gc) moneybagList.map { it.render(gc) } } } fun initFish():ObservableList<Sprite>{ return (0..14).map { Sprite("collectMoney/$it.gif", 700 * Math.random() + 40, 700 * Math.random() + 40,80.0,80.0) }.asObservable() } } class Styles : Stylesheet() { init { button { padding = box(10.px) alignment = Pos.CENTER backgroundColor += c("#DD7549") fontWeight = FontWeight.EXTRA_BOLD fontSize=28.px and (hover) { backgroundColor += c("#A05434") textFill = Color.WHITE } } label{ fontSize=28.px textFill = Color.RED } } }