Last active
February 4, 2023 04:26
-
-
Save litan/0f81274f6cc96b07ec489854e9abc60b to your computer and use it in GitHub Desktop.
Hunted - various versions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cleari() | |
drawStage(cm.darkGreen) | |
val cb = canvasBounds | |
val player = Picture.rectangle(50, 50) | |
player.setFillColor(green) | |
player.setPenColor(green) | |
player.setPosition(cb.x + cb.width / 2, cb.y + 20) | |
draw(player) | |
val nh = 5 | |
val hunters = ArrayBuffer.empty[Picture] | |
val huntersVel = HashMap.empty[Picture, Vector2D] | |
repeatFor(1 to nh) { n => | |
val pic = Picture.rectangle(50, 50) | |
pic.setFillColor(red) | |
pic.setPenColor(red) | |
pic.setPosition(cb.x + cb.width / (nh + 2) * n, cb.y + randomDouble(100, cb.height - 200)) | |
hunters.append(pic) | |
val hv = Vector2D(random(1, 4), random(1, 4)) | |
huntersVel(pic) = hv | |
draw(pic) | |
} | |
def gameLost() { | |
stopAnimation() | |
drawCenteredMessage("You Lost", white, 30) | |
} | |
val speed = 5 | |
animate { | |
repeatFor(hunters) { h => | |
var hv = huntersVel(h) | |
h.translate(hv) | |
if (h.collidesWith(stageBorder)) { | |
hv = bouncePicOffStage(h, hv) | |
huntersVel(h) = hv | |
} | |
if (h.collidesWith(player)) { | |
gameLost() | |
} | |
} | |
if (isKeyPressed(Kc.VK_RIGHT)) { | |
player.translate(speed, 0) | |
} | |
if (isKeyPressed(Kc.VK_LEFT)) { | |
player.translate(-speed, 0) | |
} | |
if (isKeyPressed(Kc.VK_UP)) { | |
player.translate(0, speed) | |
} | |
if (isKeyPressed(Kc.VK_DOWN)) { | |
player.translate(0, -speed) | |
} | |
if (player.collidesWith(stageBorder)) { | |
gameLost() | |
} | |
} | |
showGameTime(10, "You Win", black, 25) | |
activateCanvas() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cleari() | |
drawStage(cm.darkGreen) | |
val cb = canvasBounds | |
case class Player(var x: Double, var y: Double) | |
case class Hunter(var x: Double, var y: Double, var vel: Vector2D) | |
val player = Player(cb.x + cb.width / 2, cb.y + 20) | |
val hunters = ArrayBuffer.empty[Hunter] | |
var playerPic: Picture = Picture.rectangle(0, 0) | |
val hunterPics = ArrayBuffer.empty[Picture] | |
var lost = false | |
val nh = 5 | |
repeatFor(1 to nh) { n => | |
val hv = Vector2D(random(1, 4), random(1, 4)) | |
val hunter = Hunter( | |
cb.x + cb.width / (nh + 2) * n, | |
cb.y + randomDouble(100, cb.height - 200), | |
hv | |
) | |
hunters.append(hunter) | |
} | |
def gameLost() { | |
stopAnimation() | |
drawCenteredMessage("You Lost", white, 30) | |
} | |
def updateState() { | |
var idx = 0 | |
repeatFor(hunters) { h => | |
val hv = h.vel | |
val hp = hunterPics(idx) | |
if (hp.collidesWith(stageBorder)) { | |
h.vel = bouncePicOffStage(hp, h.vel) | |
} | |
if (hp.collidesWith(playerPic)) { | |
lost = true | |
} | |
h.x += h.vel.x | |
h.y += h.vel.y | |
idx += 1 | |
} | |
if (isKeyPressed(Kc.VK_RIGHT)) { | |
player.x += speed | |
} | |
if (isKeyPressed(Kc.VK_LEFT)) { | |
player.x -= speed | |
} | |
if (isKeyPressed(Kc.VK_UP)) { | |
player.y += speed | |
} | |
if (isKeyPressed(Kc.VK_DOWN)) { | |
player.y -= speed | |
} | |
if (playerPic.collidesWith(stageBorder)) { | |
lost = true | |
} | |
} | |
def drawView() { | |
if (lost) { | |
gameLost() | |
return | |
} | |
playerPic.erase() | |
repeatFor(hunterPics) { pic => pic.erase() } | |
playerPic = Picture.rectangle(50, 50) | |
.withPosition(player.x, player.y) | |
.withPenColor(green) | |
.withFillColor(green) | |
hunterPics.clear() | |
repeatFor(hunters) { hunter => | |
val hunterPic = Picture.rectangle(50, 50) | |
.withPosition(hunter.x, hunter.y) | |
.withPenColor(red) | |
.withFillColor(red) | |
hunterPics.append(hunterPic) | |
} | |
playerPic.draw() | |
repeatFor(hunterPics) { pic => pic.draw() } | |
} | |
val speed = 5 | |
drawView() | |
animate { | |
updateState() | |
drawView() | |
} | |
showGameTime(10, "You Win", black, 25) | |
activateCanvas() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cleari() | |
drawStage(cm.darkGreen) | |
val cb = canvasBounds | |
case class Player(x: Double, y: Double) | |
case class Hunter(x: Double, y: Double, vel: Vector2D) | |
case class GameState( | |
player: Player, | |
hunters: Seq[Hunter], | |
lost: Boolean | |
) | |
case class GamePics( | |
playerPic: Picture, | |
hunterPics: Seq[Picture], | |
lostPic: Option[Picture] | |
) { | |
def draw() { | |
playerPic.draw() | |
repeatFor(hunterPics) { pic => pic.draw() } | |
lostPic.foreach { pic => pic.draw() } | |
} | |
def erase() { | |
playerPic.erase() | |
repeatFor(hunterPics) { pic => pic.erase() } | |
lostPic.foreach { pic => pic.erase() } | |
} | |
} | |
// this is available in Kojo 2.9.24 | |
def makeCenteredMessage(message: String, color: Color = black, fontSize: Int): Picture = { | |
val te = textExtent(message, fontSize) | |
PicShape.text(message, fontSize) | |
.withTranslation(cb.x + (cb.width - te.width) / 2, cb.y + (cb.height - te.height) / 2 + te.height) | |
.withPenColor(color) | |
} | |
def gameLostMsg: Picture = { | |
makeCenteredMessage("You Lost", white, 30) | |
} | |
def initState(nh: Int): GameState = { | |
val player = Player(cb.x + cb.width / 2, cb.y + 20) | |
val hunters = (1 to nh).map { n => | |
val hv = Vector2D(random(1, 4), random(1, 4)) | |
Hunter( | |
cb.x + cb.width / (nh + 2) * n, | |
cb.y + randomDouble(100, cb.height - 200), | |
hv | |
) | |
} | |
GameState(player, hunters, false) | |
} | |
def nextState(prevState: GameState, gpics: GamePics): GameState = { | |
val hunters = prevState.hunters | |
val playerPic = gpics.playerPic | |
val hunterPics = gpics.hunterPics | |
val gameLost = | |
hunters.zipWithIndex.find { case (h, idx) => | |
val hp = hunterPics(idx) | |
if (hp.collidesWith(playerPic)) true else false | |
}.isDefined || | |
playerPic.collidesWith(stageBorder) | |
if (gameLost) { | |
GameState(prevState.player, prevState.hunters, true) | |
} | |
else { | |
val newHunters = hunters.zipWithIndex.map { case (h, idx) => | |
val hv = h.vel | |
val hp = hunterPics(idx) | |
val hv2 = if (hp.collidesWith(stageBorder)) | |
bouncePicOffStage(hp, hv) | |
else | |
hv | |
val hx2 = h.x + hv2.x | |
val hy2 = h.y + hv2.y | |
Hunter(hx2, hy2, hv2) | |
} | |
var newPlayer = prevState.player | |
if (isKeyPressed(Kc.VK_RIGHT)) { | |
newPlayer = newPlayer.copy(x = newPlayer.x + speed) | |
} | |
if (isKeyPressed(Kc.VK_LEFT)) { | |
newPlayer = newPlayer.copy(x = newPlayer.x - speed) | |
} | |
if (isKeyPressed(Kc.VK_UP)) { | |
newPlayer = newPlayer.copy(y = newPlayer.y + speed) | |
} | |
if (isKeyPressed(Kc.VK_DOWN)) { | |
newPlayer = newPlayer.copy(y = newPlayer.y - speed) | |
} | |
GameState(newPlayer, newHunters, false) | |
} | |
} | |
def statePic(gstate: GameState): GamePics = { | |
val player = gstate.player | |
val hunters = gstate.hunters | |
val playerPic = Picture.rectangle(50, 50) | |
.withPosition(player.x, player.y) | |
.withPenColor(green) | |
.withFillColor(green) | |
val hunterPics = hunters.map { hunter => | |
Picture.rectangle(50, 50) | |
.withPosition(hunter.x, hunter.y) | |
.withPenColor(red) | |
.withFillColor(red) | |
} | |
var gpics = GamePics(playerPic, hunterPics, None) | |
if (gstate.lost) | |
gpics.copy(lostPic = Some(gameLostMsg)) | |
else | |
gpics | |
} | |
val speed = 5 | |
val iState = initState(5) | |
val iPics = statePic(iState) | |
iPics.draw() | |
animateWithState(iState, iPics) { case (gameState, gamePics) => | |
val gameState2 = nextState(gameState, gamePics) | |
val gamePics2 = statePic(gameState2) | |
gamePics.erase() | |
gamePics2.draw() | |
if (gameState2.lost) { | |
stopAnimation() | |
} | |
(gameState2, gamePics2) | |
} | |
showGameTime(10, "You Win", black, 25) | |
activateCanvas() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cleari() | |
drawStage(cm.darkGreen) | |
val cb = canvasBounds | |
class Player(x0: Double, y0: Double) { | |
val speed = 5 | |
private var x = x0 | |
private var y = y0 | |
private var pic = Picture.rectangle(50, 50) | |
.withPenColor(green) | |
.withFillColor(green) | |
pic.setPosition(x, y) | |
def viewPic = pic | |
def step() { | |
if (isKeyPressed(Kc.VK_RIGHT)) { | |
x += speed | |
} | |
if (isKeyPressed(Kc.VK_LEFT)) { | |
x -= speed | |
} | |
if (isKeyPressed(Kc.VK_UP)) { | |
y += speed | |
} | |
if (isKeyPressed(Kc.VK_DOWN)) { | |
y -= speed | |
} | |
if (pic.collidesWith(stageBorder)) { | |
gameLost = true | |
} | |
} | |
def view() { | |
if (pic.isDrawn) { | |
pic.setPosition(x, y) | |
} | |
else { | |
pic.draw() | |
} | |
} | |
} | |
class Hunter(x0: Double, y0: Double, vel0: Vector2D) { | |
private var x = x0 | |
private var y = y0 | |
private var vel = vel0 | |
private var pic = Picture.rectangle(50, 50) | |
.withPenColor(red) | |
.withFillColor(red) | |
pic.setPosition(x, y) | |
def step() { | |
if (pic.collidesWith(stageBorder)) { | |
vel = bouncePicOffStage(pic, vel) | |
} | |
if (pic.collidesWith(player.viewPic)) { | |
gameLost = true | |
} | |
x += vel.x | |
y += vel.y | |
} | |
def view() { | |
if (pic.isDrawn) { | |
pic.setPosition(x, y) | |
} | |
else { | |
pic.draw() | |
} | |
} | |
} | |
val player = new Player(cb.x + cb.width / 2, cb.y + 20) | |
val nh = 5 | |
val hunters = (1 to nh).map { n => | |
val hv = Vector2D(random(1, 4), random(1, 4)) | |
new Hunter( | |
cb.x + cb.width / (nh + 2) * n, | |
cb.y + randomDouble(100, cb.height - 200), | |
hv | |
) | |
} | |
var gameLost = false | |
def showGameLost() { | |
stopAnimation() | |
drawCenteredMessage("You Lost", white, 30) | |
} | |
def updateState() { | |
repeatFor(hunters) { h => h.step() } | |
player.step() | |
} | |
def viewState() { | |
if (gameLost) { | |
showGameLost() | |
} | |
else { | |
player.view() | |
repeatFor(hunters) { h => h.view() } | |
} | |
} | |
viewState() | |
animate { | |
updateState() | |
viewState() | |
} | |
showGameTime(10, "You Win", black, 25) | |
activateCanvas() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cleari() | |
drawStage(cm.darkGreen) | |
val cb = canvasBounds | |
case class PlayerState(x: Double, y: Double) { | |
def withUpdatedX(speed: Double): PlayerState = copy(x = x + speed) | |
def withUpdatedY(speed: Double): PlayerState = copy(y = y + speed) | |
} | |
case class HunterState(x: Double, y: Double, vel: Vector2D) { | |
def withVel(vel2: Vector2D): HunterState = copy(vel = vel2) | |
def withVelUpdatedXY: HunterState = copy(x = x + vel.x, y = y + vel.y) | |
} | |
class Player(x0: Double, y0: Double) { | |
val speed = 5 | |
private var state = PlayerState(x0, y0) | |
private var pic = Picture.rectangle(50, 50) | |
pic.setPenColor(green) | |
pic.setFillColor(green) | |
pic.setPosition(state.x, state.y) | |
def viewPic = pic | |
def step() { | |
var newState = state | |
if (isKeyPressed(Kc.VK_RIGHT)) { | |
newState = newState.withUpdatedX(speed) | |
} | |
if (isKeyPressed(Kc.VK_LEFT)) { | |
newState = newState.withUpdatedX(-speed) | |
} | |
if (isKeyPressed(Kc.VK_UP)) { | |
newState = newState.withUpdatedY(speed) | |
} | |
if (isKeyPressed(Kc.VK_DOWN)) { | |
newState = newState.withUpdatedY(-speed) | |
} | |
if (pic.collidesWith(stageBorder)) { | |
gameLost = true | |
} | |
state = newState | |
} | |
def view() { | |
if (pic.isDrawn) { | |
pic.setPosition(state.x, state.y) | |
} | |
else { | |
pic.draw() | |
} | |
} | |
} | |
class Hunter(x0: Double, y0: Double, vel0: Vector2D) { | |
private var state = HunterState(x0, y0, vel0) | |
private var pic = Picture.rectangle(50, 50) | |
pic.setPenColor(red) | |
pic.setFillColor(red) | |
pic.setPosition(state.x, state.y) | |
def step() { | |
var newState = state | |
if (pic.collidesWith(stageBorder)) { | |
val newVel = bouncePicOffStage(pic, newState.vel) | |
newState = newState.withVel(newVel) | |
} | |
if (pic.collidesWith(player.viewPic)) { | |
gameLost = true | |
} | |
newState = newState.withVelUpdatedXY | |
state = newState | |
} | |
def view() { | |
if (pic.isDrawn) { | |
pic.setPosition(state.x, state.y) | |
} | |
else { | |
pic.draw() | |
} | |
} | |
} | |
val player = new Player(cb.x + cb.width / 2, cb.y + 20) | |
val nh = 5 | |
val hunters = (1 to nh).map { n => | |
val hv = Vector2D(random(1, 4), random(1, 4)) | |
new Hunter( | |
cb.x + cb.width / (nh + 2) * n, | |
cb.y + randomDouble(100, cb.height - 200), | |
hv | |
) | |
} | |
var gameLost = false | |
def showGameLost() { | |
stopAnimation() | |
drawCenteredMessage("You Lost", white, 30) | |
} | |
def updateState() { | |
repeatFor(hunters) { h => h.step() } | |
player.step() | |
} | |
def viewState() { | |
if (gameLost) { | |
showGameLost() | |
} | |
else { | |
player.view() | |
repeatFor(hunters) { h => h.view() } | |
} | |
} | |
viewState() | |
animate { | |
updateState() | |
viewState() | |
} | |
showGameTime(10, "You Win", black, 25) | |
activateCanvas() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) || | |
newm.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 = Subscriptions.onAnimationFrame { | |
Tick | |
} | |
val keyDownSub = 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment