Add rotation view and path prediction toggles
This commit is contained in:
parent
ce6a707526
commit
5b861cc341
12 changed files with 195 additions and 19 deletions
|
@ -11,6 +11,8 @@ export const mapping = {
|
||||||
right: 'KeyD',
|
right: 'KeyD',
|
||||||
exitEdit: 'Escape',
|
exitEdit: 'Escape',
|
||||||
inventory: 'KeyE',
|
inventory: 'KeyE',
|
||||||
|
cycleRotation: 'KeyC',
|
||||||
|
toggleTrace: 'KeyT'
|
||||||
};
|
};
|
||||||
|
|
||||||
let held, pressed;
|
let held, pressed;
|
||||||
|
@ -49,6 +51,15 @@ function tickPlaying() {
|
||||||
state.inventory = !state.inventory;
|
state.inventory = !state.inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pressed[mapping.cycleRotation]) {
|
||||||
|
events.cycleRotationMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressed[mapping.toggleTrace]) {
|
||||||
|
events.toggleTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For debugging.
|
||||||
if (pressed['KeyR']) events.startGame();
|
if (pressed['KeyR']) events.startGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,23 @@ import * as edit from './edit.mjs';
|
||||||
|
|
||||||
export let shipLanded = false;
|
export let shipLanded = false;
|
||||||
|
|
||||||
|
let notification;
|
||||||
|
let notLife = 0;
|
||||||
|
|
||||||
|
function notify(message) {
|
||||||
|
notification.text = message;
|
||||||
|
notLife = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tick() {
|
||||||
|
if (notLife-- <= 0)
|
||||||
|
notification.text = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setNotificationElement(el) {
|
||||||
|
notification = el;
|
||||||
|
}
|
||||||
|
|
||||||
export function startGame() {
|
export function startGame() {
|
||||||
game.changeView('game');
|
game.changeView('game');
|
||||||
graphics.perspective.focusPlayer();
|
graphics.perspective.focusPlayer();
|
||||||
|
@ -33,6 +50,21 @@ export function toggleEdit() {
|
||||||
edit.init();
|
edit.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleTrace() {
|
||||||
|
let trace = graphics.toggleTrace();
|
||||||
|
notify('Path prediction: ' + (trace ? 'on' : 'off'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cycleRotationMode() {
|
||||||
|
let message = {
|
||||||
|
parent: 'planet',
|
||||||
|
local: 'ship',
|
||||||
|
universe: 'universe'
|
||||||
|
}[graphics.cycleRotationMode()];
|
||||||
|
|
||||||
|
notify('Rotation view: ' + message);
|
||||||
|
}
|
||||||
|
|
||||||
export function endEditing() {
|
export function endEditing() {
|
||||||
let {valid, reason} = edit.end();
|
let {valid, reason} = edit.end();
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@ export function changeView(view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function tick() {
|
function tick() {
|
||||||
|
events.tick();
|
||||||
|
|
||||||
if (state.view == 'game') {
|
if (state.view == 'game') {
|
||||||
world.tick();
|
world.tick();
|
||||||
control.tick();
|
control.tick();
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as consts from '../consts.mjs';
|
||||||
|
|
||||||
export let canvas, context, tempCanvas, tempContext;
|
export let canvas, context, tempCanvas, tempContext;
|
||||||
export let perspective;
|
export let perspective;
|
||||||
|
export let trace = false;
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
canvas = document.querySelector('#main');
|
canvas = document.querySelector('#main');
|
||||||
|
@ -50,6 +51,23 @@ export function changePerspective(rotationMode, shiftX = 0, shiftY = 0) {
|
||||||
perspective.transition = 1;
|
perspective.transition = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cycleRotationMode() {
|
||||||
|
if (perspective.rotationMode === 'parent') {
|
||||||
|
perspective.changeRotationMode('local');
|
||||||
|
} else if (perspective.rotationMode === 'local') {
|
||||||
|
perspective.changeRotationMode('universe');
|
||||||
|
} else {
|
||||||
|
perspective.changeRotationMode('parent');
|
||||||
|
}
|
||||||
|
perspective.transition = 1;
|
||||||
|
return perspective.rotationMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleTrace() {
|
||||||
|
trace = !trace;
|
||||||
|
return trace;
|
||||||
|
}
|
||||||
|
|
||||||
export function changeZoom(delta) {
|
export function changeZoom(delta) {
|
||||||
perspective.zoomDelta(delta);
|
perspective.zoomDelta(delta);
|
||||||
}
|
}
|
||||||
|
@ -77,6 +95,7 @@ class Perspective {
|
||||||
}
|
}
|
||||||
|
|
||||||
changeRotationMode(mode) {
|
changeRotationMode(mode) {
|
||||||
|
this.oldShift = this.currentShift;
|
||||||
this.oldTarget = this.currentRotation;
|
this.oldTarget = this.currentRotation;
|
||||||
this.rotationMode = mode;
|
this.rotationMode = mode;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +130,18 @@ class Perspective {
|
||||||
return (old * x + cur * (1 - x));
|
return (old * x + cur * (1 - x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interpolateAngles(cur, old, x = this.transition) {
|
||||||
|
let a = cur % (Math.PI * 2);
|
||||||
|
let b = old % (Math.PI * 2);
|
||||||
|
|
||||||
|
let sum = a + b;
|
||||||
|
|
||||||
|
if (sum > (Math.PI * 2) && sum < (Math.PI * 3))
|
||||||
|
sum %= Math.PI;
|
||||||
|
|
||||||
|
return sum / 2;
|
||||||
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
if (this.focus !== null)
|
if (this.focus !== null)
|
||||||
[this.x, this.y] = this.focus.com;
|
[this.x, this.y] = this.focus.com;
|
||||||
|
@ -129,6 +160,8 @@ class Perspective {
|
||||||
this.targetRotation = this.focus.r;
|
this.targetRotation = this.focus.r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.normalize();
|
||||||
|
|
||||||
let dif = Math.abs(this.targetRotation - this.rotation);
|
let dif = Math.abs(this.targetRotation - this.rotation);
|
||||||
this.rotationMet = dif < (this.rotationMet ? 0.3 : 0.05);
|
this.rotationMet = dif < (this.rotationMet ? 0.3 : 0.05);
|
||||||
|
|
||||||
|
@ -137,8 +170,6 @@ class Perspective {
|
||||||
|
|
||||||
this.transition *= 0.9;
|
this.transition *= 0.9;
|
||||||
this.zoomTransition *= 0.9;
|
this.zoomTransition *= 0.9;
|
||||||
|
|
||||||
this.normalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {canvas, context} from './index.mjs';
|
import {canvas, context} from './index.mjs';
|
||||||
|
import * as graphics from './index.mjs';
|
||||||
import {images as assets} from '../assets.mjs';
|
import {images as assets} from '../assets.mjs';
|
||||||
import * as world from '../world/index.mjs';
|
import * as world from '../world/index.mjs';
|
||||||
import {state} from '../game/index.mjs';
|
import {state} from '../game/index.mjs';
|
||||||
|
@ -6,6 +7,7 @@ import {state} from '../game/index.mjs';
|
||||||
export function render() {
|
export function render() {
|
||||||
world.particles.forEach(renderParticle);
|
world.particles.forEach(renderParticle);
|
||||||
world.celestials.forEach(renderCelestial);
|
world.celestials.forEach(renderCelestial);
|
||||||
|
if (graphics.trace) world.tracers.forEach(renderTracer);
|
||||||
world.ships.forEach(renderShip);
|
world.ships.forEach(renderShip);
|
||||||
world.entities.forEach(renderEntity);
|
world.entities.forEach(renderEntity);
|
||||||
}
|
}
|
||||||
|
@ -47,3 +49,21 @@ function renderCelestial(cel) {
|
||||||
context.drawImage(cel.image, cel.x, cel.y,
|
context.drawImage(cel.image, cel.x, cel.y,
|
||||||
cel.diameter, cel.diameter);
|
cel.diameter, cel.diameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderTracer(tracer) {
|
||||||
|
context.lineWidth = 0.1;
|
||||||
|
context.strokeStyle = '#fff';
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(...tracer.pos);
|
||||||
|
let path = tracer.path;
|
||||||
|
|
||||||
|
for (let i = 0; i < path.length; i++) {
|
||||||
|
context.lineTo(...path[i]);
|
||||||
|
if (i % 5 === 0 || i == path.length - 1) {
|
||||||
|
context.stroke();
|
||||||
|
context.globalAlpha = (1 - (i / path.length)) * 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.globalAlpha = 1;
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ export function game() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let editShadow = root();
|
let editShadow = root();
|
||||||
shadow.append(editShadow);
|
shadow.append(editShadow);
|
||||||
editShadow.posRelative({x: 0.45, y: 0, w: 0.55, h: 0.6});
|
editShadow.posRelative({x: 0.45, y: 0, w: 0.55, h: 0.6});
|
||||||
|
@ -97,5 +96,16 @@ export function game() {
|
||||||
|
|
||||||
edit.guiInventory = inventory;
|
edit.guiInventory = inventory;
|
||||||
|
|
||||||
|
|
||||||
|
let notification = new GuiText('', 0, 0, 0, 0, {
|
||||||
|
size: 12,
|
||||||
|
align: 'center',
|
||||||
|
valign: 'top'
|
||||||
|
});
|
||||||
|
shadow.append(notification);
|
||||||
|
notification.posRelative({x: 0.5});
|
||||||
|
notification.y += 10;
|
||||||
|
events.setNotificationElement(notification);
|
||||||
|
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,20 +55,20 @@ export default class Body {
|
||||||
return this.rotateVector(x, y, this.r);
|
return this.rotateVector(x, y, this.r);
|
||||||
}
|
}
|
||||||
|
|
||||||
tickMotion() {
|
tickMotion(speed = 1) {
|
||||||
this.x += this.xvel;
|
this.x += this.xvel * speed;
|
||||||
this.y += this.yvel;
|
this.y += this.yvel * speed;
|
||||||
this.r += this.rvel;
|
this.r += this.rvel * speed;
|
||||||
this.rvel *= this.rfriction;
|
this.rvel *= this.rfriction * speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
tickGravity(bodies) {
|
tickGravity(bodies, speed = 1) {
|
||||||
bodies.forEach(b => {
|
bodies.forEach(b => {
|
||||||
let force = b.mass / (this.distanceTo(b) ** 2) * G;
|
let force = b.mass / (this.distanceTo(b) ** 2) * G;
|
||||||
let [[ax, ay], [bx, by]] = [this.com, b.com];
|
let [[ax, ay], [bx, by]] = [this.com, b.com];
|
||||||
let angle = Math.atan2(by - ay, bx - ax);
|
let angle = Math.atan2(by - ay, bx - ax);
|
||||||
this.xvel += Math.cos(angle) * force;
|
this.xvel += Math.cos(angle) * force * speed;
|
||||||
this.yvel += Math.sin(angle) * force;
|
this.yvel += Math.sin(angle) * force * speed;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,4 +100,14 @@ export default class Body {
|
||||||
this.yvel += vy;
|
this.yvel += vy;
|
||||||
this.rvel += r / this.mass;
|
this.rvel += r / this.mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orbit(cel, altitude) {
|
||||||
|
this.gravity = true;
|
||||||
|
let speed = Math.sqrt(G * cel.mass / (altitude + cel.radius));
|
||||||
|
let [cx, cy] = cel.com;
|
||||||
|
this.x = cx;
|
||||||
|
this.y = cy - (altitude + cel.radius);
|
||||||
|
this.yvel = 0;
|
||||||
|
this.xvel = speed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class Entity extends Body {
|
||||||
yvel = 0,
|
yvel = 0,
|
||||||
gravity = false
|
gravity = false
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super(x, y, 100);
|
super(x, y, 0.1);
|
||||||
|
|
||||||
this.xvel = xvel;
|
this.xvel = xvel;
|
||||||
this.yvel = yvel;
|
this.yvel = yvel;
|
||||||
|
@ -31,10 +31,6 @@ export default class Entity extends Body {
|
||||||
return [this.x + this.width / 2, this.y + this.height / 2];
|
return [this.x + this.width / 2, this.y + this.height / 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
orbit(celestial, radius) {
|
|
||||||
this.gravity = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
entities.delete(this);
|
entities.delete(this);
|
||||||
}
|
}
|
||||||
|
@ -50,10 +46,13 @@ export default class Entity extends Body {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerShip.colliding(this.com, this.radius)) {
|
if (playerShip.colliding(this.com, this.radius)) {
|
||||||
|
if (this.touched) return;
|
||||||
let success = events.collectItem(this.type, this.id);
|
let success = events.collectItem(this.type, this.id);
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
particle.createPickupBurst(playerShip, this.com);
|
particle.createPickupBurst(playerShip, this.com);
|
||||||
this.remove();
|
this.remove();
|
||||||
|
} else {
|
||||||
|
this.touched = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ export const entities = new Set();
|
||||||
export const celestials = new Set();
|
export const celestials = new Set();
|
||||||
export const ships = new Set();
|
export const ships = new Set();
|
||||||
export const particles = new Set();
|
export const particles = new Set();
|
||||||
|
export const tracers = new Set();
|
||||||
|
|
||||||
export let playerShip = null;
|
export let playerShip = null;
|
||||||
|
|
||||||
|
@ -19,9 +20,10 @@ export function init() {
|
||||||
celestials.clear();
|
celestials.clear();
|
||||||
ships.clear();
|
ships.clear();
|
||||||
particles.clear();
|
particles.clear();
|
||||||
|
tracers.clear();
|
||||||
spawn.player();
|
spawn.player();
|
||||||
spawn.startPlanet();
|
let p = spawn.startPlanet();
|
||||||
spawn.testEntity();
|
spawn.testEntity(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tick() {
|
export function tick() {
|
||||||
|
@ -29,4 +31,5 @@ export function tick() {
|
||||||
celestials.forEach(c => c.tick());
|
celestials.forEach(c => c.tick());
|
||||||
entities.forEach(e => e.tick());
|
entities.forEach(e => e.tick());
|
||||||
ships.forEach(s => s.tick());
|
ships.forEach(s => s.tick());
|
||||||
|
tracers.forEach(t => t.tick());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as world from './index.mjs';
|
||||||
import * as consts from '../consts.mjs';
|
import * as consts from '../consts.mjs';
|
||||||
import * as particle from './particle.mjs';
|
import * as particle from './particle.mjs';
|
||||||
import * as events from '../game/events.mjs';
|
import * as events from '../game/events.mjs';
|
||||||
|
import Tracer from './tracer.mjs';
|
||||||
import {state} from '../game/index.mjs';
|
import {state} from '../game/index.mjs';
|
||||||
|
|
||||||
export default class Ship extends Body {
|
export default class Ship extends Body {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import Ship from './ship.mjs';
|
||||||
import Module from './module.mjs';
|
import Module from './module.mjs';
|
||||||
import Celestial from './celestial.mjs';
|
import Celestial from './celestial.mjs';
|
||||||
import Entity from './entity.mjs';
|
import Entity from './entity.mjs';
|
||||||
|
import Tracer from './tracer.mjs';
|
||||||
import {modules} from '../data.mjs';
|
import {modules} from '../data.mjs';
|
||||||
import * as world from './index.mjs';
|
import * as world from './index.mjs';
|
||||||
|
|
||||||
|
@ -12,6 +13,10 @@ export function player() {
|
||||||
ship.addModule(0, 2, modules.thruster.light);
|
ship.addModule(0, 2, modules.thruster.light);
|
||||||
world.ships.add(ship);
|
world.ships.add(ship);
|
||||||
world.setPlayerShip(ship);
|
world.setPlayerShip(ship);
|
||||||
|
|
||||||
|
let tracer = new Tracer(ship);
|
||||||
|
world.tracers.add(tracer);
|
||||||
|
|
||||||
return ship;
|
return ship;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +27,10 @@ export function startPlanet() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function testEntity() {
|
export function testEntity(parent) {
|
||||||
let entity = new Entity(0, -50);
|
let entity = new Entity(0, -50);
|
||||||
world.entities.add(entity);
|
world.entities.add(entity);
|
||||||
|
entity.orbit(parent, 10);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
51
js/world/tracer.mjs
Normal file
51
js/world/tracer.mjs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import Body from './body.mjs';
|
||||||
|
import {modules} from '../data.mjs';
|
||||||
|
import {playerShip} from './index.mjs';
|
||||||
|
import {images as assets} from '../assets.mjs';
|
||||||
|
import {celestials, particles, entities} from './index.mjs';
|
||||||
|
import * as particle from './particle.mjs';
|
||||||
|
import * as consts from '../consts.mjs';
|
||||||
|
import * as events from '../game/events.mjs';
|
||||||
|
|
||||||
|
export default class Tracer extends Body {
|
||||||
|
constructor(ship) {
|
||||||
|
super(...ship.pos, 0.1);
|
||||||
|
|
||||||
|
this.ship = ship;
|
||||||
|
this.path = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
run(distance) {
|
||||||
|
this.path = [];
|
||||||
|
[this.x, this.y] = this.ship.com;
|
||||||
|
[this.xvel, this.yvel] = [this.ship.xvel, this.ship.yvel];
|
||||||
|
let dis = 0;
|
||||||
|
let last = this.pos;
|
||||||
|
let factor = 5;
|
||||||
|
|
||||||
|
for (let i = 0; dis < distance; i++) {
|
||||||
|
if (this.tickPath(factor)) break;
|
||||||
|
this.path.push(this.pos);
|
||||||
|
|
||||||
|
if (i % 10 === 0) {
|
||||||
|
let [lx, ly] = last;
|
||||||
|
dis += Math.sqrt((this.x - lx) ** 2 + (this.y - ly) ** 2);
|
||||||
|
last = this.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > distance * 5) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[this.x, this.y] = this.ship.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
this.run(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
tickPath(speed) {
|
||||||
|
this.tickMotion(speed);
|
||||||
|
this.tickGravity(celestials, speed);
|
||||||
|
return !!this.getCelestialCollision(celestials);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue