Add collectable items
This commit is contained in:
parent
826986cdbf
commit
69fee5e73d
10 changed files with 131 additions and 52 deletions
|
@ -11,7 +11,7 @@ export const EPSILON = 1e-8;
|
||||||
// Unit length of sector. Only for internal representation.
|
// Unit length of sector. Only for internal representation.
|
||||||
export const SECTOR_SIZE = 512;
|
export const SECTOR_SIZE = 512;
|
||||||
// G, G-boy, The big G, Mr. G, g's big brother, G-dog
|
// G, G-boy, The big G, Mr. G, g's big brother, G-dog
|
||||||
export const GRAVITATIONAL_CONSTANT = 0.01;
|
export const GRAVITATIONAL_CONSTANT = 0.002;
|
||||||
// Perspective constraints. Higher zoom value = closer.
|
// Perspective constraints. Higher zoom value = closer.
|
||||||
export const MIN_ZOOM = 1;
|
export const MIN_ZOOM = 1;
|
||||||
export const MAX_ZOOM = 100;
|
export const MAX_ZOOM = 100;
|
||||||
|
@ -22,7 +22,11 @@ export const TIP_ANGLE = 0.3;
|
||||||
export const TIP_SPEED = 0.015;
|
export const TIP_SPEED = 0.015;
|
||||||
// Ship flight mechanics. Speed measured in units per tick.
|
// Ship flight mechanics. Speed measured in units per tick.
|
||||||
export const FUEL_BURN_RATE = 0.01;
|
export const FUEL_BURN_RATE = 0.01;
|
||||||
|
export const THRUST_POWER = 0.007;
|
||||||
|
export const TURN_POWER = 0.05;
|
||||||
// Distance at which an orbited planet will not be considered a parent body.
|
// Distance at which an orbited planet will not be considered a parent body.
|
||||||
export const MAX_PARENT_CELESTIAL_DISTANCE = 120;
|
export const MAX_PARENT_CELESTIAL_DISTANCE = 120;
|
||||||
// Ship editing.
|
// Ship editing.
|
||||||
export const EDIT_MARGIN = 2;
|
export const EDIT_MARGIN = 2;
|
||||||
|
// Floating items.
|
||||||
|
export const ENTITY_ROTATION_RATE = 0.01;
|
||||||
|
|
|
@ -2,6 +2,8 @@ import * as game from './index.mjs';
|
||||||
import * as graphics from '../graphics/index.mjs';
|
import * as graphics from '../graphics/index.mjs';
|
||||||
import * as world from '../world/index.mjs';
|
import * as world from '../world/index.mjs';
|
||||||
import * as player from './player.mjs';
|
import * as player from './player.mjs';
|
||||||
|
import * as inventory from './inventory.mjs';
|
||||||
|
import * as particle from '../world/particle.mjs';
|
||||||
import * as edit from './edit.mjs';
|
import * as edit from './edit.mjs';
|
||||||
|
|
||||||
export let shipLanded = false;
|
export let shipLanded = false;
|
||||||
|
@ -48,3 +50,12 @@ export function invalidTilePlacement() {
|
||||||
export function tilePlacement() {
|
export function tilePlacement() {
|
||||||
// TODO: Play some audio.
|
// TODO: Play some audio.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tossItem() {
|
||||||
|
particle.createItemToss(world.playerShip);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collectItem(type, id) {
|
||||||
|
inventory.addItem(type, id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {modules} from '../data.mjs';
|
import {modules} from '../data.mjs';
|
||||||
import {images as assets} from '../assets.mjs';
|
import {images as assets} from '../assets.mjs';
|
||||||
|
import * as events from './events.mjs';
|
||||||
|
|
||||||
export const items = new Map();
|
export const items = new Map();
|
||||||
export let currentItem = null;
|
export let currentItem = null;
|
||||||
|
@ -30,6 +31,7 @@ export function removeItem(type, id) {
|
||||||
items.delete(mapId);
|
items.delete(mapId);
|
||||||
currentItem = null;
|
currentItem = null;
|
||||||
}
|
}
|
||||||
|
events.tossItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectItem(type, id) {
|
export function selectItem(type, id) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ export function render() {
|
||||||
world.particles.forEach(renderParticle);
|
world.particles.forEach(renderParticle);
|
||||||
world.celestials.forEach(renderCelestial);
|
world.celestials.forEach(renderCelestial);
|
||||||
world.ships.forEach(renderShip);
|
world.ships.forEach(renderShip);
|
||||||
|
world.entities.forEach(renderEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderParticle(particle) {
|
function renderParticle(particle) {
|
||||||
|
@ -14,6 +15,14 @@ function renderParticle(particle) {
|
||||||
context.fillRect(...particle.com, particle.size, particle.size);
|
context.fillRect(...particle.com, particle.size, particle.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderEntity(entity) {
|
||||||
|
context.save();
|
||||||
|
context.translate(...entity.com);
|
||||||
|
context.rotate(entity.r);
|
||||||
|
context.drawImage(entity.image, -0.5, -0.5, 1, 1);
|
||||||
|
context.restore();
|
||||||
|
}
|
||||||
|
|
||||||
function renderShip(ship) {
|
function renderShip(ship) {
|
||||||
context.save();
|
context.save();
|
||||||
context.translate(...ship.com);
|
context.translate(...ship.com);
|
||||||
|
|
|
@ -24,6 +24,15 @@ export default class Body {
|
||||||
return Math.sqrt(this.xvel ** 2 + this.yvel ** 2);
|
return Math.sqrt(this.xvel ** 2 + this.yvel ** 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCelestialCollision(celestials) {
|
||||||
|
let result = false;
|
||||||
|
celestials.forEach(c => {
|
||||||
|
let dis = this.distanceTo(c);
|
||||||
|
if (dis < c.radius) result = c;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
getWorldPoint(lx, ly) {
|
getWorldPoint(lx, ly) {
|
||||||
let [cx, cy] = this.localCom;
|
let [cx, cy] = this.localCom;
|
||||||
let [nx, ny] = this.rotateVector(lx - cx, ly - cy, this.r);
|
let [nx, ny] = this.rotateVector(lx - cx, ly - cy, this.r);
|
||||||
|
@ -55,7 +64,7 @@ export default class Body {
|
||||||
|
|
||||||
tickGravity(bodies) {
|
tickGravity(bodies) {
|
||||||
bodies.forEach(b => {
|
bodies.forEach(b => {
|
||||||
let force = b.mass / this.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;
|
||||||
|
|
|
@ -1,64 +1,59 @@
|
||||||
import Body from './body.mjs';
|
import Body from './body.mjs';
|
||||||
import {modules} from '../data.mjs';
|
import {modules} from '../data.mjs';
|
||||||
import {celestials, particles} from './index.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 function createThrustExhaust(thruster) {
|
export default class Entity extends Body {
|
||||||
let ship = thruster.ship;
|
constructor(x, y, type = 'fuel', id = 'small', {
|
||||||
let [fx, fy] = ship.relativeVector(0, 0.2);
|
|
||||||
let [dx, dy] = ship.relativeVector((Math.random() - 0.5) * 0.5, 0.5);
|
|
||||||
let [cx, cy] = thruster.com;
|
|
||||||
particles.add(new Particle(cx + dx, cy + dy, {
|
|
||||||
xvel: ship.xvel + fx,
|
|
||||||
yvel: ship.yvel + fy,
|
|
||||||
color: '#f4c542',
|
|
||||||
lifetime: 5,
|
|
||||||
size: 0.07
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
class Particle extends Body {
|
|
||||||
constructor(x, y, {
|
|
||||||
xvel = 0,
|
xvel = 0,
|
||||||
yvel = 0,
|
yvel = 0,
|
||||||
spray = 0.1,
|
gravity = false
|
||||||
fizzle = 0,
|
} = {}) {
|
||||||
maxFizzle = fizzle * 2,
|
super(x, y, 100);
|
||||||
color = '#fff',
|
|
||||||
gravity = false,
|
|
||||||
lifetime = 50,
|
|
||||||
size = 0.1,
|
|
||||||
friction = 0.99
|
|
||||||
}) {
|
|
||||||
super(x, y, 0.1);
|
|
||||||
|
|
||||||
this.size = size;
|
this.xvel = xvel;
|
||||||
this.xvel = xvel + (Math.random() - 0.5) * spray;
|
this.yvel = yvel;
|
||||||
this.yvel = yvel + (Math.random() - 0.5) * spray;
|
this.width = 1;
|
||||||
this.friction = friction;
|
this.height = 1;
|
||||||
this.fizzle = fizzle;
|
this.radius = (this.width + this.height) / 2;
|
||||||
this.maxFizzle = maxFizzle;
|
this.type = type;
|
||||||
this.color = color;
|
this.id = id;
|
||||||
|
this.image = assets.modules[type][id];
|
||||||
this.gravity = gravity;
|
this.gravity = gravity;
|
||||||
this.life = lifetime;
|
this.touched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get com() {
|
get com() {
|
||||||
return [this.x - this.size / 2, this.y - this.size / 2];
|
return [this.x + this.width / 2, this.y + this.height / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
orbit(celestial, radius) {
|
||||||
|
this.gravity = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
entities.delete(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
if (!this.life--) {
|
this.r += consts.ENTITY_ROTATION_RATE;
|
||||||
particles.delete(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tickMotion();
|
this.tickMotion();
|
||||||
if (this.gravity) this.tickGravity(celestials);
|
if (this.gravity) this.tickGravity(celestials);
|
||||||
|
let col = this.getCelestialCollision(celestials);
|
||||||
|
|
||||||
this.xvel *= this.friction;
|
if (col !== false) {
|
||||||
this.yvel *= this.friction;
|
this.remove();
|
||||||
this.x += (Math.random() - 0.5) * this.fizzle;
|
}
|
||||||
this.y += (Math.random() - 0.5) * this.fizzle;
|
|
||||||
if (this.fizzle < this.mazFizzle) this.fizzle *= 1.05;
|
if (playerShip.colliding(this.com, this.radius)) {
|
||||||
|
let success = events.collectItem(this.type, this.id);
|
||||||
|
if (!success) return;
|
||||||
|
particle.createPickupBurst(playerShip, this.com);
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ export function init() {
|
||||||
particles.clear();
|
particles.clear();
|
||||||
spawn.player();
|
spawn.player();
|
||||||
spawn.startPlanet();
|
spawn.startPlanet();
|
||||||
|
spawn.testEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tick() {
|
export function tick() {
|
||||||
|
|
|
@ -15,6 +15,31 @@ export function createThrustExhaust(thruster) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createPickupBurst(ship, point) {
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
particles.add(new Particle(...point, {
|
||||||
|
xvel: ship.xvel,
|
||||||
|
yvel: ship.yvel,
|
||||||
|
color: '#eae55d',
|
||||||
|
lifetime: Math.random() * 20 + 15,
|
||||||
|
friction: 0.95,
|
||||||
|
size: Math.random() * 0.2 + 0.05,
|
||||||
|
spray: 0.3
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createItemToss(ship) {
|
||||||
|
particles.add(new Particle(...ship.com, {
|
||||||
|
xvel: ship.xvel,
|
||||||
|
yvel: ship.yvel,
|
||||||
|
color: '#a87234',
|
||||||
|
lifetime: 50,
|
||||||
|
size: 0.6,
|
||||||
|
spray: 0.4
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
class Particle extends Body {
|
class Particle extends Body {
|
||||||
constructor(x, y, {
|
constructor(x, y, {
|
||||||
xvel = 0,
|
xvel = 0,
|
||||||
|
@ -46,7 +71,7 @@ class Particle extends Body {
|
||||||
}
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
if (!this.life--) {
|
if (this.life-- <= 0) {
|
||||||
particles.delete(this);
|
particles.delete(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,19 @@ export default class Ship extends Body {
|
||||||
Math.max(Math.sqrt((bx - lx) ** 2 + (by - ly) ** 2), a), 0) + 1;
|
Math.max(Math.sqrt((bx - lx) ** 2 + (by - ly) ** 2), a), 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
colliding(point, radius) {
|
||||||
|
let [px, py] = point;
|
||||||
|
let result = false;
|
||||||
|
|
||||||
|
this.modules.forEach(m => {
|
||||||
|
let [mx, my] = this.getWorldPoint(...m.localCom);
|
||||||
|
let dis = Math.sqrt((py - my) ** 2 + (px - mx) ** 2);
|
||||||
|
if (dis < radius) result = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
resolveCollisions() {
|
resolveCollisions() {
|
||||||
this.landed = false;
|
this.landed = false;
|
||||||
|
|
||||||
|
@ -127,8 +140,11 @@ export default class Ship extends Body {
|
||||||
|
|
||||||
applyThrust({ forward = 0, left = 0, right = 0, back = 0,
|
applyThrust({ forward = 0, left = 0, right = 0, back = 0,
|
||||||
turnLeft = 0, turnRight = 0}) {
|
turnLeft = 0, turnRight = 0}) {
|
||||||
let turnForce = (turnRight - turnLeft) / 20;
|
|
||||||
this.applyDirectionalForce(0, -forward / 30, turnForce);
|
let thrustForce = -forward * consts.THRUST_POWER;
|
||||||
|
let turnForce = (turnRight - turnLeft) * consts.TURN_POWER;
|
||||||
|
|
||||||
|
this.applyDirectionalForce(0, thrustForce, turnForce);
|
||||||
|
|
||||||
this.modules.forEach(m => {
|
this.modules.forEach(m => {
|
||||||
if (m.type !== 'thruster') return;
|
if (m.type !== 'thruster') return;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Ship from './ship.mjs';
|
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 {modules} from '../data.mjs';
|
import {modules} from '../data.mjs';
|
||||||
import * as world from './index.mjs';
|
import * as world from './index.mjs';
|
||||||
|
|
||||||
|
@ -16,11 +17,17 @@ export function player() {
|
||||||
|
|
||||||
export function startPlanet() {
|
export function startPlanet() {
|
||||||
return celestial(0, 0, 40, {
|
return celestial(0, 0, 40, {
|
||||||
density: 10,
|
density: 3,
|
||||||
type: 'green'
|
type: 'green'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testEntity() {
|
||||||
|
let entity = new Entity(0, -50);
|
||||||
|
world.entities.add(entity);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
export function celestial(x, y, radius, params) {
|
export function celestial(x, y, radius, params) {
|
||||||
let celestial = new Celestial(x - radius, y - radius, radius, params);
|
let celestial = new Celestial(x - radius, y - radius, radius, params);
|
||||||
world.celestials.add(celestial);
|
world.celestials.add(celestial);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue