Performant trajectories
This commit is contained in:
1 parent
d8dafbe9b4
commit
ce575fd5d9
3 files changed
+57
-28
No files matched your search
+1
-1
@@ -39,4 +39,4 @@ export const PARTICLE_WIND_REDUCTION_FACTOR = 3;
|
|||||||
export const PLAYER_WEAPON_CHANGE_DELAY = 150;
|
export const PLAYER_WEAPON_CHANGE_DELAY = 150;
|
||||||
|
|
||||||
export const MAX_EXPLOSION_SHAKE_FACTOR = 60;
|
export const MAX_EXPLOSION_SHAKE_FACTOR = 60;
|
||||||
export const EXPLOSION_SHAKE_REDUCTION_FACTOR = 8;
|
export const EXPLOSION_SHAKE_REDUCTION_FACTOR = 7;
|
||||||
@@ -29,7 +29,7 @@ export function plot(ctx, x, y, color) {
|
|||||||
ctx.fillRect(x, y, 1, 1);
|
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);
|
const steep = Math.abs(y2 - y1) > Math.abs(x2 - x1);
|
||||||
if (steep) [x1, y1, x2, y2] = [y1, x1, y2, x2];
|
if (steep) [x1, y1, x2, y2] = [y1, x1, y2, x2];
|
||||||
if (x1 > x2) [x1, y1, x2, y2] = [x2, y2, x1, y1];
|
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 err = (dX / 2);
|
||||||
let y = y1;
|
let y = y1;
|
||||||
for (let x = x1; x <= x2; ++x) {
|
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 }
|
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) {
|
export function drawRect(ctx, x, y, w, h, color) {
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fillRect(x, y, w, h);
|
ctx.fillRect(x, y, w, h);
|
||||||
|
|||||||
@@ -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 {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 {key} from './input.js';
|
||||||
import {clamp, deg2rad, parable, randomInt, vec, wrap, random} from './math.js';
|
import {clamp, deg2rad, parable, randomInt, vec, wrap, random} from './math.js';
|
||||||
import {createSky} from './sky.js';
|
import {createSky} from './sky.js';
|
||||||
@@ -15,21 +15,21 @@ let state = 'start-game';
|
|||||||
const players = [];
|
const players = [];
|
||||||
let currentPlayer = 0;
|
let currentPlayer = 0;
|
||||||
let projectile = null;
|
let projectile = null;
|
||||||
let prevProjectile = null;
|
|
||||||
let explosion = null;
|
let explosion = null;
|
||||||
let wind = 0;
|
let wind = 0;
|
||||||
let fadeCount = 0;
|
let fadeCount = 0;
|
||||||
let lastWeaponChangeTime = 0;
|
let lastWeaponChangeTime = 0;
|
||||||
let particles = [];
|
let particles = [];
|
||||||
let screenShake = 0;
|
let screenShake = 0;
|
||||||
|
let trajectories = [];
|
||||||
|
|
||||||
// Init layers
|
// Init layers
|
||||||
const sky = createSky(W, H);
|
const sky = createSky(W, H);
|
||||||
const terrain = createTerrain(W, H);
|
const terrain = createTerrain(W, H);
|
||||||
const projectiles = createCanvas(W, H);
|
const traces = createCanvas(W, H);
|
||||||
const foreground = 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.width = `${W * Z}px`;
|
||||||
c.canvas.style.height = `${H * Z}px`;
|
c.canvas.style.height = `${H * Z}px`;
|
||||||
document.body.appendChild(c.canvas);
|
document.body.appendChild(c.canvas);
|
||||||
@@ -121,26 +121,22 @@ function update() {
|
|||||||
const weaponType = player.weapons[player.currentWeapon];
|
const weaponType = player.weapons[player.currentWeapon];
|
||||||
weaponType.ammo -= 1;
|
weaponType.ammo -= 1;
|
||||||
|
|
||||||
projectile = prevProjectile = {
|
projectile = {
|
||||||
osc: createOsc(),
|
osc: createOsc(),
|
||||||
player: player,
|
player: player,
|
||||||
weaponTypeId: weaponType.type,
|
weaponTypeId: weaponType.type,
|
||||||
ox:px, oy:py, a, p,
|
ox:px, oy:py, a, p,
|
||||||
x:px, y:py, t: 0,
|
x:px, y:py, t: 0,
|
||||||
|
c: player.c
|
||||||
};
|
};
|
||||||
|
|
||||||
projectile.osc.start();
|
projectile.osc.start();
|
||||||
state = 'fire';
|
state = 'shoot';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (state === 'fire') {
|
else if (state === 'shoot') {
|
||||||
prevProjectile = {...projectile};
|
const prevProjectile = {...projectile};
|
||||||
|
|
||||||
if (++fadeCount % 3 === 0) {
|
|
||||||
fadeProjectiles(2);
|
|
||||||
fadeCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i=0; i<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
|
for (let i=0; i<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
|
||||||
const {weaponTypeId, ox, oy, a, p, t} = projectile;
|
const {weaponTypeId, ox, oy, a, p, t} = projectile;
|
||||||
@@ -167,9 +163,29 @@ function update() {
|
|||||||
explosion = explosionType.create(explosionSpec, projectile.x, projectile.y);
|
explosion = explosionType.create(explosionSpec, projectile.x, projectile.y);
|
||||||
createParticles(projectile.x, projectile.y, projectile.p);
|
createParticles(projectile.x, projectile.y, projectile.p);
|
||||||
state = 'explosion';
|
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') {
|
else if (state === 'explosion') {
|
||||||
@@ -305,8 +321,9 @@ function updateParticles() {
|
|||||||
function draw() {
|
function draw() {
|
||||||
if (idle && particles.length===0) return;
|
if (idle && particles.length===0) return;
|
||||||
foreground.clearRect(0, 0, W, H);
|
foreground.clearRect(0, 0, W, H);
|
||||||
drawProjectiles();
|
drawTrajectories();
|
||||||
drawPlayers();
|
drawPlayers();
|
||||||
|
drawProjectile();
|
||||||
drawExplosions();
|
drawExplosions();
|
||||||
drawParticles();
|
drawParticles();
|
||||||
drawStatus();
|
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;
|
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');
|
plot(foreground, clamp(0, projectile.x, W), clamp(0, projectile.y, H), 'white');
|
||||||
}
|
}
|
||||||
|
|
||||||
function fadeProjectiles(amount) {
|
function fadeTrajectories(amount) {
|
||||||
// TODO: Very expensive, optimize
|
for (let trajectory of trajectories) {
|
||||||
const data = projectiles.getImageData(0, 0, W, H);
|
trajectory.a -= amount;
|
||||||
for (let i=0; i<data.data.length; i+=4) data.data[i+3] -= amount;
|
}
|
||||||
projectiles.clearRect(0, 0, W, H);
|
trajectories = trajectories.filter(x => x.a > 0);
|
||||||
projectiles.putImageData(data, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawExplosions() {
|
function drawExplosions() {
|
||||||
@@ -354,7 +377,7 @@ function drawParticles() {
|
|||||||
function drawScreenShake() {
|
function drawScreenShake() {
|
||||||
const x = randomInt(-screenShake, screenShake);
|
const x = randomInt(-screenShake, screenShake);
|
||||||
const y = 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)`;
|
c.canvas.style.transform = `translate(${x}px, ${y}px)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user