Add rotation view and path prediction toggles

This commit is contained in:
asraelite 2018-03-06 10:35:54 +00:00
parent ce6a707526
commit 5b861cc341
12 changed files with 195 additions and 19 deletions

View file

@ -11,6 +11,8 @@ export const mapping = {
right: 'KeyD',
exitEdit: 'Escape',
inventory: 'KeyE',
cycleRotation: 'KeyC',
toggleTrace: 'KeyT'
};
let held, pressed;
@ -49,6 +51,15 @@ function tickPlaying() {
state.inventory = !state.inventory;
}
if (pressed[mapping.cycleRotation]) {
events.cycleRotationMode();
}
if (pressed[mapping.toggleTrace]) {
events.toggleTrace();
}
// For debugging.
if (pressed['KeyR']) events.startGame();
}

View file

@ -8,6 +8,23 @@ import * as edit from './edit.mjs';
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() {
game.changeView('game');
graphics.perspective.focusPlayer();
@ -33,6 +50,21 @@ export function toggleEdit() {
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() {
let {valid, reason} = edit.end();

View file

@ -51,6 +51,8 @@ export function changeView(view) {
}
function tick() {
events.tick();
if (state.view == 'game') {
world.tick();
control.tick();

View file

@ -8,6 +8,7 @@ import * as consts from '../consts.mjs';
export let canvas, context, tempCanvas, tempContext;
export let perspective;
export let trace = false;
export function init() {
canvas = document.querySelector('#main');
@ -50,6 +51,23 @@ export function changePerspective(rotationMode, shiftX = 0, shiftY = 0) {
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) {
perspective.zoomDelta(delta);
}
@ -77,6 +95,7 @@ class Perspective {
}
changeRotationMode(mode) {
this.oldShift = this.currentShift;
this.oldTarget = this.currentRotation;
this.rotationMode = mode;
}
@ -111,6 +130,18 @@ class Perspective {
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() {
if (this.focus !== null)
[this.x, this.y] = this.focus.com;
@ -129,6 +160,8 @@ class Perspective {
this.targetRotation = this.focus.r;
}
this.normalize();
let dif = Math.abs(this.targetRotation - this.rotation);
this.rotationMet = dif < (this.rotationMet ? 0.3 : 0.05);
@ -137,8 +170,6 @@ class Perspective {
this.transition *= 0.9;
this.zoomTransition *= 0.9;
this.normalize();
}
reset() {

View file

@ -1,4 +1,5 @@
import {canvas, context} from './index.mjs';
import * as graphics from './index.mjs';
import {images as assets} from '../assets.mjs';
import * as world from '../world/index.mjs';
import {state} from '../game/index.mjs';
@ -6,6 +7,7 @@ import {state} from '../game/index.mjs';
export function render() {
world.particles.forEach(renderParticle);
world.celestials.forEach(renderCelestial);
if (graphics.trace) world.tracers.forEach(renderTracer);
world.ships.forEach(renderShip);
world.entities.forEach(renderEntity);
}
@ -47,3 +49,21 @@ function renderCelestial(cel) {
context.drawImage(cel.image, cel.x, cel.y,
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;
}

View file

@ -56,7 +56,6 @@ export function game() {
}
}
let editShadow = root();
shadow.append(editShadow);
editShadow.posRelative({x: 0.45, y: 0, w: 0.55, h: 0.6});
@ -97,5 +96,16 @@ export function game() {
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;
}

View file

@ -55,20 +55,20 @@ export default class Body {
return this.rotateVector(x, y, this.r);
}
tickMotion() {
this.x += this.xvel;
this.y += this.yvel;
this.r += this.rvel;
this.rvel *= this.rfriction;
tickMotion(speed = 1) {
this.x += this.xvel * speed;
this.y += this.yvel * speed;
this.r += this.rvel * speed;
this.rvel *= this.rfriction * speed;
}
tickGravity(bodies) {
tickGravity(bodies, speed = 1) {
bodies.forEach(b => {
let force = b.mass / (this.distanceTo(b) ** 2) * G;
let [[ax, ay], [bx, by]] = [this.com, b.com];
let angle = Math.atan2(by - ay, bx - ax);
this.xvel += Math.cos(angle) * force;
this.yvel += Math.sin(angle) * force;
this.xvel += Math.cos(angle) * force * speed;
this.yvel += Math.sin(angle) * force * speed;
});
}
@ -100,4 +100,14 @@ export default class Body {
this.yvel += vy;
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;
}
}

View file

@ -13,7 +13,7 @@ export default class Entity extends Body {
yvel = 0,
gravity = false
} = {}) {
super(x, y, 100);
super(x, y, 0.1);
this.xvel = xvel;
this.yvel = yvel;
@ -31,10 +31,6 @@ export default class Entity extends Body {
return [this.x + this.width / 2, this.y + this.height / 2];
}
orbit(celestial, radius) {
this.gravity = true;
}
remove() {
entities.delete(this);
}
@ -50,10 +46,13 @@ export default class Entity extends Body {
}
if (playerShip.colliding(this.com, this.radius)) {
if (this.touched) return;
let success = events.collectItem(this.type, this.id);
if (!success) return;
particle.createPickupBurst(playerShip, this.com);
this.remove();
} else {
this.touched = false;
}
}
}

View file

@ -7,6 +7,7 @@ export const entities = new Set();
export const celestials = new Set();
export const ships = new Set();
export const particles = new Set();
export const tracers = new Set();
export let playerShip = null;
@ -19,9 +20,10 @@ export function init() {
celestials.clear();
ships.clear();
particles.clear();
tracers.clear();
spawn.player();
spawn.startPlanet();
spawn.testEntity();
let p = spawn.startPlanet();
spawn.testEntity(p);
}
export function tick() {
@ -29,4 +31,5 @@ export function tick() {
celestials.forEach(c => c.tick());
entities.forEach(e => e.tick());
ships.forEach(s => s.tick());
tracers.forEach(t => t.tick());
}

View file

@ -4,6 +4,7 @@ import * as world from './index.mjs';
import * as consts from '../consts.mjs';
import * as particle from './particle.mjs';
import * as events from '../game/events.mjs';
import Tracer from './tracer.mjs';
import {state} from '../game/index.mjs';
export default class Ship extends Body {

View file

@ -2,6 +2,7 @@ import Ship from './ship.mjs';
import Module from './module.mjs';
import Celestial from './celestial.mjs';
import Entity from './entity.mjs';
import Tracer from './tracer.mjs';
import {modules} from '../data.mjs';
import * as world from './index.mjs';
@ -12,6 +13,10 @@ export function player() {
ship.addModule(0, 2, modules.thruster.light);
world.ships.add(ship);
world.setPlayerShip(ship);
let tracer = new Tracer(ship);
world.tracers.add(tracer);
return ship;
}
@ -22,9 +27,10 @@ export function startPlanet() {
});
}
export function testEntity() {
export function testEntity(parent) {
let entity = new Entity(0, -50);
world.entities.add(entity);
entity.orbit(parent, 10);
return entity;
}

51
js/world/tracer.mjs Normal file
View 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);
}
}