Rollers
This commit is contained in:
1 parent
3c5dd97641
commit
27fa1d31c2
3 files changed
+139
-4
No files matched your search
@@ -27,6 +27,9 @@ export const PLAYER_STARTING_WEAPONS = [
|
|||||||
{type: 'missile', ammo:5},
|
{type: 'missile', ammo:5},
|
||||||
{type: 'babyNuke', ammo:3},
|
{type: 'babyNuke', ammo:3},
|
||||||
{type: 'nuke', ammo:1},
|
{type: 'nuke', ammo:1},
|
||||||
|
{type: 'babyRoller', ammo:5},
|
||||||
|
{type: 'roller', ammo:3},
|
||||||
|
{type: 'superRoller', ammo:1},
|
||||||
{type: 'mirv', ammo:5},
|
{type: 'mirv', ammo:5},
|
||||||
{type: 'xmirv', ammo:3},
|
{type: 'xmirv', ammo:3},
|
||||||
{type: 'leapfrog', ammo:3},
|
{type: 'leapfrog', ammo:3},
|
||||||
@@ -45,6 +48,9 @@ export const WEAPON_TYPES = {
|
|||||||
missile: {id:'missile', name:'Missile', projectile:{type:'normal'}, explosion:{type:'blast', r:20}},
|
missile: {id:'missile', name:'Missile', projectile:{type:'normal'}, explosion:{type:'blast', r:20}},
|
||||||
babyNuke: {id:'babyNuke', name:'Baby Nuke', projectile:{type:'normal'}, explosion:{type:'blast', r:50}},
|
babyNuke: {id:'babyNuke', name:'Baby Nuke', projectile:{type:'normal'}, explosion:{type:'blast', r:50}},
|
||||||
nuke: {id:'nuke', name:'Nuke', projectile:{type:'normal'}, explosion:{type:'blast', r:100}},
|
nuke: {id:'nuke', name:'Nuke', projectile:{type:'normal'}, explosion:{type:'blast', r:100}},
|
||||||
|
babyRoller: {id:'babyRoller', name:'Baby Roller', projectile:{type:'roller'}, explosion:{type:'blast', r:15}},
|
||||||
|
roller: {id:'roller', name:'Roller', projectile:{type:'roller'}, explosion:{type:'blast', r:35}},
|
||||||
|
superRoller: {id:'superRoller', name:'Super Roller', projectile:{type:'roller'}, explosion:{type:'blast', r:60}},
|
||||||
leapfrog: {id:'leapfrog', name:'Leapfrog', projectile:{type:'leapfrog', n:3, s:10}, explosion:{type:'blast', r:35}},
|
leapfrog: {id:'leapfrog', name:'Leapfrog', projectile:{type:'leapfrog', n:3, s:10}, explosion:{type:'blast', r:35}},
|
||||||
mirv: {id:'mirv', name:'MIRV', projectile:{type:'mirv', n:3, s:8}, explosion:{type:'blast', r:35}},
|
mirv: {id:'mirv', name:'MIRV', projectile:{type:'mirv', n:3, s:8}, explosion:{type:'blast', r:35}},
|
||||||
xmirv: {id:'xmirv', name:'X-MIRV', projectile:{type:'mirv', n:5, s:8}, explosion:{type:'blast', r:45}},
|
xmirv: {id:'xmirv', name:'X-MIRV', projectile:{type:'mirv', n:5, s:8}, explosion:{type:'blast', r:45}},
|
||||||
|
|||||||
+11
-1
@@ -53,10 +53,20 @@ export function drawLine(ctx, x1, y1, x2, y2, color, plotFn=plot) {
|
|||||||
|
|
||||||
export function drawLineVirtual(x1, y1, x2, y2, color) {
|
export function drawLineVirtual(x1, y1, x2, y2, color) {
|
||||||
const points = [];
|
const points = [];
|
||||||
drawLine(null, x1, y1, x2, y2, color, (ctx, x, y, c) => points.push({x, y, c}));
|
drawLine(
|
||||||
|
null, x1, y1, x2, y2, color,
|
||||||
|
(ctx, x, y, c) => points.push({x, y, c})
|
||||||
|
);
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function checkLineWith(x1, y1, x2, y2, fn) {
|
||||||
|
drawLine(
|
||||||
|
null, x1, y1, x2, y2, null,
|
||||||
|
(ctx, x, y, c) => fn(x, y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function drawRect(ctx, x, y, w, h, color) {
|
export function drawRect(ctx, x, y, w, h, color) {
|
||||||
x = Math.round(x); y = Math.round(y);
|
x = Math.round(x); y = Math.round(y);
|
||||||
w = Math.round(w); h = Math.round(h);
|
w = Math.round(w); h = Math.round(h);
|
||||||
|
|||||||
+122
-3
@@ -1,9 +1,9 @@
|
|||||||
import {H, PROJECTILE_ITERATIONS_PER_FRAME, PROJECTILE_ITERATION_PROGRESS, PROJECTILE_MAX_SOUND_FREQUENCY, PROJECTILE_MIN_SOUND_FREQUENCY, PROJECTILE_POWER_REDUCTION_FACTOR, PROJECTILE_WIND_REDUCTION_FACTOR, WEAPON_TYPES} from './constants.js';
|
import {H, PROJECTILE_ITERATIONS_PER_FRAME, PROJECTILE_ITERATION_PROGRESS, PROJECTILE_MAX_SOUND_FREQUENCY, PROJECTILE_MIN_SOUND_FREQUENCY, PROJECTILE_POWER_REDUCTION_FACTOR, PROJECTILE_WIND_REDUCTION_FACTOR, WEAPON_TYPES} from './constants.js';
|
||||||
import {drawLineVirtual} from './gfx.js';
|
import {checkLineWith, drawLineVirtual} from './gfx.js';
|
||||||
import {isTank, createParticles} from './main.js';
|
import {createParticles, isTank} from './main.js';
|
||||||
import {deg2rad, parable} from './math.js';
|
import {deg2rad, parable} from './math.js';
|
||||||
import {audio, createOsc} from './sound.js';
|
import {audio, createOsc} from './sound.js';
|
||||||
import {isTerrain} from './terrain.js';
|
import {isTerrain, landHeight} from './terrain.js';
|
||||||
import {EXPLOSION_TYPES} from './weapons.js';
|
import {EXPLOSION_TYPES} from './weapons.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +77,125 @@ export const PROJECTILE_TYPES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
roller: {
|
||||||
|
create(spec, player, weapon, ox, oy, a, p, wind) {
|
||||||
|
const osc = createOsc('sine');
|
||||||
|
osc.start();
|
||||||
|
|
||||||
|
return [{
|
||||||
|
type: 'roller',
|
||||||
|
player, weapon,
|
||||||
|
x:ox, y:oy, ox, oy, a, p,
|
||||||
|
t: 0, osc, wind,
|
||||||
|
state: 'flying',
|
||||||
|
d: 0,
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
stop(projectile) {
|
||||||
|
projectile.osc.stop(0);
|
||||||
|
},
|
||||||
|
update(projectile, terrain, projectiles, trajectories, explosions) {
|
||||||
|
const prevProjectile = {...projectile};
|
||||||
|
const {state, weapon, player, wind} = projectile;
|
||||||
|
const weaponType = WEAPON_TYPES[weapon.type];
|
||||||
|
let finished = false;
|
||||||
|
|
||||||
|
if (state === 'flying') {
|
||||||
|
const {ox, oy, a, p, t} = projectile;
|
||||||
|
for (let i=0; i<PROJECTILE_ITERATIONS_PER_FRAME; i++) {
|
||||||
|
let [x, y] = parable(
|
||||||
|
t, ox, oy, deg2rad(180+a),
|
||||||
|
p / PROJECTILE_POWER_REDUCTION_FACTOR,
|
||||||
|
wind / PROJECTILE_WIND_REDUCTION_FACTOR,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isTerrain(terrain, x, y)) {
|
||||||
|
let prevPoint;
|
||||||
|
checkLineWith(
|
||||||
|
prevProjectile.x, prevProjectile.y, x, y,
|
||||||
|
(x, y) => {
|
||||||
|
if (prevPoint && isTerrain(terrain, prevPoint.x, prevPoint.y) && !isTerrain(terrain, x, y)) {
|
||||||
|
projectile.x = x;
|
||||||
|
projectile.y = y;
|
||||||
|
} else if (prevPoint && !isTerrain(terrain, prevPoint.x, prevPoint.y) && isTerrain(terrain, x, y)) {
|
||||||
|
projectile.x = prevPoint.x;
|
||||||
|
projectile.y = prevPoint.y;
|
||||||
|
}
|
||||||
|
prevPoint = {x, y};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
projectile.t += PROJECTILE_ITERATION_PROGRESS;
|
||||||
|
projectile.x = x;
|
||||||
|
projectile.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = projectile.x;
|
||||||
|
y = projectile.y;
|
||||||
|
|
||||||
|
if (y > H || isTank(x, y)) {
|
||||||
|
projectile.state = 'explode';
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
const hitLeft = isTerrain(terrain, x-1, y) || isTerrain(terrain, x-1, y+1);
|
||||||
|
const hitRight = isTerrain(terrain, x+1, y) || isTerrain(terrain, x+1, y+1);
|
||||||
|
const hitBottom = isTerrain(terrain, x, y+1);
|
||||||
|
if (hitLeft || hitRight || hitBottom) {
|
||||||
|
projectile.state = 'rolling';
|
||||||
|
projectile.d = (
|
||||||
|
hitLeft? 1 :
|
||||||
|
hitRight? -1 :
|
||||||
|
Math.sign(projectile.x - prevProjectile.x)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (state === 'rolling') {
|
||||||
|
const {x, y, d} = projectile;
|
||||||
|
const nextY = landHeight(terrain, x+d);
|
||||||
|
|
||||||
|
if (nextY < y || y > H || isTank(x, y)) {
|
||||||
|
projectile.state = 'explode';
|
||||||
|
} else {
|
||||||
|
projectile.x += d;
|
||||||
|
projectile.y = nextY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (state === 'explode') {
|
||||||
|
const {x, y, p} = projectile;
|
||||||
|
const explosionSpec = weaponType.explosion;
|
||||||
|
const explosionType = EXPLOSION_TYPES[explosionSpec.type];
|
||||||
|
explosions.push(explosionType.create(explosionSpec, x, y));
|
||||||
|
// @ts-ignore: canvas color hack
|
||||||
|
createParticles(x, y, p, terrain.color);
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const f = (
|
||||||
|
(1 - (1 / H * projectile.y)) *
|
||||||
|
(PROJECTILE_MAX_SOUND_FREQUENCY - PROJECTILE_MIN_SOUND_FREQUENCY) +
|
||||||
|
PROJECTILE_MIN_SOUND_FREQUENCY
|
||||||
|
);
|
||||||
|
projectile.osc.frequency.setValueAtTime(f, audio.currentTime);
|
||||||
|
|
||||||
|
let trajectory = drawLineVirtual(
|
||||||
|
prevProjectile.x, prevProjectile.y,
|
||||||
|
projectile.x, projectile.y, player.c,
|
||||||
|
);
|
||||||
|
|
||||||
|
trajectory
|
||||||
|
.slice(0, trajectory.length-1) // Cut last pixel to prevent overlap
|
||||||
|
.map(x => ({...x, a:255})) // Add alpha to all lines
|
||||||
|
.forEach(x => trajectories.push(x));
|
||||||
|
|
||||||
|
return !finished;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mirv: {
|
mirv: {
|
||||||
create(spec, player, weapon, ox, oy, a, p, wind) {
|
create(spec, player, weapon, ox, oy, a, p, wind) {
|
||||||
const {n, s} = spec;
|
const {n, s} = spec;
|
||||||
|
|||||||
Reference in new issue
Block a user