Performant trajectories

This commit is contained in:
zenoamaro committed 2019-06-30 01:39:14 +02:00
1 parent d8dafbe9b4
commit ce575fd5d9
3 files changed
+57 -28

No files matched your search

+1 -1
View File
@@ -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;
+8 -2
View File
@@ -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);
+48 -25
View File
@@ -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<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
const {weaponTypeId, ox, oy, a, p, t} = projectile;
@@ -167,9 +163,29 @@ function update() {
explosion = explosionType.create(explosionSpec, projectile.x, projectile.y);
createParticles(projectile.x, projectile.y, projectile.p);
state = 'explosion';
return;
break;
}
}
if (++fadeCount % 3 === 0) {
fadeTrajectories(2);
fadeCount = 0;
}
let trajectory = drawLineVirtual(
prevProjectile.x, prevProjectile.y,
projectile.x, projectile.y,
projectile.c,
)
trajectory = trajectory
.slice(0, trajectory.length-1) // Cut last pixel to prevent overlap
.map(x => ({...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<data.data.length; i+=4) data.data[i+3] -= amount;
projectiles.clearRect(0, 0, W, H);
projectiles.putImageData(data, 0, 0);
function fadeTrajectories(amount) {
for (let trajectory of trajectories) {
trajectory.a -= amount;
}
trajectories = trajectories.filter(x => 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)`;
}
}