import { Juego } from './main' import { boxCollision, drawText } from './utils' const ENEMIES_NUM = 20 const SEED_COOLDOWN = 300 const MAP_MIN = 1000 const MAP_MAX = 5000 const MAP_SIZE = MAP_MAX - MAP_MIN const TREES_TO_WIN = 70 const TIME = 2 * 60 * 1000 export type State = { current: "jugando" pos: { x: number } view: { x: number } side: "left" | "right" enemies: { x: number }[] seeds: { x: number; velocity: { x: number } }[] trees: { x: number }[] time: number, seedCooldown: number, } export function createJugandoState(): State { return { current: "jugando", pos: { x: MAP_MIN + MAP_SIZE / 2 }, view: { x: 0 }, side: "right", enemies: [], seeds: [], trees: [], time: TIME, seedCooldown: 0, } } export function update(juego: Juego, dt: number) { juego.state.time -= dt if (juego.state.time < 0) { (juego as Juego).state = { current: "lose" } return } const playerSpeed = juego.canvas.width * 0.15 const enemySpeed = juego.canvas.width * 0.05 if (juego.keyboard.keys.d || juego.keyboard.keys.ArrowRight) { juego.state.side = "right" juego.state.pos.x += (dt / 1000) * playerSpeed } if (juego.keyboard.keys.a || juego.keyboard.keys.ArrowLeft) { juego.state.side = "left" juego.state.pos.x -= (dt / 1000) * playerSpeed } 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 juego.state.seedCooldown -= dt if (juego.keyboard.keys[' '] && juego.state.seedCooldown < 0) { const seedSpeed = juego.canvas.width * 0.7 juego.state.seeds.push({ x: juego.state.pos.x, velocity: { x: juego.state.side === "left" ? -seedSpeed : seedSpeed }, }) juego.state.seedCooldown = SEED_COOLDOWN } for (const seed of juego.state.seeds) { seed.x += (dt / 1000) * seed.velocity.x seed.velocity.x *= 0.97 for (const enemy of juego.state.enemies) { if (boxCollision({ x: seed.x, y: getFloorY(juego) - juego.sprites.semilla.getHeight(juego), width: juego.sprites.semilla.getWidth(juego), height: juego.sprites.semilla.getHeight(juego), }, { x: enemy.x, y: getFloorY(juego) - juego.sprites.larreta.getHeight(juego), width: juego.sprites.larreta.getWidth(juego), height: juego.sprites.larreta.getHeight(juego), })) { juego.state.seeds = juego.state.seeds.filter(s => s.x !== seed.x) juego.state.enemies = juego.state.enemies.filter(e => e.x !== enemy.x) juego.state.trees.push({ x: enemy.x }) } } if (Math.abs(seed.velocity.x) < 100) juego.state.seeds = juego.state.seeds.filter(s => s.velocity.x !== seed.velocity.x) } if (juego.state.trees.length >= TREES_TO_WIN) { (juego as Juego).state = { current: "win" } return } 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 }) } for (const enemy of juego.state.enemies) { const distance = enemy.x - juego.state.pos.x if (distance < 0) { enemy.x += (dt / 1000) * enemySpeed } else { enemy.x -= (dt / 1000) * enemySpeed } } juego.state.view.x = -juego.state.pos.x + juego.canvas.width / 2 - juego.sprites.jugadorx.getWidth(juego) / 2 } function drawBackground( juego: Juego, y: number, height: number, img: HTMLImageElement, ) { const aspect = img.width / img.height const width = height * aspect for (let i = 0; i < 10; i++) { juego.ctx.drawImage(img, i * (width - 1) + juego.state.view.x, y, width, height) } } function drawJugadorx(juego: Juego) { const floorY = getFloorY(juego) juego.sprites.jugadorx.draw( juego, juego.state.pos.x + juego.state.view.x, floorY - juego.sprites.jugadorx.getHeight(juego), 0, juego.state.side === "left", ) } function drawTrees(juego: Juego) { const height = juego.sprites.arbol.getHeight(juego) const floorY = getFloorY(juego) for (const tree of juego.state.trees) { juego.sprites.arbol.draw( juego, tree.x + juego.state.view.x, floorY - height, ) } } function drawEnemies(juego: Juego) { const height = juego.sprites.larreta.getHeight(juego) const floorY = getFloorY(juego) for (const enemy of juego.state.enemies) { juego.sprites.larreta.draw( juego, enemy.x + juego.state.view.x, floorY - height, ) } } function drawSeeds(juego: Juego) { const height = juego.sprites.semilla.getHeight(juego) const floorY = getFloorY(juego) for (const seed of juego.state.seeds) { juego.sprites.semilla.draw( juego, seed.x + juego.state.view.x, floorY - height, ) } } function getFloorY(juego: Juego): number { return (juego.canvas.height / 3) * 2 } export function draw(juego: Juego, timestamp: number) { const { height } = juego.canvas drawBackground(juego, 0, (height / 3) * 2, juego.assets.fondo) drawBackground(juego, getFloorY(juego), height / 3, juego.assets.vereda) drawTrees(juego) drawEnemies(juego) drawJugadorx(juego) drawSeeds(juego) 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'}) const tiempoBox = drawText( juego, `Tiempo restante`, { x: 10, y: 10 }, { bold: false, align: 'left'}) juego.ctx.fillRect( 10, tiempoBox.y + tiempoBox.height, (juego.canvas.width - arbolesBox.width - 20) * (juego.state.time / TIME), 30) }