Skip to content

Commit

Permalink
Merge branch 'litan:master' into turkish_keywords_2.13.x
Browse files Browse the repository at this point in the history
  • Loading branch information
bulent2k2 authored Dec 1, 2022
2 parents 949c987 + 8c44fd9 commit 690a40d
Show file tree
Hide file tree
Showing 11 changed files with 383 additions and 36 deletions.
120 changes: 120 additions & 0 deletions src/main/resources/samples/hunted-fp.kojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
cleari()
drawStage(cm.white)
val cb = canvasBounds

// game model/state

case class Player(x: Double, y: Double, w: Double, h: Double)
case class Hunter(x: Double, y: Double, w: Double, h: Double, vel: Vector2D)

case class Model(
player: Player,
hunters: Seq[Hunter],
gameOver: Boolean
)

// possible events/messages that can update the model
trait Msg
case object Tick extends Msg
case object MoveLeft extends Msg
case object MoveRight extends Msg
case object MoveUp extends Msg
case object MoveDown extends Msg
case object DontMove extends Msg

val nh = 20
def init: Model =
Model(
Player(cb.x + cb.width / 2, cb.y + 20, 40, 40),
(1 to nh).map { n =>
Hunter(
cb.x + cb.width / (nh + 2) * n,
cb.y + randomDouble(100, cb.height - 200),
40, 40,
Vector2D(random(1, 4), random(1, 4))
)
},
false
)

val speed = 5
val cd = new net.kogics.kojo.gaming.CollisionDetector()
def update(m: Model, msg: Msg): Model = msg match {
case MoveLeft =>
val player = m.player
m.copy(player = player.copy(x = player.x - speed))
case MoveRight =>
val player = m.player
m.copy(player = player.copy(x = player.x + speed))
case MoveUp =>
val player = m.player
m.copy(player = player.copy(y = player.y + speed))
case MoveDown =>
val player = m.player
m.copy(player = player.copy(y = player.y - speed))
case DontMove => m
case Tick =>
val newm = m.copy(hunters =
m.hunters.map { h =>
val newx = h.x + h.vel.x
val newy = h.y + h.vel.y
val vx = if (cd.collidesWithHorizontalEdge(newx, h.w))
h.vel.x * -1 else h.vel.x
val vy = if (cd.collidesWithVerticalEdge(newy, h.h))
h.vel.y * -1 else h.vel.y
h.copy(x = newx, y = newy, vel = Vector2D(vx, vy))
})

val p = m.player
val gameOver =
cd.collidesWithEdge(p.x, p.y, p.w, p.h) ||
m.hunters.exists { h =>
cd.collidesWith(p.x, p.y, p.w, p.h, h.x, h.y, h.w, h.h)
}
newm.copy(gameOver = gameOver)
}

def playerPic(p: Player): Picture = {
val base = Picture.rectangle(p.w, p.h)
return base.thatsFilledWith(cm.yellow).thatsStrokeColored(black).thatsTranslated(p.x, p.y)
}

def hunterPic(h: Hunter): Picture = {
val base = Picture.rectangle(h.w, h.h)
return base.thatsFilledWith(cm.lightBlue).thatsStrokeColored(black).thatsTranslated(h.x, h.y)
}

def view(m: Model): Picture = {
val viewPics =
m.hunters.map { h =>
hunterPic(h)
}.appended(playerPic(m.player))

if (m.gameOver) {
picStack(viewPics.appended(Picture.text("Game Over", 40)))
}
else
picStack(viewPics)
}

val tickSub: Sub[Msg] = Subscriptions.onAnimationFrame {
Tick
}

val keyDownSub: Sub[Msg] = Subscriptions.onKeyDown { keyCode =>
keyCode match {
case Kc.VK_LEFT => MoveLeft
case Kc.VK_RIGHT => MoveRight
case Kc.VK_UP => MoveUp
case Kc.VK_DOWN => MoveDown
case _ => DontMove
}
}

def subscriptions(m: Model) = {
if (m.gameOver) Seq()
else Seq(tickSub, keyDownSub)
}

runGame(init, update, view, subscriptions)
activateCanvas()
40 changes: 19 additions & 21 deletions src/main/scala/net/kogics/kojo/animation/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package net.kogics.kojo

import net.kogics.kojo.core.{Picture, SCanvas}
import net.kogics.kojo.kmath.KEasing
import net.kogics.kojo.util.Utils

package object animation {
val noOp = () => {}
Expand Down Expand Up @@ -120,7 +121,7 @@ package object animation {
var currPic: Picture = _

private def nextState(s: Seq[Double], elapsedTimeMillis: Double): Seq[Double] = {
if (elapsedTimeMillis > durationMillis) {
if (elapsedTimeMillis >= durationMillis) {
finalState
}
else {
Expand All @@ -132,36 +133,33 @@ package object animation {

def run(onDone: () => Unit)(onStart: () => Unit)(implicit canvas: SCanvas): Unit = {
import edu.umd.cs.piccolo.activities.PActivity

import java.util.concurrent.Future

val startMillis = System.currentTimeMillis
val initPic: Picture = picture.rect2(0, 0)
val initPic = picMaker(initState)

Utils.runInSwingThreadNonBatched {
initPic.draw()
currPic = initPic
onStart()
}

lazy val anim: Future[PActivity] =
canvas.animateWithState((initPic, initState, false)) { case (pic, s, stop) =>
if (s == initState) {
onStart()
}
canvas.animateWithState((initPic, initState)) { case (pic, s) =>
val elapsedTimeMillis =
(System.currentTimeMillis - startMillis).toDouble
val ns = nextState(s, elapsedTimeMillis)

pic.erase()
val pic2 = picMaker(s)
val pic2 = picMaker(ns)
pic2.draw()
currPic = pic2

if (stop) {
canvas.stopAnimationActivity(anim)
if (ns == finalState && elapsedTimeMillis >= durationMillis) {
onDone()
(pic, s, stop)
}
else {
val elapsedTimeMillis = (System.currentTimeMillis - startMillis).toDouble
val ns = nextState(s, elapsedTimeMillis)
if (ns == finalState && elapsedTimeMillis > durationMillis) {
(pic2, ns, true)
}
else {
(pic2, ns, false)
}
canvas.stopAnimationActivity(anim)
}
(pic2, ns)
}
anim
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/net/kogics/kojo/figure/Figure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class Figure private (canvas: SCanvas, initX: Double, initY: Double) {
@volatile var figAnimation: PActivity = null
val promise = new FutureResult[PActivity]

Utils.runLaterInSwingThread {
Utils.runInSwingThreadNonBatched {
val _ = figAnimation // force a volatile read to trigger a StoreLoad memory barrier
figAnimation = new PActivity(-1, rate, System.currentTimeMillis + delay) {
override def activityStep(elapsedTime: Long): Unit = {
Expand Down
Loading

0 comments on commit 690a40d

Please sign in to comment.