kill counter fixed. 8x8 anf 8x16 fonts added. terrain slides are aminated.
This commit is contained in:
1 parent
43ee0d9150
commit
e8a79c2a81
9 files changed
+80
-20
No files matched your search
+1
-1
@@ -121,7 +121,7 @@ export const PLAYER_STARTING_TOOLS = [
|
||||
|
||||
export const PANEL_WIDTH = 400;
|
||||
export const PANEL_HEIGHT = 300;
|
||||
export const PANEL_FONT_SIZE = 10;
|
||||
export const PANEL_FONT_SIZE = 8;
|
||||
export const PANEL_TITLE_FONT_SIZE = 16;
|
||||
export const PANEL_BG_COLOR = '#666';
|
||||
export const PANEL_BORDER_COLOR = '#333';
|
||||
|
||||
+5
-1
@@ -163,8 +163,12 @@ export function drawParagraph(ctx, text, x, y, w, h, color) {
|
||||
}
|
||||
|
||||
export function loop(fn) {
|
||||
let lastTime = performance.now();
|
||||
(function looped() {
|
||||
fn();
|
||||
const now = performance.now();
|
||||
const dt = Math.min((now - lastTime) / 1000, 0.1);
|
||||
lastTime = now;
|
||||
fn(dt);
|
||||
requestAnimationFrame(looped);
|
||||
})();
|
||||
}
|
||||
+20
-6
@@ -6,7 +6,7 @@ import {clamp, deg2rad, distance, parable, random, randomInt, vec, wrap} from '.
|
||||
import {PROJECTILE_TYPES} from './projectiles.js?v=5';
|
||||
import {generateSky} from './sky.js?v=5';
|
||||
import {playTickSound} from './sound.js?v=5';
|
||||
import {clipTerrain, closestLand, collapseTerrain, generateTerrain, isTerrain, landHeight} from './terrain.js?v=5';
|
||||
import {clipTerrain, closestLand, collapseTerrain, generateTerrain, isTerrain, landHeight, startCollapseTerrain, collapseTerrainStep} from './terrain.js?v=5';
|
||||
import {sample, shuffle} from './utils.js?v=5';
|
||||
import {EXPLOSION_TYPES} from './weapons.js?v=5';
|
||||
import {drawPanelBg, drawPanelTitle, drawPanelText, drawPanelDivider, drawPanelMenu, getPanelBounds} from './panel.js?v=5';
|
||||
@@ -22,6 +22,8 @@ let particles = [];
|
||||
let screenShake = 0;
|
||||
let trajectories = [];
|
||||
let idle = false;
|
||||
let dt = 0;
|
||||
let collapseState = null;
|
||||
let winner;
|
||||
|
||||
let score = 0;
|
||||
@@ -162,6 +164,7 @@ function initAllPlayerStats() {
|
||||
deaths: 0,
|
||||
shotsFired: 0,
|
||||
wins: 0,
|
||||
lastDamageSource: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -200,7 +203,7 @@ function updateMarket() {
|
||||
const item = marketItems[menuState.selected];
|
||||
const itemData = MARKET_ITEMS[item];
|
||||
const humanPlayer = players.find(p => !p.ai);
|
||||
if (humanPlayer && score >= itemData.price && item !== 'babyMissile') {
|
||||
if (humanPlayer && score >= itemData.price && item !== 'babyMissile' && WEAPON_TYPES[item]) {
|
||||
score -= itemData.price;
|
||||
let existingWeapon = humanPlayer.weapons.find(w => w.type === item);
|
||||
if (existingWeapon) {
|
||||
@@ -285,6 +288,7 @@ function initPlayers() {
|
||||
player.kills = 0;
|
||||
player.deaths = 0;
|
||||
player.shotsFired = 0;
|
||||
player.lastDamageSource = null;
|
||||
}
|
||||
players = existingPlayers;
|
||||
} else {
|
||||
@@ -310,6 +314,7 @@ function initPlayers() {
|
||||
deaths: 0,
|
||||
shotsFired: 0,
|
||||
wins: 0,
|
||||
lastDamageSource: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -435,7 +440,7 @@ function update() {
|
||||
for (let i=projectiles.length-1; i>=0; i--) {
|
||||
const projectile = projectiles[i];
|
||||
const projectileType = PROJECTILE_TYPES[projectile.type];
|
||||
if (projectileType.update(projectile, terrain, projectiles, trajectories, explosions)) continue;
|
||||
if (projectileType.update(projectile, terrain, projectiles, trajectories, explosions, dt)) continue;
|
||||
projectileType.stop(projectile);
|
||||
projectiles.splice(i, 1);
|
||||
}
|
||||
@@ -463,6 +468,8 @@ function update() {
|
||||
let remainingDamage = damage;
|
||||
if (!damage) continue;
|
||||
|
||||
if (explosion.source) player.lastDamageSource = explosion.source;
|
||||
|
||||
if (player.shield) {
|
||||
remainingDamage = clamp(0, damage-player.shield.energy, Infinity);
|
||||
player.shield.energy = clamp(0, player.shield.energy-damage, Infinity);
|
||||
@@ -478,8 +485,11 @@ function update() {
|
||||
}
|
||||
|
||||
else if (state === 'land-collapse') {
|
||||
collapseTerrain(terrain);
|
||||
state = 'land-players';
|
||||
if (!collapseState) collapseState = startCollapseTerrain(terrain);
|
||||
if (collapseTerrainStep(terrain, collapseState)) {
|
||||
collapseState = null;
|
||||
state = 'land-players';
|
||||
}
|
||||
}
|
||||
|
||||
else if (state === 'land-players') {
|
||||
@@ -518,6 +528,9 @@ function update() {
|
||||
createParticles(x, y, PLAYER_EXPLOSION_PARTICLE_POWER, c);
|
||||
dyingPlayer.dead = true;
|
||||
dyingPlayer.deaths++;
|
||||
if (dyingPlayer.lastDamageSource && dyingPlayer.lastDamageSource !== dyingPlayer) {
|
||||
dyingPlayer.lastDamageSource.kills++;
|
||||
}
|
||||
state = 'explosions';
|
||||
}
|
||||
|
||||
@@ -912,7 +925,8 @@ function drawStatus() {
|
||||
drawText(foreground, `Round: ${round}/${totalRounds} Score: ${score}`, W-8, 18, 'white', 'right');
|
||||
}
|
||||
|
||||
loop(() => {
|
||||
loop((deltaTime) => {
|
||||
dt = deltaTime;
|
||||
update();
|
||||
draw();
|
||||
});
|
||||
+2
-2
@@ -20,7 +20,7 @@ export function drawPanelBg(ctx) {
|
||||
export function drawPanelTitle(ctx, text) {
|
||||
const x = PANEL_X + PANEL_WIDTH / 2;
|
||||
const y = PANEL_Y + 20;
|
||||
ctx.font = `${PANEL_TITLE_FONT_SIZE}px text`;
|
||||
ctx.font = `${PANEL_TITLE_FONT_SIZE}px ibm-vga`;
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = 'black';
|
||||
@@ -30,7 +30,7 @@ export function drawPanelTitle(ctx, text) {
|
||||
}
|
||||
|
||||
export function drawPanelText(ctx, text, x, y, color = 'white', align = 'left') {
|
||||
ctx.font = `${PANEL_FONT_SIZE}px text`;
|
||||
ctx.font = `${PANEL_FONT_SIZE}px ibm-bios`;
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.textAlign = align;
|
||||
ctx.fillStyle = 'black';
|
||||
|
||||
+13
-10
@@ -23,13 +23,14 @@ export const PROJECTILE_TYPES = {
|
||||
stop(projectile) {
|
||||
projectile.osc.stop(0);
|
||||
},
|
||||
update(projectile, terrain, projectiles, trajectories, explosions) {
|
||||
update(projectile, terrain, projectiles, trajectories, explosions, dt) {
|
||||
const prevProjectile = {...projectile};
|
||||
const {weapon, player, wind} = projectile;
|
||||
const weaponType = WEAPON_TYPES[weapon.type];
|
||||
let exploded = false;
|
||||
const iterations = Math.max(1, Math.round(PROJECTILE_ITERATIONS_PER_FRAME * dt * 60));
|
||||
|
||||
for (let i=0; i<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
|
||||
for (let i=0; i<iterations; i++) {
|
||||
const {ox, oy, a, p, t} = projectile;
|
||||
|
||||
const [x, y] = parable(
|
||||
@@ -69,7 +70,7 @@ export const PROJECTILE_TYPES = {
|
||||
) {
|
||||
const explosionSpec = weaponType.explosion;
|
||||
const explosionType = EXPLOSION_TYPES[explosionSpec.type];
|
||||
explosions.push(explosionType.create(explosionSpec, x, y));
|
||||
explosions.push({...explosionType.create(explosionSpec, x, y), source: player});
|
||||
// @ts-ignore: canvas color hack
|
||||
createParticles(x, y, p, terrain.color);
|
||||
exploded = true;
|
||||
@@ -108,7 +109,7 @@ export const PROJECTILE_TYPES = {
|
||||
stop(projectile) {
|
||||
projectile.osc.stop(0);
|
||||
},
|
||||
update(projectile, terrain, projectiles, trajectories, explosions) {
|
||||
update(projectile, terrain, projectiles, trajectories, explosions, dt) {
|
||||
const prevProjectile = {...projectile};
|
||||
const {state, weapon, player, wind} = projectile;
|
||||
const weaponType = WEAPON_TYPES[weapon.type];
|
||||
@@ -116,7 +117,8 @@ export const PROJECTILE_TYPES = {
|
||||
|
||||
if (state === 'flying') {
|
||||
const {ox, oy, a, p, t} = projectile;
|
||||
for (let i=0; i<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
|
||||
const iterations = Math.max(1, Math.round(PROJECTILE_ITERATIONS_PER_FRAME * dt * 60));
|
||||
for (let i=0; i<iterations; i++) {
|
||||
let [x, y] = parable(
|
||||
t, ox, oy, deg2rad(180+a),
|
||||
p / PROJECTILE_POWER_REDUCTION_FACTOR,
|
||||
@@ -183,12 +185,13 @@ export const PROJECTILE_TYPES = {
|
||||
|
||||
else if (state === 'rolling') {
|
||||
const {x, y, d} = projectile;
|
||||
const nextY = landHeight(terrain, x+d);
|
||||
const rollSpeed = Math.max(1, Math.round(dt * 60));
|
||||
const nextY = landHeight(terrain, x + d * rollSpeed);
|
||||
|
||||
if (nextY < y || y > H || isTank(x, y)) {
|
||||
projectile.state = 'explode';
|
||||
} else {
|
||||
projectile.x += d;
|
||||
projectile.x += d * rollSpeed;
|
||||
projectile.y = nextY;
|
||||
}
|
||||
}
|
||||
@@ -197,7 +200,7 @@ export const PROJECTILE_TYPES = {
|
||||
const {x, y, p} = projectile;
|
||||
const explosionSpec = weaponType.explosion;
|
||||
const explosionType = EXPLOSION_TYPES[explosionSpec.type];
|
||||
explosions.push(explosionType.create(explosionSpec, x, y));
|
||||
explosions.push({...explosionType.create(explosionSpec, x, y), source: player});
|
||||
// @ts-ignore: canvas color hack
|
||||
createParticles(x, y, p, terrain.color);
|
||||
finished = true;
|
||||
@@ -255,7 +258,7 @@ export const PROJECTILE_TYPES = {
|
||||
}];
|
||||
},
|
||||
stop() {},
|
||||
update(projectile, terrain, projectiles, trajectories, explosions) {
|
||||
update(projectile, terrain, projectiles, trajectories, explosions, dt) {
|
||||
const {player, weapon, ox, oy, a, p, wind, n, s} = projectile;
|
||||
const projectileType = PROJECTILE_TYPES.normal;
|
||||
|
||||
@@ -268,7 +271,7 @@ export const PROJECTILE_TYPES = {
|
||||
}
|
||||
|
||||
const alive = projectileType.update(
|
||||
projectile.payload, terrain, projectiles, trajectories, explosions
|
||||
projectile.payload, terrain, projectiles, trajectories, explosions, dt
|
||||
);
|
||||
|
||||
if (!alive) {
|
||||
|
||||
@@ -72,6 +72,43 @@ export function collapseTerrain(ctx, ) {
|
||||
cacheImageData(ctx);
|
||||
}
|
||||
|
||||
export function startCollapseTerrain(terrain) {
|
||||
return {};
|
||||
}
|
||||
|
||||
export function collapseTerrainStep(terrain, state) {
|
||||
const {width, height} = terrain.canvas;
|
||||
const imageData = terrain.getImageData(0, 0, width, height);
|
||||
const data = imageData.data;
|
||||
let anyMoved = false;
|
||||
|
||||
for (let y = height - 2; y >= 0; y--) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
const idx = (y * width + x) * 4;
|
||||
const belowIdx = ((y + 1) * width + x) * 4;
|
||||
if (data[idx + 3] > 0 && data[belowIdx + 3] === 0) {
|
||||
data[belowIdx] = data[idx];
|
||||
data[belowIdx + 1] = data[idx + 1];
|
||||
data[belowIdx + 2] = data[idx + 2];
|
||||
data[belowIdx + 3] = data[idx + 3];
|
||||
data[idx] = 0;
|
||||
data[idx + 1] = 0;
|
||||
data[idx + 2] = 0;
|
||||
data[idx + 3] = 0;
|
||||
anyMoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyMoved) {
|
||||
cacheImageData(terrain);
|
||||
return true;
|
||||
}
|
||||
|
||||
terrain.putImageData(imageData, 0, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTerrain(ctx, x, y) {
|
||||
const index = coords2index(ctx.canvas.width, x, y) * 4;
|
||||
return cachedImageData.data[index+3] > 0;
|
||||
|
||||
Reference in new issue
Block a user