feat: add ants with stomp-crush and collision heart damage
This commit is contained in:
parent
5de53553ca
commit
85e6d8290f
63
js/game.js
63
js/game.js
@ -25,6 +25,13 @@ const state = {
|
||||
stepCarry: 0,
|
||||
cameraX: 0,
|
||||
hearts: 3,
|
||||
hitCooldown: 0,
|
||||
ants: [
|
||||
{ x: 1000, y: groundY - 20, width: 22, height: 20, vx: -65, alive: true },
|
||||
{ x: 1750, y: groundY - 20, width: 22, height: 20, vx: -70, alive: true },
|
||||
{ x: 2600, y: groundY - 20, width: 22, height: 20, vx: -80, alive: true },
|
||||
{ x: 3400, y: groundY - 20, width: 22, height: 20, vx: -75, alive: true }
|
||||
],
|
||||
player: {
|
||||
x: 160,
|
||||
y: 0,
|
||||
@ -79,6 +86,22 @@ function drawTRex(p) {
|
||||
ctx.fillRect(sx + p.width - 24, p.y + p.height - 8, 14, 8);
|
||||
}
|
||||
|
||||
function drawAnts() {
|
||||
ctx.fillStyle = '#5a1e0d';
|
||||
for (const ant of state.ants) {
|
||||
if (!ant.alive) continue;
|
||||
const sx = ant.x - state.cameraX;
|
||||
if (sx + ant.width < 0 || sx > canvas.width) continue;
|
||||
ctx.fillRect(sx, ant.y, ant.width, ant.height);
|
||||
ctx.fillRect(sx - 4, ant.y + 6, 4, 4);
|
||||
ctx.fillRect(sx + ant.width, ant.y + 6, 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
function intersects(a, b) {
|
||||
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
||||
}
|
||||
|
||||
function updateHeartsUI() {
|
||||
heartsEl.textContent = '❤'.repeat(state.hearts) + '🖤'.repeat(Math.max(0, 3 - state.hearts));
|
||||
}
|
||||
@ -89,11 +112,44 @@ function kill(reason) {
|
||||
state.deadReason = reason;
|
||||
}
|
||||
|
||||
function applyHit(reason) {
|
||||
if (state.hitCooldown > 0 || state.dead) return;
|
||||
state.hearts -= 1;
|
||||
state.hitCooldown = 1.0;
|
||||
if (state.hearts <= 0) {
|
||||
kill(reason);
|
||||
}
|
||||
}
|
||||
|
||||
function isOverWater(player) {
|
||||
const centerX = player.x + player.width / 2;
|
||||
return waterGaps.some((g) => centerX >= g.x && centerX <= g.x + g.width);
|
||||
}
|
||||
|
||||
function updateAnts(dt) {
|
||||
const p = state.player;
|
||||
const prevBottom = p.y + p.height - p.vy * dt;
|
||||
|
||||
for (const ant of state.ants) {
|
||||
if (!ant.alive) continue;
|
||||
|
||||
ant.x += ant.vx * dt;
|
||||
if (ant.x < 200) ant.vx = Math.abs(ant.vx);
|
||||
if (ant.x > worldWidth - 200) ant.vx = -Math.abs(ant.vx);
|
||||
|
||||
if (intersects(p, ant)) {
|
||||
const playerBottom = p.y + p.height;
|
||||
const stomped = p.vy > 0 && prevBottom <= ant.y + 4 && playerBottom >= ant.y;
|
||||
if (stomped) {
|
||||
ant.alive = false;
|
||||
p.vy = -380;
|
||||
} else {
|
||||
applyHit('A swarm of ants got you.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlayer(dt) {
|
||||
const p = state.player;
|
||||
let move = 0;
|
||||
@ -153,10 +209,15 @@ function tick(ts) {
|
||||
const dt = Math.min((ts - state.lastTs) / 1000, 0.05);
|
||||
state.lastTs = ts;
|
||||
|
||||
if (state.running) updatePlayer(dt);
|
||||
if (state.running) {
|
||||
state.hitCooldown = Math.max(0, state.hitCooldown - dt);
|
||||
updatePlayer(dt);
|
||||
updateAnts(dt);
|
||||
}
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
drawBackground();
|
||||
drawAnts();
|
||||
drawTRex(state.player);
|
||||
drawDeathText();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user