From 5218fab55aa87a1d7ac385cae8dd48de14762587 Mon Sep 17 00:00:00 2001 From: Paula Date: Sat, 7 Mar 2026 13:01:52 -0300 Subject: [PATCH] Basic gameplay? --- assets/sprites/textures/hoed_dirt.png | Bin 0 -> 177 bytes assets/sprites/textures/hoed_watered_dirt.png | Bin 0 -> 177 bytes client/client_world.ts | 5 ++ client/components/dimension.ts | 2 +- client/components/inventory.ts | 20 ++++- client/game.ts | 25 +----- client/main.ts | 4 + client/player.ts | 5 +- client/systems/dimension_logic.ts | 79 ++++++++++++++++++ client/tiles/dirt.ts | 78 +++++++++++++++++ client/tiles/grass.ts | 16 ++++ client/tiles/mod.ts | 3 + client/tiles/tree.ts | 17 ++++ common/constants.ts | 2 +- common/everything_registry.ts | 11 +++ 15 files changed, 239 insertions(+), 28 deletions(-) create mode 100644 assets/sprites/textures/hoed_dirt.png create mode 100644 assets/sprites/textures/hoed_watered_dirt.png create mode 100644 client/systems/dimension_logic.ts create mode 100644 client/tiles/dirt.ts create mode 100644 client/tiles/grass.ts create mode 100644 client/tiles/mod.ts create mode 100644 client/tiles/tree.ts diff --git a/assets/sprites/textures/hoed_dirt.png b/assets/sprites/textures/hoed_dirt.png new file mode 100644 index 0000000000000000000000000000000000000000..34ad403559e8c9f68a3b7d59bfb02ac775109193 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`6`n4RAr`&KcP`2Nn$O5}Z_ocD z3Q8x~(~S)b4*cA4WQN2ChLqMDKUjDhZg%h=;B^S^c_$jfws=Q_g!Ba^I2Y&82GDG46LrUw7A1u5LH#_(b@H&L|yc3OKTfCz|LVa=f!>>$w*C*yM z*fk_E=*`~Xs@lf*gNb*3V+Hd>35Ou71JA6Q8a*_!I=NhG7!I>8X=6UO#Ah0J$41$^ aN(`(^jQq}Itosaf1B0ilpUXO@geCwhXFlry literal 0 HcmV?d00001 diff --git a/client/client_world.ts b/client/client_world.ts index 1f89e74..68a1bdc 100644 --- a/client/client_world.ts +++ b/client/client_world.ts @@ -12,11 +12,15 @@ import { create_main_menu } from "./main_menu.ts"; import { ClickableSystem } from "./systems/clickable_system.ts"; import { start_game } from "./game.ts"; import { canvas, resize_canvas } from "./renderer.ts"; +import { DimensionLogicSystem } from "./systems/dimension_logic.ts"; +import { Dimension } from "./components/dimension.ts"; export class ClientWorld extends World { paused = false; debugging = false; + dimension!: Dimension; + constructor() { super("game"); @@ -43,6 +47,7 @@ export class ClientWorld extends World { this.add_system(new PlayerControlsSystem(), "game"); this.add_system(new MovementSystem(), "game"); this.add_system(new CropSystem(), "game"); + this.add_system(new DimensionLogicSystem(), "game"); // render systems this.add_system(new RenderSystem(), "game"); diff --git a/client/components/dimension.ts b/client/components/dimension.ts index f49af15..3e582af 100644 --- a/client/components/dimension.ts +++ b/client/components/dimension.ts @@ -2,7 +2,7 @@ import { Component } from "$/common/ecs/mod.ts"; import { AssetManager } from "../assets.ts"; import { Texture } from "../renderer.ts"; -interface Tile { +export interface Tile { x: number; y: number; id: string; diff --git a/client/components/inventory.ts b/client/components/inventory.ts index f906ea7..887ded5 100644 --- a/client/components/inventory.ts +++ b/client/components/inventory.ts @@ -25,6 +25,9 @@ export class ContainerSlot { } set_item(item_stack: ItemStack | undefined) { + if ((item_stack?.amount ?? 0) <= 0) { + item_stack = undefined; + } this.#item_stack = item_stack; } @@ -57,7 +60,18 @@ export class Container { } add_item(item_stack: ItemStack) { - // TODO: merge stacks + for (const slot of this.#slots.filter((slot) => slot.has_item())) { + const slot_item = slot.get_item()!; + if (slot_item.type_id === item_stack.type_id) { + const missing = slot_item.max_amount - slot_item.amount; + const adding = Math.min(missing, item_stack.amount); + slot_item.amount += adding; + item_stack.amount -= adding; + if (item_stack.amount === 0) { + return; + } + } + } for (const slot of this.#slots) { if (!slot.has_item()) { slot.set_item(item_stack); @@ -75,6 +89,10 @@ export class Container { get_slot(slot: number): ContainerSlot { return this.#slots[slot]; } + + set_item(slot: number, item: ItemStack) { + this.#slots[slot].set_item(item); + } } export interface ContainerLayout { diff --git a/client/game.ts b/client/game.ts index 71b829f..5cd3380 100644 --- a/client/game.ts +++ b/client/game.ts @@ -5,7 +5,6 @@ import { Dimension } from "./components/dimension.ts"; import { create_player } from "./player.ts"; import { UIButton } from "./components/ui_components.ts"; import { open_about } from "./about.ts"; -import { create_crop_entity, Crop } from "./components/crop.ts"; import { generate } from "./generation.ts"; import { canvas } from "./renderer.ts"; @@ -14,7 +13,8 @@ export function start_game(world: ClientWorld) { world.clear_entities(); const dimension = new Entity("dimension"); - dimension.add(new Dimension([])); + world.dimension = new Dimension([]); + dimension.add(world.dimension); world.add_entity(dimension); generate(dimension.get(Dimension)!, 100, 100); @@ -30,25 +30,4 @@ export function start_game(world: ClientWorld) { 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); - - world.add_entity(create_crop_entity( - 0, - 0, - new Crop("bworld:potato"), - )); - world.add_entity(create_crop_entity( - 32, - 0, - new Crop("bworld:carrot"), - )); - world.add_entity(create_crop_entity( - 0, - 32, - new Crop("bworld:pumpkin"), - )); - world.add_entity(create_crop_entity( - 32, - 32, - new Crop("bworld:tomato"), - )); } diff --git a/client/main.ts b/client/main.ts index ffec27d..badb75a 100644 --- a/client/main.ts +++ b/client/main.ts @@ -1,8 +1,12 @@ +import { EverythingRegistry } from "../common/everything_registry.ts"; import { AssetManager } from "./assets.ts"; import { ClientWorld } from "./client_world.ts"; import { InputManager } from "./input_manager.ts"; import { begin_drawing, end_drawing, init_window } from "./renderer.ts"; +EverythingRegistry.add_registry("tiles"); +await import("./tiles/mod.ts"); + export class ClientLoop { running = false; last_time = 0; diff --git a/client/player.ts b/client/player.ts index 8a5a45e..de4a407 100644 --- a/client/player.ts +++ b/client/player.ts @@ -34,11 +34,12 @@ export function create_player(world: ClientWorld) { // TODO: actual player ids player.add(new PlayerInventory(player.id)); player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:pickaxe", 1, 1)); - player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:sword", 1, 1)); - player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:axe", 1, 1)); player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:hoe", 1, 1)); player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:watering_can", 1, 1)); + player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:axe", 1, 1)); + player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:sword", 1, 1)); player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:bomb", 64)); + player.get(PlayerInventory)!.container.add_item(new ItemStack("bworld:tomato_seeds", 64)); player.add(new Camera(-100, -100)); world.add_entity(player); diff --git a/client/systems/dimension_logic.ts b/client/systems/dimension_logic.ts new file mode 100644 index 0000000..670a3b7 --- /dev/null +++ b/client/systems/dimension_logic.ts @@ -0,0 +1,79 @@ +import { System } from "$/common/ecs/mod.ts"; +import { ClientWorld } from "../client_world.ts"; +import { Dimension } from "../components/dimension.ts"; +import { Camera, screen_to_world } from "../components/camera.ts"; +import { InputManager } from "../input_manager.ts"; +import { canvas } from "../renderer.ts"; +import { TILE_SIZE } from "$/common/constants.ts"; +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; + +export class DimensionLogicSystem extends System { + update(world: ClientWorld, _delta: number): void { + const dimension_entity = world.get_entities().values().find((ent) => ent.get(Dimension)); + const dimension = dimension_entity!.get(Dimension)!; + + const [player] = world.get_tag("player")!; + const camera = player.get(Camera)!; + + const mouse = InputManager.get_mouse_position(); + + const world_mouse = screen_to_world( + mouse.x, + mouse.y, + camera, + canvas.width, + canvas.height, + ); + + const tile_x = Math.floor(world_mouse.x / TILE_SIZE); + const tile_y = Math.floor(world_mouse.y / TILE_SIZE); + + const tile = dimension.tiles.findLast((tile) => tile.x === tile_x && tile.y === tile_y); + + if (tile) { + const tile_info = EverythingRegistry.get("tiles", tile.id); + + if (!tile_info) { + return; + } + + if (tile_info.on_interact || tile_info.on_click) { + if (tile_info.on_interact && InputManager.is_mouse_pressed(2)) { + InputManager.consume_mouse(2); + tile_info.on_interact(world, tile); + } + if (tile_info.on_click && InputManager.is_mouse_pressed(0)) { + InputManager.consume_mouse(0); + tile_info.on_click(world, tile); + } + } + } + + /*for (const tile of dimension.tiles) { + const tile_info = EverythingRegistry.get("tiles", tile.id); + if (!tile_info) { + continue; + } + + if (tile_info.on_interact || tile_info.on_click) { + console.log(tile_info); + const hovered = point_inside_rec( + world_mouse.x, + world_mouse.y, + tile.x * TILE_SIZE, + tile.y * TILE_SIZE, + TILE_SIZE, + TILE_SIZE, + ); + if (tile_info.on_interact && hovered && InputManager.is_mouse_pressed(2)) { + InputManager.consume_mouse(2); + tile_info.on_interact(world, tile); + } + if (tile_info.on_click && hovered && InputManager.is_mouse_pressed(0)) { + InputManager.consume_mouse(0); + tile_info.on_click(world, tile); + } + } + }*/ + } +} diff --git a/client/tiles/dirt.ts b/client/tiles/dirt.ts new file mode 100644 index 0000000..5398203 --- /dev/null +++ b/client/tiles/dirt.ts @@ -0,0 +1,78 @@ +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; +import { PlayerInventory } from "../components/inventory.ts"; + +EverythingRegistry.register("tiles", "bworld:dirt", { + texture_id: "bworld:dirt", + has_collision: false, + + on_interact(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const maybe_item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (maybe_item && maybe_item.type_id === "bworld:hoe") { + tile.id = "bworld:hoed_dirt"; + } + }, +}); + +EverythingRegistry.register("tiles", "bworld:hoed_dirt", { + texture_id: "bworld:hoed_dirt", + has_collision: false, + + on_click(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (!item) { + return; + } + + if (item.type_id === "bworld:pickaxe") { + tile.id = "bworld:dirt"; + } + }, + on_interact(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (!item) { + return; + } + + if (item.type_id === "bworld:watering_can") { + tile.id = "bworld:hoed_watered_dirt"; + } + }, +}); + +EverythingRegistry.register("tiles", "bworld:hoed_watered_dirt", { + texture_id: "bworld:hoed_watered_dirt", + has_collision: false, + + on_click(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (!item) { + return; + } + + if (item.type_id === "bworld:pickaxe") { + tile.id = "bworld:dirt"; + } + }, + on_interact(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (!item) { + return; + } + + if (item.type_id === "bworld:tomato_seeds") { + world.dimension.tiles.push({ x: tile.x, y: tile.y, id: "bworld:tomato_seeds" }); + item.amount -= 1; + player_inventory.container.set_item(player_inventory.hotbar_selected, item); + } + }, +}); diff --git a/client/tiles/grass.ts b/client/tiles/grass.ts new file mode 100644 index 0000000..b23c876 --- /dev/null +++ b/client/tiles/grass.ts @@ -0,0 +1,16 @@ +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; +import { PlayerInventory } from "../components/inventory.ts"; + +EverythingRegistry.register("tiles", "bworld:grass", { + texture_id: "bworld:grass", + has_collision: false, + + on_interact(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const maybe_item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (maybe_item && maybe_item.type_id === "bworld:hoe") { + tile.id = "bworld:hoed_dirt"; + } + }, +}); diff --git a/client/tiles/mod.ts b/client/tiles/mod.ts new file mode 100644 index 0000000..5969e51 --- /dev/null +++ b/client/tiles/mod.ts @@ -0,0 +1,3 @@ +import "./grass.ts"; +import "./dirt.ts"; +import "./tree.ts"; diff --git a/client/tiles/tree.ts b/client/tiles/tree.ts new file mode 100644 index 0000000..116ed8f --- /dev/null +++ b/client/tiles/tree.ts @@ -0,0 +1,17 @@ +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; +import { ItemStack, PlayerInventory } from "../components/inventory.ts"; + +EverythingRegistry.register("tiles", "bworld:tree", { + texture_id: "bworld:tree", + has_collision: false, + + on_click(world, tile) { + const [player] = world.get_tag("player")!; + const player_inventory = player.get(PlayerInventory)!; + const maybe_item = player_inventory.container.get_item(player_inventory.hotbar_selected); + if (maybe_item && maybe_item.type_id === "bworld:axe") { + tile.id = "bworld:grass"; + player_inventory.container.add_item(new ItemStack("bworld:log", 7)); + } + }, +}); diff --git a/common/constants.ts b/common/constants.ts index ac7aadb..0c6d2f3 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -1,5 +1,5 @@ export const TEXTURE_SIZE = 16; -export const TILE_SIZE = 32; +export const TILE_SIZE = 48; export const SLOT_SIZE = 18 * 3; diff --git a/common/everything_registry.ts b/common/everything_registry.ts index e282716..ae4e89a 100644 --- a/common/everything_registry.ts +++ b/common/everything_registry.ts @@ -1,3 +1,6 @@ +import { ClientWorld } from "../client/client_world.ts"; +import { Tile } from "../client/components/dimension.ts"; + export class EverythingRegistry { static #registries = new Map>(); @@ -13,3 +16,11 @@ export class EverythingRegistry { return this.#registries.get(registry_name)?.get(key) as T; } } + +export interface TileRegistry { + texture_id: string; + has_collision: boolean; + + on_click?(world: ClientWorld, tile: Tile): void; + on_interact?(world: ClientWorld, tile: Tile): void; +}