Compare commits

...

7 Commits

Author SHA1 Message Date
transoptimal 811b27da46 add world utility function for setting tiles to empty. 2023-06-28 15:08:09 +02:00
transoptimal f2aa5ede1b make representation of empty tiles consistent.
previously, world generation would represent empty tiles as the number
0, while other code would expect them to be an object with its `type`
property set to `"empty"`. the object representation is now used
consistently.
2023-06-28 15:06:56 +02:00
transoptimal b389e3b401 recursively update tiles within boxes. 2023-06-28 15:03:22 +02:00
transoptimal 3e4e58e2a2 improve grass growth.
grass now checks all adjacent tiles when attempting to grow.
2023-06-28 14:35:07 +02:00
transoptimal ed99df295a initial grass test.
start working on tile updating code; add grass as test & demo for this.
add temporary "texture" for grass, and keybind for creating it.
2023-06-28 14:24:18 +02:00
transoptimal adbc9939ac fix typo in iter_2d.
replace two "for in array" loops with "for of array" loops. the former gives indexes
as strings, whereas the latter gives the actual array items.
2023-06-28 14:22:32 +02:00
transoptimal a9ec0b4e75 add todo list and todo item. 2023-06-28 08:54:35 +02:00
8 changed files with 126 additions and 19 deletions

1
TODO.md Normal file
View File

@ -0,0 +1 @@
- rewrite import paths to be absolute.

View File

@ -37,8 +37,7 @@ export function draw_world (box, start_x = 0, start_y = 0, scale = BASE_SCALE) {
draw_floor(start_x, start_y, scale, !checkerboard(start_x, start_y));
iter_2d(range(0, world.BOX_SIZE - 1), (x, y) => {
const tile = world.get_tile(box, x, y);
world.for_each_tile(box, (x, y, tile) => {
draw_tile(tile, x * scale + start_x, y * scale + start_y, scale);
});
@ -62,6 +61,15 @@ function draw_tile (tile, x, y, scale) {
draw_rect(x, y, scale);
break;
}
// temporary: in the future, textures will exist and tile definitions will exist and keep track of textures for tiles.
case "grass": {
graphics.set_color("#2a0");
draw_rect(x, y, scale);
graphics.set_color("#4c0");
draw_rect(x, y, scale * 0.5);
draw_rect(x + scale / 2, y + scale / 2, scale * 0.5);
break;
}
}
}

View File

@ -1,21 +1,32 @@
import * as graphics from "./graphics.mjs";
import { BOX_SIZE, get_tile } from "./world.mjs";
import { BOX_SIZE, get_tile, get_root } from "./world.mjs";
import { get_player_box } from "./player.mjs";
import { save_in_browser, load_from_browser } from "./save_load.mjs";
import { tick } from "/js/tile_update.mjs";
load_from_browser();
function render (timestamp) {
function render (_delta_time) {
graphics.clear();
graphics.draw_world(get_player_box());
graphics.render();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
let last_time = new Date().getTime();
function main (timestamp) {
let dt_ms = timestamp - last_time;
last_time += dt_ms;
const delta = dt_ms / 1000;
render(delta);
tick(get_root(), delta);
requestAnimationFrame(main);
}
requestAnimationFrame(main);
function autosave () {
save_in_browser();

View File

@ -33,9 +33,7 @@ on_press(" ", _ => {
});
function clear_tile (x, y) {
world.set_tile(player.box, x, y, {
type: "empty",
});
world.clear_tile(player.box, x, y);
}
on_press("Backspace", _ => {
@ -48,12 +46,16 @@ export function get_player_box () {
return player.box;
}
function set_painting_key (key, color) {
function set_place_key (key, tile) {
on_press(key, _ => {
world.set_tile(player.box, player.x, player.y, {
type: "paint",
color,
});
world.set_tile(player.box, player.x, player.y, structuredClone(tile));
});
}
function set_painting_key (key, color) {
set_place_key(key, {
type: "paint",
color,
});
}
@ -71,3 +73,7 @@ set_painting_key("x", "#aaa");
// black and white
set_painting_key("c", "#000");
set_painting_key("v", "#fff");
// grass test
set_place_key("g", {
type: "grass",
});

47
js/tile_update.mjs Normal file
View File

@ -0,0 +1,47 @@
import * as world from "/js/world.mjs";
import { get_player_box } from "/js/player.mjs";
import * as random from "/js/utils/random.mjs";
// lots of this code is very hacky temporary for testing things out & getting started with tile updates.
export function tick (box, delta_time) {
world.for_each_tile(box, (x, y, tile) => {
if (tile_tickers.has(tile.type)) {
tile_tickers.get(tile.type)(box, x, y, delta_time);
}
});
}
const tile_tickers = new Map();
const dirs = [
[ -1, 0 ],
[ 1, 0 ],
[ 0, -1 ],
[ 0, 1 ],
];
// this might become terrible for performance eventually.
tile_tickers.set("box", (box, x, y, delta_time) => {
tick(world.get_tile(box, x, y).box, delta_time);
});
tile_tickers.set("grass", (box, x, y, delta_time) => {
const tile = world.get_tile(box, x, y);
if (Math.random() > 0.8 ** delta_time) {
const dir = random.item(dirs);
const spaces = random.shuffle(dirs)
.map(([d_x, d_y]) => [x + d_x, y + d_y]);
for (const [new_x, new_y] of spaces) {
if (world.get_tile(box, new_x, new_y).type === "empty") {
world.set_tile(box, new_x, new_y, {
type: "grass",
});
break;
}
}
};
});

21
js/utils/random.mjs Normal file
View File

@ -0,0 +1,21 @@
export function range (min, max) {
return min + Math.random() * (max - min);
}
export function integer (min, max) {
return Math.floor(range(min, max));
}
export function item (array) {
return array[integer(0, array.length)];
}
export function shuffle (array) {
const copy = [ ...array ];
const result = [];
while (copy.length > 0) {
const index = integer(0, copy.length);
result.push(copy.splice(index, 1)[0]);
}
return result;
}

View File

@ -19,8 +19,8 @@ export function range (start, end) {
}
export function iter_2d (range_1d, callback) {
for (const y in range_1d) {
for (const x in range_1d) {
for (const y of range_1d) {
for (const x of range_1d) {
callback(x, y);
}
}

View File

@ -7,12 +7,18 @@ export const CENTER = Math.floor(BOX_SIZE / 2);
function create_world (size) {
return {
tiles: Array(size).fill(0).map(_ => Array(size).fill(0)),
tiles: Array(size).fill(0).map(_ =>
Array(size).fill(0).map(_ => empty_tile())
),
depth: 0,
};
}
const world = create_world(BOX_SIZE);
export function empty_tile () {
return { type: "empty" };
}
export function create_new () {
return create_world(BOX_SIZE);
}
@ -27,6 +33,10 @@ export function get_tile (world, x, y) {
return world.tiles[x][y];
}
export function clear_tile (box, x, y) {
set_tile(box, x, y, empty_tile());
}
export function create_box (parent) {
return {
...create_world(BOX_SIZE),
@ -73,7 +83,10 @@ function reconstruct_parent (world, parent) {
}
export function from_json (json) {
const result = JSON.parse(json);
const result = JSON.parse(json, (key, value) => {
if (value === undefined || value === 0 || value === null) return empty_tile();
return value;
});
for_each_tile(result, (x, y, tile) => {
if (tile.type === "box") {