2021-06-28 18:01:45 +00:00
|
|
|
import { Juego } from './main'
|
2021-06-30 21:18:13 +00:00
|
|
|
import { boxCollision, drawText } from './utils'
|
2021-06-28 18:01:45 +00:00
|
|
|
|
2021-06-28 19:20:41 +00:00
|
|
|
const ENEMIES_NUM = 20
|
|
|
|
const SEED_COOLDOWN = 300
|
|
|
|
const MAP_MIN = 1000
|
|
|
|
const MAP_MAX = 5000
|
|
|
|
const MAP_SIZE = MAP_MAX - MAP_MIN
|
2021-06-30 16:26:31 +00:00
|
|
|
const TREES_TO_WIN = 70
|
2021-06-30 21:18:13 +00:00
|
|
|
const TIME = 2 * 60 * 1000
|
2021-06-28 19:20:41 +00:00
|
|
|
|
2021-06-28 18:01:45 +00:00
|
|
|
export type State = {
|
|
|
|
current: "jugando"
|
|
|
|
pos: { x: number }
|
|
|
|
view: { x: number }
|
2021-06-28 19:02:12 +00:00
|
|
|
side: "left" | "right"
|
2021-06-28 18:01:45 +00:00
|
|
|
enemies: { x: number }[]
|
2021-06-28 19:02:12 +00:00
|
|
|
seeds: { x: number; velocity: { x: number } }[]
|
2021-06-28 19:35:49 +00:00
|
|
|
trees: { x: number }[]
|
2021-06-30 21:18:13 +00:00
|
|
|
time: number,
|
2021-06-28 19:02:12 +00:00
|
|
|
seedCooldown: number,
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function createJugandoState(): State {
|
|
|
|
return {
|
|
|
|
current: "jugando",
|
2021-06-28 19:20:41 +00:00
|
|
|
pos: { x: MAP_MIN + MAP_SIZE / 2 },
|
2021-06-28 18:01:45 +00:00
|
|
|
view: { x: 0 },
|
2021-06-28 19:02:12 +00:00
|
|
|
side: "right",
|
2021-06-28 19:20:41 +00:00
|
|
|
enemies: [],
|
2021-06-28 19:02:12 +00:00
|
|
|
seeds: [],
|
2021-06-28 19:35:49 +00:00
|
|
|
trees: [],
|
2021-06-30 21:18:13 +00:00
|
|
|
time: TIME,
|
2021-06-28 19:02:12 +00:00
|
|
|
seedCooldown: 0,
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function update(juego: Juego<State>, dt: number) {
|
2021-06-30 21:18:13 +00:00
|
|
|
juego.state.time -= dt
|
|
|
|
if (juego.state.time < 0) {
|
2021-06-30 21:25:30 +00:00
|
|
|
(juego as Juego<any>).state = { current: "lose" }
|
2021-06-30 21:18:13 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-30 16:15:53 +00:00
|
|
|
const playerSpeed = juego.canvas.width * 0.15
|
|
|
|
const enemySpeed = juego.canvas.width * 0.05
|
2021-06-28 19:02:12 +00:00
|
|
|
if (juego.keyboard.keys.d || juego.keyboard.keys.ArrowRight) {
|
|
|
|
juego.state.side = "right"
|
2021-06-30 16:15:53 +00:00
|
|
|
juego.state.pos.x += (dt / 1000) * playerSpeed
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
2021-06-28 19:02:12 +00:00
|
|
|
if (juego.keyboard.keys.a || juego.keyboard.keys.ArrowLeft) {
|
|
|
|
juego.state.side = "left"
|
2021-06-30 16:15:53 +00:00
|
|
|
juego.state.pos.x -= (dt / 1000) * playerSpeed
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
|
|
|
|
2021-06-28 19:20:41 +00:00
|
|
|
if (juego.state.pos.x < MAP_MIN) juego.state.pos.x = MAP_MIN
|
|
|
|
if (juego.state.pos.x > MAP_MAX) juego.state.pos.x = MAP_MAX
|
2021-06-28 18:01:45 +00:00
|
|
|
|
2021-06-28 19:02:12 +00:00
|
|
|
juego.state.seedCooldown -= dt
|
|
|
|
if (juego.keyboard.keys[' '] && juego.state.seedCooldown < 0) {
|
2021-06-30 16:15:53 +00:00
|
|
|
const seedSpeed = juego.canvas.width * 0.7
|
2021-06-28 19:02:12 +00:00
|
|
|
juego.state.seeds.push({
|
|
|
|
x: juego.state.pos.x,
|
2021-06-30 16:15:53 +00:00
|
|
|
velocity: { x: juego.state.side === "left" ? -seedSpeed : seedSpeed },
|
2021-06-28 19:02:12 +00:00
|
|
|
})
|
2021-06-28 19:20:41 +00:00
|
|
|
juego.state.seedCooldown = SEED_COOLDOWN
|
2021-06-28 19:02:12 +00:00
|
|
|
}
|
|
|
|
for (const seed of juego.state.seeds) {
|
|
|
|
seed.x += (dt / 1000) * seed.velocity.x
|
2021-06-30 16:15:53 +00:00
|
|
|
seed.velocity.x *= 0.97
|
2021-06-28 19:02:12 +00:00
|
|
|
for (const enemy of juego.state.enemies) {
|
|
|
|
if (boxCollision({
|
|
|
|
x: seed.x,
|
2021-06-28 20:28:26 +00:00
|
|
|
y: getFloorY(juego) - juego.sprites.semilla.getHeight(juego),
|
|
|
|
width: juego.sprites.semilla.getWidth(juego),
|
|
|
|
height: juego.sprites.semilla.getHeight(juego),
|
2021-06-28 19:02:12 +00:00
|
|
|
}, {
|
|
|
|
x: enemy.x,
|
2021-06-28 20:28:26 +00:00
|
|
|
y: getFloorY(juego) - juego.sprites.larreta.getHeight(juego),
|
|
|
|
width: juego.sprites.larreta.getWidth(juego),
|
|
|
|
height: juego.sprites.larreta.getHeight(juego),
|
2021-06-28 19:02:12 +00:00
|
|
|
})) {
|
|
|
|
juego.state.seeds = juego.state.seeds.filter(s => s.x !== seed.x)
|
|
|
|
juego.state.enemies = juego.state.enemies.filter(e => e.x !== enemy.x)
|
2021-06-28 19:35:49 +00:00
|
|
|
juego.state.trees.push({ x: enemy.x })
|
2021-06-28 19:02:12 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-28 19:20:54 +00:00
|
|
|
if (Math.abs(seed.velocity.x) < 100)
|
|
|
|
juego.state.seeds = juego.state.seeds.filter(s => s.velocity.x !== seed.velocity.x)
|
2021-06-28 19:02:12 +00:00
|
|
|
}
|
|
|
|
|
2021-06-30 16:34:26 +00:00
|
|
|
if (juego.state.trees.length >= TREES_TO_WIN) {
|
|
|
|
(juego as Juego<any>).state = { current: "win" }
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-28 19:20:41 +00:00
|
|
|
while (juego.state.enemies.length < ENEMIES_NUM) {
|
|
|
|
const x = Math.random() * MAP_SIZE + MAP_MIN
|
|
|
|
// Don't spawn enemies too close
|
|
|
|
if (Math.abs(juego.state.pos.x - x) < 300) continue
|
|
|
|
juego.state.enemies.push({ x })
|
|
|
|
}
|
|
|
|
|
2021-06-28 19:26:27 +00:00
|
|
|
for (const enemy of juego.state.enemies) {
|
|
|
|
const distance = enemy.x - juego.state.pos.x
|
|
|
|
if (distance < 0) {
|
2021-06-30 16:15:53 +00:00
|
|
|
enemy.x += (dt / 1000) * enemySpeed
|
2021-06-28 19:26:27 +00:00
|
|
|
} else {
|
2021-06-30 16:15:53 +00:00
|
|
|
enemy.x -= (dt / 1000) * enemySpeed
|
2021-06-28 19:26:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 20:28:26 +00:00
|
|
|
juego.state.view.x = -juego.state.pos.x + juego.canvas.width / 2 - juego.sprites.jugadorx.getWidth(juego) / 2
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function drawBackground(
|
|
|
|
juego: Juego<State>,
|
2021-06-28 19:02:12 +00:00
|
|
|
y: number,
|
2021-06-28 18:01:45 +00:00
|
|
|
height: number,
|
|
|
|
img: HTMLImageElement,
|
|
|
|
) {
|
|
|
|
const aspect = img.width / img.height
|
|
|
|
const width = height * aspect
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2021-06-28 19:02:12 +00:00
|
|
|
juego.ctx.drawImage(img, i * (width - 1) + juego.state.view.x, y, width, height)
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 19:02:12 +00:00
|
|
|
function drawJugadorx(juego: Juego<State>) {
|
|
|
|
const floorY = getFloorY(juego)
|
2021-06-28 20:28:26 +00:00
|
|
|
juego.sprites.jugadorx.draw(
|
2021-06-28 18:01:45 +00:00
|
|
|
juego,
|
|
|
|
juego.state.pos.x + juego.state.view.x,
|
2021-06-28 20:28:26 +00:00
|
|
|
floorY - juego.sprites.jugadorx.getHeight(juego),
|
2021-06-28 19:02:12 +00:00
|
|
|
0,
|
|
|
|
juego.state.side === "left",
|
2021-06-28 18:01:45 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-06-28 19:35:49 +00:00
|
|
|
function drawTrees(juego: Juego<State>) {
|
2021-06-28 20:28:26 +00:00
|
|
|
const height = juego.sprites.arbol.getHeight(juego)
|
2021-06-28 19:35:49 +00:00
|
|
|
const floorY = getFloorY(juego)
|
|
|
|
for (const tree of juego.state.trees) {
|
2021-06-28 20:28:26 +00:00
|
|
|
juego.sprites.arbol.draw(
|
2021-06-28 19:35:49 +00:00
|
|
|
juego,
|
|
|
|
tree.x + juego.state.view.x,
|
|
|
|
floorY - height,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2021-06-28 19:02:12 +00:00
|
|
|
function drawEnemies(juego: Juego<State>) {
|
2021-06-28 20:28:26 +00:00
|
|
|
const height = juego.sprites.larreta.getHeight(juego)
|
2021-06-28 19:02:12 +00:00
|
|
|
const floorY = getFloorY(juego)
|
2021-06-28 18:01:45 +00:00
|
|
|
for (const enemy of juego.state.enemies) {
|
2021-06-28 20:28:26 +00:00
|
|
|
juego.sprites.larreta.draw(
|
2021-06-28 18:01:45 +00:00
|
|
|
juego,
|
|
|
|
enemy.x + juego.state.view.x,
|
|
|
|
floorY - height,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 19:02:12 +00:00
|
|
|
function drawSeeds(juego: Juego<State>) {
|
2021-06-28 20:28:26 +00:00
|
|
|
const height = juego.sprites.semilla.getHeight(juego)
|
2021-06-28 19:02:12 +00:00
|
|
|
const floorY = getFloorY(juego)
|
|
|
|
for (const seed of juego.state.seeds) {
|
2021-06-28 20:28:26 +00:00
|
|
|
juego.sprites.semilla.draw(
|
2021-06-28 19:02:12 +00:00
|
|
|
juego,
|
|
|
|
seed.x + juego.state.view.x,
|
|
|
|
floorY - height,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFloorY(juego: Juego<State>): number {
|
|
|
|
return (juego.canvas.height / 3) * 2
|
|
|
|
}
|
|
|
|
|
2021-06-28 18:01:45 +00:00
|
|
|
export function draw(juego: Juego<State>, timestamp: number) {
|
|
|
|
const { height } = juego.canvas
|
|
|
|
|
2021-06-28 20:28:26 +00:00
|
|
|
drawBackground(juego, 0, (height / 3) * 2, juego.assets.fondo)
|
|
|
|
drawBackground(juego, getFloorY(juego), height / 3, juego.assets.vereda)
|
2021-06-28 18:01:45 +00:00
|
|
|
|
2021-06-28 19:35:49 +00:00
|
|
|
drawTrees(juego)
|
2021-06-28 19:02:12 +00:00
|
|
|
drawEnemies(juego)
|
2021-06-28 18:01:45 +00:00
|
|
|
|
2021-06-28 19:02:12 +00:00
|
|
|
drawJugadorx(juego)
|
|
|
|
drawSeeds(juego)
|
2021-06-28 19:21:04 +00:00
|
|
|
|
2021-06-30 21:18:13 +00:00
|
|
|
drawText(juego, 'Usá las flechitas para moverte, y espacio para "disparar" semillas.', { x: 0, y: 100 }, {})
|
|
|
|
|
|
|
|
const arbolesBox = drawText(
|
|
|
|
juego, `Arboles: ${juego.state.trees.length}/${TREES_TO_WIN}`,
|
|
|
|
{ x: juego.canvas.width - 10, y: 10 },
|
|
|
|
{ bold: true, align: 'right'})
|
2021-06-30 16:26:31 +00:00
|
|
|
|
2021-06-30 21:18:13 +00:00
|
|
|
const tiempoBox = drawText(
|
|
|
|
juego, `Tiempo restante`,
|
|
|
|
{ x: 10, y: 10 },
|
|
|
|
{ bold: false, align: 'left'})
|
2021-06-30 16:26:31 +00:00
|
|
|
|
2021-06-30 21:18:13 +00:00
|
|
|
juego.ctx.fillRect(
|
|
|
|
10, tiempoBox.y + tiempoBox.height,
|
|
|
|
(juego.canvas.width - arbolesBox.width - 20) * (juego.state.time / TIME),
|
|
|
|
30)
|
2021-06-28 18:01:45 +00:00
|
|
|
}
|