Add zooming
This commit is contained in:
parent
56a09f98c5
commit
b02675f4fb
12 changed files with 156 additions and 29 deletions
|
@ -13,6 +13,11 @@ export const images = {
|
||||||
thruster: {
|
thruster: {
|
||||||
light: 'modules/light_thruster.svg'
|
light: 'modules/light_thruster.svg'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
celestials: {
|
||||||
|
green: {
|
||||||
|
"0": 'celestials/green_0.svg'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* Constants that do not change during gameplay.
|
* Constants that do not change during gameplay.
|
||||||
* This can kind of be treated like a configuration file, I guess.
|
* This can kind of be treated like a configuration file, I guess.
|
||||||
|
*
|
||||||
|
* All le
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Pixel length of sector.
|
// Unit length of sector. Only for internal representation.
|
||||||
export const SECTOR_SIZE = 512;
|
export const SECTOR_SIZE = 512;
|
||||||
// Star count per sector.
|
// Star count per sector.
|
||||||
export const STAR_DENSITY = (SECTOR_SIZE ** 2) / 10000;
|
export const STAR_DENSITY = (SECTOR_SIZE ** 2) / 10000;
|
||||||
// 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.01;
|
||||||
|
// Perspective constraints. Higher zoom value = closer.
|
||||||
|
export const MIN_ZOOM = 2;
|
||||||
|
export const MAX_ZOOM = 30;
|
||||||
|
export const DEFAULT_ZOOM = 10;
|
||||||
|
export const ZOOM_SPEED = 0.01;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import * as game from './index.mjs';
|
import * as game from './index.mjs';
|
||||||
|
import * as graphics from '../graphics/index.mjs';
|
||||||
|
import * as world from '../world/index.mjs';
|
||||||
|
|
||||||
export function startGame() {
|
export function startGame() {
|
||||||
game.changeView('game');
|
game.changeView('game');
|
||||||
|
graphics.perspective.focusPlayer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ export async function init() {
|
||||||
gui.init();
|
gui.init();
|
||||||
input.init();
|
input.init();
|
||||||
|
|
||||||
//events.startGame();
|
events.startGame();
|
||||||
|
|
||||||
|
//tick(); return;
|
||||||
|
|
||||||
// Recursive `requestAnimationFrame` can cause problems with Parcel.
|
// Recursive `requestAnimationFrame` can cause problems with Parcel.
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import {game} from '../game/index.mjs';
|
|
||||||
import {getContainedSectors} from '../world/index.mjs';
|
|
||||||
import * as background from './background.mjs';
|
|
||||||
import * as gui from './gui.mjs';
|
import * as gui from './gui.mjs';
|
||||||
import * as draw from './draw.mjs';
|
import * as draw from './draw.mjs';
|
||||||
import * as ship from './ship.mjs';
|
import * as input from '../input.mjs';
|
||||||
|
import {render as renderWorld} from './world.mjs';
|
||||||
|
import {render as renderBackground} from './background.mjs';
|
||||||
|
import * as world from '../world/index.mjs';
|
||||||
|
import * as consts from '../consts.mjs';
|
||||||
|
|
||||||
export let canvas, context, tempCanvas, tempContext;
|
export let canvas, context, tempCanvas, tempContext;
|
||||||
export let view;
|
export let perspective;
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
canvas = document.querySelector('#main');
|
canvas = document.querySelector('#main');
|
||||||
|
@ -17,12 +18,7 @@ export function init() {
|
||||||
canvas.width = 600;
|
canvas.width = 600;
|
||||||
canvas.height = 600;
|
canvas.height = 600;
|
||||||
|
|
||||||
view = {
|
perspective = new Perspective();
|
||||||
bounds: [0, 0, canvas.width, canvas.height],
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
zoom: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
draw.text('Loading...', canvas.width / 2, canvas.height / 2,
|
draw.text('Loading...', canvas.width / 2, canvas.height / 2,
|
||||||
{ align: 'center', valign: 'middle' });
|
{ align: 'center', valign: 'middle' });
|
||||||
|
@ -32,18 +28,84 @@ export function render() {
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
context.fillStyle = '#000';
|
context.fillStyle = '#000';
|
||||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
renderBackground();
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
|
perspective.tick();
|
||||||
// TODO: Translate canvas.
|
perspective.transformCanvas();
|
||||||
|
renderWorld();
|
||||||
background.render();
|
|
||||||
ship.render();
|
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
|
|
||||||
gui.render();
|
gui.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVisibleSectors() {
|
export function getVisibleSectors() {
|
||||||
return getContainedSectors(...view.bounds);
|
return world.getContainedSectors(...perspective.bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Perspective {
|
||||||
|
constructor() {
|
||||||
|
this.x = 0;
|
||||||
|
this.y = 0;
|
||||||
|
this.bounds = [0, 0, canvas.width, canvas.height];
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
if (input.mouse.scroll !== 0) {
|
||||||
|
this.zoomDelta(-input.mouse.scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.focus !== null) {
|
||||||
|
this.x = this.focus.x;
|
||||||
|
this.y = this.focus.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.rotationFocus !== null) {
|
||||||
|
this.targetRotation = this.rotationFocus.r;
|
||||||
|
} else {
|
||||||
|
this.targetRotation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.smoothRotation) {
|
||||||
|
this.rotation = (this.rotation * 0.9 + this.targetRotation * 0.1);
|
||||||
|
} else {
|
||||||
|
this.rotation = this.targetRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.rotation = 0;
|
||||||
|
this.targetRotation = 0;
|
||||||
|
this.smoothRotation = false;
|
||||||
|
this.zoom = consts.DEFAULT_ZOOM;
|
||||||
|
this.focus = null;
|
||||||
|
this.rotationFocus = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
focusPlayer() {
|
||||||
|
this.focus = world.playerShip;
|
||||||
|
this.rotationFocus = world.playerShip;
|
||||||
|
this.smoothRotation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomDelta(delta) {
|
||||||
|
let factor = 1 + (consts.ZOOM_SPEED * Math.abs(delta));
|
||||||
|
this.zoom *= delta > 0 ? factor : 1 / factor;
|
||||||
|
this.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize() {
|
||||||
|
this.zoom = Math.max(consts.MIN_ZOOM,
|
||||||
|
Math.min(consts.MAX_ZOOM, this.zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
transformCanvas() {
|
||||||
|
let [bx, by, bw, bh] = this.bounds;
|
||||||
|
let tx = -this.x + bw / 2;
|
||||||
|
let ty = -this.y + bh / 2;
|
||||||
|
context.translate(tx, ty);
|
||||||
|
context.scale(this.zoom, this.zoom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@ import * as world from '../world/index.mjs';
|
||||||
|
|
||||||
export function render() {
|
export function render() {
|
||||||
world.ships.forEach(renderShip);
|
world.ships.forEach(renderShip);
|
||||||
|
world.celestials.forEach(renderCelestial);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderShip(ship) {
|
function renderShip(ship) {
|
||||||
context.fillStyle = 'red';
|
context.fillStyle = 'red';
|
||||||
//context.fillRect(ship.x, ship.y, 10, 10);
|
//context.fillRect(ship.x, ship.y, 10, 10);
|
||||||
let size = 100;
|
let size = 1;
|
||||||
context.drawImage(assets.modules.capsule.small, ship.x, ship.y,
|
context.drawImage(assets.modules.capsule.small, ship.x, ship.y,
|
||||||
size, size);
|
size, size);
|
||||||
context.drawImage(assets.modules.fuel.small, ship.x, ship.y + size,
|
context.drawImage(assets.modules.fuel.small, ship.x, ship.y + size,
|
||||||
|
@ -17,3 +18,11 @@ function renderShip(ship) {
|
||||||
context.drawImage(assets.modules.thruster.light, ship.x,
|
context.drawImage(assets.modules.thruster.light, ship.x,
|
||||||
ship.y + size * 2, size, size);
|
ship.y + size * 2, size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const celestialImages = {
|
||||||
|
green: Object.values(assets.celestials.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCelestial(cel) {
|
||||||
|
context.drawImage(cel.image, cel.x, cel.y, cel.diameter, cel.diameter);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import {canvas} from './graphics/index.mjs';
|
import {canvas} from './graphics/index.mjs';
|
||||||
|
|
||||||
export const mouse = { pressed: {}, held: {}, x: 0, y: 0 };
|
export const mouse = { pressed: {}, held: {}, x: 0, y: 0, scroll: 0 };
|
||||||
export const keyCode = { pressed: {}, held: {} };
|
export const keyCode = { pressed: {}, held: {} };
|
||||||
export const key = { pressed: {}, held: {} };
|
export const key = { pressed: {}, held: {} };
|
||||||
export const action = {};
|
export const action = {};
|
||||||
|
@ -11,6 +11,7 @@ export function tick() {
|
||||||
mouse.pressed = {};
|
mouse.pressed = {};
|
||||||
keyCode.pressed = {};
|
keyCode.pressed = {};
|
||||||
key.pressed = {};
|
key.pressed = {};
|
||||||
|
mouse.scroll = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
|
@ -43,4 +44,8 @@ export function init() {
|
||||||
mouse.x = event.clientX - rect.left;
|
mouse.x = event.clientX - rect.left;
|
||||||
mouse.y = event.clientY - rect.top;
|
mouse.y = event.clientY - rect.top;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener('wheel', event => {
|
||||||
|
mouse.scroll = event.deltaY;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default class Body {
|
||||||
this.rvel = 0;
|
this.rvel = 0;
|
||||||
this.mass = mass;
|
this.mass = mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
tickGravity(bodies) {
|
tickGravity(bodies) {
|
||||||
bodies.forEach(b => {
|
bodies.forEach(b => {
|
||||||
let force = b.mass / this.mass / (distanceTo(b) ** 2) * G;
|
let force = b.mass / this.mass / (distanceTo(b) ** 2) * G;
|
||||||
|
|
|
@ -1,10 +1,29 @@
|
||||||
|
import {images as assets} from '../assets.mjs';
|
||||||
import Body from './body.mjs';
|
import Body from './body.mjs';
|
||||||
|
|
||||||
export default class Celestial extends Body {
|
export default class Celestial extends Body {
|
||||||
constructor(x, y, radius, {
|
constructor(x, y, radius, {
|
||||||
density = 1,
|
density = 1,
|
||||||
mass = (radius ** 2) * density
|
type = 'rock'
|
||||||
}) {
|
}) {
|
||||||
|
let mass = (radius ** 2) * density
|
||||||
super(x, y, mass);
|
super(x, y, mass);
|
||||||
|
this.radius = radius;
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
let imageArr = Object.values(assets.celestials[this.type]);
|
||||||
|
this.image = imageArr[Math.random() * imageArr.length | 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get center() {
|
||||||
|
return [this.x + this.radius / 2, this.y + this.radius / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
get diameter() {
|
||||||
|
return this.radius * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ export function init() {
|
||||||
entities.clear();
|
entities.clear();
|
||||||
celestials.clear();
|
celestials.clear();
|
||||||
spawn.player();
|
spawn.player();
|
||||||
|
spawn.startPlanet();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tick() {
|
export function tick() {
|
||||||
|
|
|
@ -3,6 +3,9 @@ export default class Module {
|
||||||
name = 'Unnamed Module',
|
name = 'Unnamed Module',
|
||||||
type = 'block',
|
type = 'block',
|
||||||
mass = 1,
|
mass = 1,
|
||||||
|
// Fuel
|
||||||
|
filled = false,
|
||||||
|
fuelCapacity = 0,
|
||||||
...properties
|
...properties
|
||||||
}) {
|
}) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
@ -10,6 +13,7 @@ export default class Module {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.mass = mass;
|
this.mass = mass;
|
||||||
|
// Fuel
|
||||||
|
this.fuel = filled ? fuelCapacity : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Ship from './ship.mjs';
|
import Ship from './ship.mjs';
|
||||||
import Module from './module.mjs';
|
import Module from './module.mjs';
|
||||||
import Celestial from './ship.mjs';
|
import Celestial from './celestial.mjs';
|
||||||
import {modules} from '../data.mjs';
|
import {modules} from '../data.mjs';
|
||||||
import * as world from './index.mjs';
|
import * as world from './index.mjs';
|
||||||
|
|
||||||
|
@ -11,9 +11,18 @@ 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);
|
||||||
|
return ship;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make module length = 1, define all other length off that.
|
export function startPlanet() {
|
||||||
export function celestial() {
|
return celestial(-40, 10, 40, {
|
||||||
let celestial = new Celestial(0, 50, 45)
|
density: 1,
|
||||||
|
type: 'green'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function celestial(x, y, radius, params) {
|
||||||
|
let celestial = new Celestial(x, y, radius, params);
|
||||||
|
world.celestials.add(celestial);
|
||||||
|
return celestial;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue