diff --git a/README.md b/README.md new file mode 100644 index 0000000..16efc9f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Improcket + +A little 2D space rocket game. Not done tho. diff --git a/js/assets.mjs b/js/assets.mjs new file mode 100644 index 0000000..e69de29 diff --git a/js/consts.mjs b/js/consts.mjs new file mode 100644 index 0000000..15d11dc --- /dev/null +++ b/js/consts.mjs @@ -0,0 +1,9 @@ +/* + * Constants that do not change during gameplay. + * This can kind of be treated like a configuration file, I guess. + */ + +// Pixel length of sector. +export const SECTOR_SIZE = 512; +// Star count per sector. +export const STAR_DENSITY = (SECTOR_SIZE ** 2) / 10000; diff --git a/js/game.mjs b/js/game.mjs index c11261e..979a673 100644 --- a/js/game.mjs +++ b/js/game.mjs @@ -1,16 +1,21 @@ +import * as graphics from './graphics/index.mjs'; - -const game = { - state: { - room: 'menu', - paused: false - } -}; +export let game; export function init() { - game.state.room = 'menu'; + game = { + state: { + room: 'menu', + paused: false + } + }; + + graphics.init(); + + tick(); } function tick() { + graphics.render(); requestAnimationFrame(tick); } diff --git a/js/graphics/background.mjs b/js/graphics/background.mjs index e69de29..82a4c8e 100644 --- a/js/graphics/background.mjs +++ b/js/graphics/background.mjs @@ -0,0 +1,21 @@ +import {SeededRandom} from '../util.mjs'; +import {context, view, getVisibleSectors} from './index.mjs'; +import {STAR_DENSITY} from '../consts.mjs'; + +export function render() { + context.fillStyle = '#000'; + + getVisibleSectors().forEach(s => renderSectorStars(s)); +} + +function renderSectorStars(sector) { + let rand = new SeededRandom(sector.numId); + + context.fillStyle = '#fff'; + + for (let i = 0; i < STAR_DENSITY; i++) { + let sx = rand.next() * sector.size + sector.wx; + let sy = rand.next() * sector.size + sector.wy; + context.fillRect(sx, sy, 1.5, 1.5); + } +} diff --git a/js/graphics/index.mjs b/js/graphics/index.mjs index e69de29..7cc470d 100644 --- a/js/graphics/index.mjs +++ b/js/graphics/index.mjs @@ -0,0 +1,39 @@ +import {game} from '../game.mjs'; +import {getContainedSectors} from '../world/index.mjs'; +import * as background from './background.mjs'; + +export let canvas, context, tempCanvas, tempContext; +export let view; + +export function init() { + canvas = document.querySelector('#main'); + context = canvas.getContext('2d'); + tempCanvas = document.querySelector('#temp'); + tempContext = tempCanvas.getContext('2d'); + + canvas.width = 600; + canvas.height = 600; + + view = { + bounds: [0, 0, canvas.width, canvas.height], + x: 0, + y: 0, + zoom: 1 + } +} + +export function render() { + context.clearRect(0, 0, canvas.width, canvas.height); + context.fillRect(0, 0, canvas.width, canvas.height); + context.save(); + + // TODO: Translate canvas. + + background.render(); + + context.restore(); +} + +export function getVisibleSectors() { + return getContainedSectors(...view.bounds); +} diff --git a/js/graphics/rocket.mjs b/js/graphics/rocket.mjs new file mode 100644 index 0000000..474ccf4 --- /dev/null +++ b/js/graphics/rocket.mjs @@ -0,0 +1,6 @@ +import {canvas, context} from './index.mjs'; +import * as assets from '../assets.mjs'; + +export function render() { + +} diff --git a/js/util.mjs b/js/util.mjs new file mode 100644 index 0000000..88ae18f --- /dev/null +++ b/js/util.mjs @@ -0,0 +1,11 @@ +export class SeededRandom { + constructor(seed) { + this.seed = seed % 2147483647; + } + + next() { + this.seed = this.seed * 16807 % 2147483647; + if (this.seed <= 0) this.seed += 2147483646; + return (this.seed - 1) / 2147483646; + } +} diff --git a/js/world/index.mjs b/js/world/index.mjs new file mode 100644 index 0000000..344816f --- /dev/null +++ b/js/world/index.mjs @@ -0,0 +1,3 @@ +import * as sector from './sector.mjs'; + +export {sectorFromPoint, getContainedSectors} from './sector.mjs'; diff --git a/js/world/sector.mjs b/js/world/sector.mjs new file mode 100644 index 0000000..7ec9ebe --- /dev/null +++ b/js/world/sector.mjs @@ -0,0 +1,51 @@ +import {SECTOR_SIZE} from '../consts.mjs'; + +const sectors = new Map(); + +export default class Sector { + constructor(x, y) { + this.x = x; + this.y = y; + this.size = SECTOR_SIZE; + this.wx = this.size * this.x; + this.wy = this.size * this.y; + this.id = getId(this.x, this.y); + this.numId = getNumId(this.x, this.y); + } + + containsPoint(wx, wy) { + return wx >= this.wx && wy >= this.wy && + wx < this.wx + SECTOR_SIZE && wy < this.wy + SECTOR_SIZE; + } +} + +function getId(x, y) { + return `${x}.${y}`; +} + +function getNumId(x, y) { + return Math.abs(x + (y * 3665)) % Number.MAX_SAFE_INTEGER; +} + +export function getSector(x, y) { + if (!sectors.has(getId(x, y))) { + sectors.set(getId(x, y), new Sector(x, y)); + } + + return sectors.get(getId(x, y)); +} + +export function getSectorFromWorld(wx, wy) { + return getSector(wx / SECTOR_SIZE | 0, wy / SECTOR_SIZE | 0); +} + +export function getContainedSectors(startX, startY, endX, endY) { + let sectors = []; + + for (let x = startX; x < endX; x += SECTOR_SIZE) + for (let y = startY; y < endY; y += SECTOR_SIZE) { + sectors.push(getSectorFromWorld(x, y)); + } + + return sectors; +}