diff --git a/constants.js b/constants.js index 7f6b6aa..1f55521 100644 --- a/constants.js +++ b/constants.js @@ -39,4 +39,4 @@ export const PARTICLE_WIND_REDUCTION_FACTOR = 3; export const PLAYER_WEAPON_CHANGE_DELAY = 150; export const MAX_EXPLOSION_SHAKE_FACTOR = 60; -export const EXPLOSION_SHAKE_REDUCTION_FACTOR = 8; +export const EXPLOSION_SHAKE_REDUCTION_FACTOR = 7; diff --git a/gfx.js b/gfx.js index c3cb4eb..c4c15d0 100644 --- a/gfx.js +++ b/gfx.js @@ -29,7 +29,7 @@ export function plot(ctx, x, y, color) { ctx.fillRect(x, y, 1, 1); } -export function drawLine(ctx, x1, y1, x2, y2, color) { +export function drawLine(ctx, x1, y1, x2, y2, color, plotFn=plot) { const steep = Math.abs(y2 - y1) > Math.abs(x2 - x1); if (steep) [x1, y1, x2, y2] = [y1, x1, y2, x2]; if (x1 > x2) [x1, y1, x2, y2] = [x2, y2, x1, y1]; @@ -41,11 +41,17 @@ export function drawLine(ctx, x1, y1, x2, y2, color) { let err = (dX / 2); let y = y1; for (let x = x1; x <= x2; ++x) { - if (steep) plot(ctx, y, x, color); else plot(ctx, x, y, color); + if (steep) plotFn(ctx, y, x, color); else plotFn(ctx, x, y, color); err = err - dY; if (err < 0) { y += ystep; err += dX } } } +export function drawLineVirtual(x1, y1, x2, y2, color) { + const points = []; + drawLine(null, x1, y1, x2, y2, color, (ctx, x, y, c) => points.push({x, y, c})); + return points; +} + export function drawRect(ctx, x, y, w, h, color) { ctx.fillStyle = color; ctx.fillRect(x, y, w, h); diff --git a/main.js b/main.js index 4212265..e99b319 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,5 @@ import {H, PROJECTILE_MAX_SOUND_FREQUENCY, MAX_WIND, PROJECTILE_MIN_SOUND_FREQUENCY, PLAYER_COLORS, PLAYER_INITIAL_POWER, PROJECTILE_POWER_REDUCTION_FACTOR, W, Z, PROJECTILE_ITERATIONS_PER_FRAME, PROJECTILE_ITERATION_PROGRESS, PLAYER_MAX_ENERGY, PLAYER_ENERGY_POWER_MULTIPLIER, PLAYER_FALL_DAMAGE_FACTOR, PLAYER_FALL_DAMAGE_HEIGHT, PLAYER_WEAPON_CHANGE_DELAY, PARTICLE_AMOUNT, PROJECTILE_WIND_REDUCTION_FACTOR, PARTICLE_POWER_REDUCTION_FACTOR, PARTICLE_WIND_REDUCTION_FACTOR, PARTICLE_MIN_POWER_FACTOR, PARTICLE_MAX_POWER_FACTOR, PARTICLE_MIN_LIFETIME, PARTICLE_TIME_FACTOR, PLAYER_EXPLOSION_PARTICLE_POWER, EXPLOSION_SHAKE_REDUCTION_FACTOR, MAX_EXPLOSION_SHAKE_FACTOR} from './constants.js'; -import {createCanvas, drawLine, drawRect, drawText, loop, plot} from './gfx.js'; +import {createCanvas, drawLine, drawRect, drawText, loop, plot, drawLineVirtual} from './gfx.js'; import {key} from './input.js'; import {clamp, deg2rad, parable, randomInt, vec, wrap, random} from './math.js'; import {createSky} from './sky.js'; @@ -15,21 +15,21 @@ let state = 'start-game'; const players = []; let currentPlayer = 0; let projectile = null; -let prevProjectile = null; let explosion = null; let wind = 0; let fadeCount = 0; let lastWeaponChangeTime = 0; let particles = []; let screenShake = 0; +let trajectories = []; // Init layers const sky = createSky(W, H); const terrain = createTerrain(W, H); -const projectiles = createCanvas(W, H); +const traces = createCanvas(W, H); const foreground = createCanvas(W, H); -for (let c of [sky, terrain, projectiles, foreground]) { +for (let c of [sky, terrain, traces, foreground]) { c.canvas.style.width = `${W * Z}px`; c.canvas.style.height = `${H * Z}px`; document.body.appendChild(c.canvas); @@ -121,26 +121,22 @@ function update() { const weaponType = player.weapons[player.currentWeapon]; weaponType.ammo -= 1; - projectile = prevProjectile = { + projectile = { osc: createOsc(), player: player, weaponTypeId: weaponType.type, ox:px, oy:py, a, p, x:px, y:py, t: 0, + c: player.c }; projectile.osc.start(); - state = 'fire'; + state = 'shoot'; } } - else if (state === 'fire') { - prevProjectile = {...projectile}; - - if (++fadeCount % 3 === 0) { - fadeProjectiles(2); - fadeCount = 0; - } + else if (state === 'shoot') { + const prevProjectile = {...projectile}; for (let i=0; i ({...x, a:255})); // Add alpha to all lines + + trajectories = [ + ...trajectories, + ...trajectory, + ]; } else if (state === 'explosion') { @@ -305,8 +321,9 @@ function updateParticles() { function draw() { if (idle && particles.length===0) return; foreground.clearRect(0, 0, W, H); - drawProjectiles(); + drawTrajectories(); drawPlayers(); + drawProjectile(); drawExplosions(); drawParticles(); drawStatus(); @@ -324,19 +341,25 @@ function drawPlayers() { } } -function drawProjectiles() { +function drawTrajectories() { + traces.clearRect(0, 0, W, H); + for (let {x, y, c, a} of trajectories) { + traces.globalAlpha = a/255; + plot(traces, x, y, c); + } + traces.globalAlpha = 1; +} + +function drawProjectile() { if (!projectile) return; - const {x, y, player} = projectile; - drawLine(projectiles, prevProjectile.x, prevProjectile.y, x, y, player.c); plot(foreground, clamp(0, projectile.x, W), clamp(0, projectile.y, H), 'white'); } -function fadeProjectiles(amount) { - // TODO: Very expensive, optimize - const data = projectiles.getImageData(0, 0, W, H); - for (let i=0; i x.a > 0); } function drawExplosions() { @@ -354,7 +377,7 @@ function drawParticles() { function drawScreenShake() { const x = randomInt(-screenShake, screenShake); const y = randomInt(-screenShake, screenShake); - for (let c of [sky, terrain, projectiles, foreground]) { + for (let c of [sky, terrain, traces, foreground]) { c.canvas.style.transform = `translate(${x}px, ${y}px)`; } }