Game states and main menu
This commit is contained in:
+18
-40
@@ -1,19 +1,14 @@
|
|||||||
import { Entity, World } from "$/common/ecs/mod.ts";
|
import { World } from "$/common/ecs/mod.ts";
|
||||||
import { MovementSystem } from "$/common/systems/movement_system.ts";
|
import { MovementSystem } from "$/common/systems/movement_system.ts";
|
||||||
import { RenderSystem } from "$/client/systems/render_system.ts";
|
import { RenderSystem } from "$/client/systems/render_system.ts";
|
||||||
import { PlayerControlsSystem } from "$/client/systems/player_controls.ts";
|
import { PlayerControlsSystem } from "$/client/systems/player_controls.ts";
|
||||||
import { DebugUI } from "$/client/debug_ui.ts";
|
import { DebugUI } from "$/client/debug_ui.ts";
|
||||||
import { DebugSystem } from "$/client/systems/debug_system.ts";
|
import { DebugSystem } from "$/client/systems/debug_system.ts";
|
||||||
import { create_player } from "$/client/player.ts";
|
|
||||||
import { Tilemap } from "$/client/components/tilemap.ts";
|
|
||||||
import { AssetManager } from "$/client/assets.ts";
|
|
||||||
import { TileEditorSystem } from "$/client/systems/tile_editor_system.ts";
|
import { TileEditorSystem } from "$/client/systems/tile_editor_system.ts";
|
||||||
import { InventorySystem } from "$/client/systems/inventory_system.ts";
|
import { InventorySystem } from "$/client/systems/inventory_system.ts";
|
||||||
import { UIInteractionSystem } from "$/client/systems/ui_interaction_system.ts";
|
import { UIInteractionSystem } from "$/client/systems/ui_interaction_system.ts";
|
||||||
import { UIRenderSystem } from "$/client/systems/ui_render_system.ts";
|
import { UIRenderSystem } from "$/client/systems/ui_render_system.ts";
|
||||||
import { UIButton } from "./components/ui_components.ts";
|
import { create_main_menu } from "./main_menu.ts";
|
||||||
import { Position } from "../common/components/position.ts";
|
|
||||||
import { open_about } from "./about.ts";
|
|
||||||
|
|
||||||
export class ClientWorld extends World {
|
export class ClientWorld extends World {
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
@@ -23,7 +18,11 @@ export class ClientWorld extends World {
|
|||||||
debugging = false;
|
debugging = false;
|
||||||
|
|
||||||
constructor(canvas: HTMLCanvasElement) {
|
constructor(canvas: HTMLCanvasElement) {
|
||||||
super();
|
super("main_menu");
|
||||||
|
|
||||||
|
this.add_state("main_menu");
|
||||||
|
this.add_state("paused");
|
||||||
|
this.add_state("game");
|
||||||
|
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
@@ -52,41 +51,20 @@ export class ClientWorld extends World {
|
|||||||
|
|
||||||
DebugUI.initialize(this.ctx);
|
DebugUI.initialize(this.ctx);
|
||||||
|
|
||||||
const tilemap = new Entity("backgroundtiles");
|
create_main_menu(this);
|
||||||
tilemap.add(
|
|
||||||
new Tilemap(
|
|
||||||
AssetManager.instance.get("bworld:roguelike"),
|
|
||||||
16,
|
|
||||||
[],
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.add_entity(tilemap);
|
|
||||||
|
|
||||||
const player = create_player(this);
|
|
||||||
|
|
||||||
// UI !
|
|
||||||
const unpause_button = new Entity("unpausebutton");
|
|
||||||
unpause_button.add(new Position(canvas.width / 2 - 150, canvas.height / 2 - 80));
|
|
||||||
unpause_button.add(new UIButton("Unpause", 320, 64, () => this.paused = false));
|
|
||||||
this.add_entity(unpause_button);
|
|
||||||
|
|
||||||
const about_button = new Entity("aboutbutton");
|
|
||||||
about_button.add(new Position(canvas.width / 2 - 150, canvas.height / 2 + 80));
|
|
||||||
about_button.add(new UIButton("About", 320, 64, () => open_about()));
|
|
||||||
this.add_entity(about_button);
|
|
||||||
|
|
||||||
// Logic systems
|
// Logic systems
|
||||||
this.add_system(new UIInteractionSystem());
|
this.add_system(new UIInteractionSystem(), "main_menu");
|
||||||
this.add_system(new InventorySystem());
|
this.add_system(new UIInteractionSystem(), "paused");
|
||||||
this.add_system(new PlayerControlsSystem(player));
|
this.add_system(new InventorySystem(), "game");
|
||||||
this.add_system(new MovementSystem());
|
this.add_system(new PlayerControlsSystem(), "game");
|
||||||
|
this.add_system(new MovementSystem(), "game");
|
||||||
|
|
||||||
// render systems
|
// render systems
|
||||||
this.add_system(new RenderSystem(this.ctx));
|
this.add_system(new RenderSystem(this.ctx), "game");
|
||||||
this.add_system(new DebugSystem());
|
this.add_system(new DebugSystem(), "*");
|
||||||
this.add_system(new TileEditorSystem());
|
this.add_system(new TileEditorSystem(), "game");
|
||||||
this.add_system(new UIRenderSystem());
|
this.add_system(new UIRenderSystem(), "main_menu");
|
||||||
|
this.add_system(new UIRenderSystem(), "paused");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Entity } from "$/common/ecs/mod.ts";
|
||||||
|
import { Position } from "$/common/components/position.ts";
|
||||||
|
import { ClientWorld } from "./client_world.ts";
|
||||||
|
import { Tilemap } from "./components/tilemap.ts";
|
||||||
|
import { AssetManager } from "./assets.ts";
|
||||||
|
import { create_player } from "./player.ts";
|
||||||
|
import { UIButton } from "./components/ui_components.ts";
|
||||||
|
import { open_about } from "./about.ts";
|
||||||
|
|
||||||
|
export function start_game(world: ClientWorld) {
|
||||||
|
world.state = "game";
|
||||||
|
world.clear_entities();
|
||||||
|
|
||||||
|
const tilemap = new Entity("backgroundtiles");
|
||||||
|
tilemap.add(
|
||||||
|
new Tilemap(
|
||||||
|
AssetManager.instance.get("bworld:roguelike"),
|
||||||
|
16,
|
||||||
|
[],
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
world.add_entity(tilemap);
|
||||||
|
|
||||||
|
create_player(world);
|
||||||
|
|
||||||
|
// UI !
|
||||||
|
const unpause_button = new Entity("unpausebutton");
|
||||||
|
unpause_button.add(new Position(world.canvas.width / 2 - 150, world.canvas.height / 2 - 80));
|
||||||
|
unpause_button.add(new UIButton("Unpause", 320, 64, () => world.state = "paused"));
|
||||||
|
world.add_entity(unpause_button);
|
||||||
|
|
||||||
|
const about_button = new Entity("aboutbutton");
|
||||||
|
about_button.add(new Position(world.canvas.width / 2 - 150, world.canvas.height / 2 + 80));
|
||||||
|
about_button.add(new UIButton("About", 320, 64, () => open_about()));
|
||||||
|
world.add_entity(about_button);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Entity } from "$/common/ecs/mod.ts";
|
||||||
|
import { Position } from "$/common/components/position.ts";
|
||||||
|
import { ClientWorld } from "./client_world.ts";
|
||||||
|
import { UIButton } from "./components/ui_components.ts";
|
||||||
|
import { open_about } from "./about.ts";
|
||||||
|
import { start_game } from "./game.ts";
|
||||||
|
|
||||||
|
export function create_main_menu(world: ClientWorld) {
|
||||||
|
const canvas = world.canvas;
|
||||||
|
|
||||||
|
const play_button = new Entity("play");
|
||||||
|
play_button.add(new Position(canvas.width / 2 - 150, canvas.height / 2 - 80));
|
||||||
|
play_button.add(new UIButton("Play", 320, 64, () => start_game(world)));
|
||||||
|
world.add_entity(play_button);
|
||||||
|
|
||||||
|
const about_button = new Entity("aboutbutton");
|
||||||
|
about_button.add(new Position(canvas.width / 2 - 150, canvas.height / 2 + 80));
|
||||||
|
about_button.add(new UIButton("About", 320, 64, () => open_about()));
|
||||||
|
world.add_entity(about_button);
|
||||||
|
}
|
||||||
@@ -9,10 +9,6 @@ import { Sprite } from "../components/sprite.ts";
|
|||||||
|
|
||||||
export class InventorySystem extends System {
|
export class InventorySystem extends System {
|
||||||
update(world: ClientWorld, _delta: number): void {
|
update(world: ClientWorld, _delta: number): void {
|
||||||
if (world.paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const entity of world.get_entities()) {
|
for (const entity of world.get_entities()) {
|
||||||
const player_inventory = entity.get(PlayerInventory);
|
const player_inventory = entity.get(PlayerInventory);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Entity, System } from "$/common/ecs/mod.ts";
|
import { System } from "$/common/ecs/mod.ts";
|
||||||
import { Velocity } from "$/common/components/velocity.ts";
|
import { Velocity } from "$/common/components/velocity.ts";
|
||||||
import { InputManager } from "../input_manager.ts";
|
import { InputManager } from "../input_manager.ts";
|
||||||
import { AnimatedSprite } from "../components/sprite.ts";
|
import { AnimatedSprite } from "../components/sprite.ts";
|
||||||
@@ -9,21 +9,15 @@ import { Camera } from "../components/camera.ts";
|
|||||||
import { Position } from "../../common/components/position.ts";
|
import { Position } from "../../common/components/position.ts";
|
||||||
|
|
||||||
export class PlayerControlsSystem extends System {
|
export class PlayerControlsSystem extends System {
|
||||||
player: Entity;
|
constructor() {
|
||||||
|
|
||||||
constructor(player: Entity) {
|
|
||||||
super();
|
super();
|
||||||
this.player = player;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update(world: ClientWorld, _delta: number): void {
|
update(world: ClientWorld, _delta: number): void {
|
||||||
if (world.paused) {
|
const [player] = world.get_tag("player")!;
|
||||||
return;
|
const velocity = player.get(Velocity)!;
|
||||||
}
|
const controls = player.get(PlayerControls)!;
|
||||||
|
const player_inventory = player.get(PlayerInventory)!;
|
||||||
const velocity = this.player.get(Velocity)!;
|
|
||||||
const controls = this.player.get(PlayerControls)!;
|
|
||||||
const player_inventory = this.player.get(PlayerInventory)!;
|
|
||||||
|
|
||||||
if (InputManager.is_key_down(controls.move_left)) {
|
if (InputManager.is_key_down(controls.move_left)) {
|
||||||
velocity.vx = -controls.move_speed;
|
velocity.vx = -controls.move_speed;
|
||||||
@@ -41,7 +35,7 @@ export class PlayerControlsSystem extends System {
|
|||||||
velocity.vy = 0;
|
velocity.vy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const animated_sprite = this.player.get(AnimatedSprite)!;
|
const animated_sprite = player.get(AnimatedSprite)!;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
InputManager.is_key_down(controls.move_up) || InputManager.is_key_down(controls.move_down) ||
|
InputManager.is_key_down(controls.move_up) || InputManager.is_key_down(controls.move_down) ||
|
||||||
@@ -59,7 +53,7 @@ export class PlayerControlsSystem extends System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (InputManager.is_key_pressed(controls.open_inventory)) {
|
if (InputManager.is_key_pressed(controls.open_inventory)) {
|
||||||
const inventory = this.player.get(PlayerInventory)!;
|
const inventory = player.get(PlayerInventory)!;
|
||||||
inventory.is_open = !inventory.is_open;
|
inventory.is_open = !inventory.is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +61,8 @@ export class PlayerControlsSystem extends System {
|
|||||||
world.debugging = !world.debugging;
|
world.debugging = !world.debugging;
|
||||||
}
|
}
|
||||||
|
|
||||||
const position = this.player.get(Position)!;
|
const position = player.get(Position)!;
|
||||||
const camera = this.player.get(Camera)!;
|
const camera = player.get(Camera)!;
|
||||||
|
|
||||||
camera.x = Math.round(position.x);
|
camera.x = Math.round(position.x);
|
||||||
camera.y = Math.round(position.y);
|
camera.y = Math.round(position.y);
|
||||||
|
|||||||
@@ -7,15 +7,6 @@ import { InputManager } from "$/client/input_manager.ts";
|
|||||||
|
|
||||||
export class UIInteractionSystem implements System {
|
export class UIInteractionSystem implements System {
|
||||||
update(world: ClientWorld, _delta: number) {
|
update(world: ClientWorld, _delta: number) {
|
||||||
// TODO: dont like
|
|
||||||
if (InputManager.is_key_pressed("Escape")) {
|
|
||||||
world.paused = !world.paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!world.paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mouse = InputManager.get_mouse_position();
|
const mouse = InputManager.get_mouse_position();
|
||||||
|
|
||||||
for (const entity of world.get_entities()) {
|
for (const entity of world.get_entities()) {
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ export class UIRenderSystem implements System {
|
|||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
update(world: ClientWorld, _delta: number) {
|
update(world: ClientWorld, _delta: number) {
|
||||||
if (!world.paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = world.ctx;
|
const ctx = world.ctx;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|||||||
+57
-11
@@ -2,33 +2,79 @@ import type { Entity } from "./entity.ts";
|
|||||||
import type { System } from "./system.ts";
|
import type { System } from "./system.ts";
|
||||||
|
|
||||||
export class World {
|
export class World {
|
||||||
entities = new Set<Entity>();
|
#entities = new Set<Entity>();
|
||||||
systems = new Set<System>();
|
#entities_for_deletion = new Set<Entity>();
|
||||||
tags = new Map<string, Entity[]>();
|
|
||||||
|
|
||||||
add_entity(entity: Entity) {
|
#systems = new Map<string, Set<System>>();
|
||||||
this.entities.add(entity);
|
#tags = new Map<string, Entity[]>();
|
||||||
|
#states = new Set<string>();
|
||||||
|
|
||||||
|
#state: string = "";
|
||||||
|
#new_state: string | undefined;
|
||||||
|
|
||||||
|
constructor(initial_state: string) {
|
||||||
|
this.#state = initial_state;
|
||||||
|
this.add_state("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
add_system(system: System) {
|
add_state(new_state: string) {
|
||||||
this.systems.add(system);
|
this.#states.add(new_state);
|
||||||
|
this.#systems.set(new_state, new Set());
|
||||||
|
}
|
||||||
|
|
||||||
|
add_entity(entity: Entity) {
|
||||||
|
this.#entities.add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_system(system: System, state: string) {
|
||||||
|
console.assert(this.#states.has(state));
|
||||||
|
this.#systems.get(state)!.add(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_tag(tag: string, entities: Entity[]) {
|
add_tag(tag: string, entities: Entity[]) {
|
||||||
this.tags.set(tag, entities);
|
this.#tags.set(tag, entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_tag(tag: string) {
|
get_tag(tag: string) {
|
||||||
return this.tags.get(tag);
|
return this.#tags.get(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(delta: number) {
|
update(delta: number) {
|
||||||
for (const system of this.systems) {
|
for (const system of this.#systems.get("*") ?? []) {
|
||||||
system.update(this, delta);
|
system.update(this, delta);
|
||||||
}
|
}
|
||||||
|
for (const system of this.#systems.get(this.#state) ?? []) {
|
||||||
|
system.update(this, delta);
|
||||||
|
}
|
||||||
|
// should be faster than Set.prototype.difference lol
|
||||||
|
for (const entity of this.#entities_for_deletion) {
|
||||||
|
this.#entities.delete(entity);
|
||||||
|
}
|
||||||
|
if (this.#new_state) {
|
||||||
|
this.#state = this.#new_state;
|
||||||
|
this.#new_state = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_entities() {
|
get_entities() {
|
||||||
return this.entities;
|
return this.#entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_entity(entity: Entity) {
|
||||||
|
this.#entities_for_deletion.add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_entities() {
|
||||||
|
for (const entity of this.#entities) {
|
||||||
|
this.#entities_for_deletion.add(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get state() {
|
||||||
|
return this.#state;
|
||||||
|
}
|
||||||
|
|
||||||
|
set state(new_state: string) {
|
||||||
|
this.#new_state = new_state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user