diff --git a/assets/ASSETS.md b/assets/ASSETS.md index 4d06527..fabd085 100644 --- a/assets/ASSETS.md +++ b/assets/ASSETS.md @@ -31,8 +31,6 @@ license: `free to use with attribution` https://butterymilk.itch.io/tiny-wonder-farm-asset-pack (https://web.archive.org/web/20260204234306/https://butterymilk.itch.io/tiny-wonder-farm-asset-pack) -file: assets/sprites/player.png - license: ``` @@ -50,3 +48,33 @@ the sprites and add something new! You can't resell the sprites, even if changes were made. You cannot use it in any projects related to NFT." ``` + +# Farmer's delight + +https://github.com/vectorwing/FarmersDelight + +License: + +``` +MIT License + +Copyright (c) 2020 vectorwing + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/assets/sprites/textures/arrow.png b/assets/sprites/textures/arrow.png new file mode 100644 index 0000000..4daf6d1 Binary files /dev/null and b/assets/sprites/textures/arrow.png differ diff --git a/assets/sprites/textures/axe.png b/assets/sprites/textures/axe.png new file mode 100644 index 0000000..cd998d7 Binary files /dev/null and b/assets/sprites/textures/axe.png differ diff --git a/assets/sprites/textures/bomb.png b/assets/sprites/textures/bomb.png new file mode 100644 index 0000000..8155baf Binary files /dev/null and b/assets/sprites/textures/bomb.png differ diff --git a/assets/sprites/textures/bow.png b/assets/sprites/textures/bow.png new file mode 100644 index 0000000..2d9e559 Binary files /dev/null and b/assets/sprites/textures/bow.png differ diff --git a/assets/sprites/textures/cabbage_seeds.png b/assets/sprites/textures/cabbage_seeds.png new file mode 100644 index 0000000..692218a Binary files /dev/null and b/assets/sprites/textures/cabbage_seeds.png differ diff --git a/assets/sprites/textures/carrot.png b/assets/sprites/textures/carrot.png new file mode 100644 index 0000000..fbfe2cf Binary files /dev/null and b/assets/sprites/textures/carrot.png differ diff --git a/assets/sprites/textures/carrot_seeds.png b/assets/sprites/textures/carrot_seeds.png new file mode 100644 index 0000000..b256f17 Binary files /dev/null and b/assets/sprites/textures/carrot_seeds.png differ diff --git a/assets/sprites/textures/carrot_stage_1.png b/assets/sprites/textures/carrot_stage_1.png new file mode 100644 index 0000000..27a501e Binary files /dev/null and b/assets/sprites/textures/carrot_stage_1.png differ diff --git a/assets/sprites/textures/carrot_stage_2.png b/assets/sprites/textures/carrot_stage_2.png new file mode 100644 index 0000000..f8f0bb0 Binary files /dev/null and b/assets/sprites/textures/carrot_stage_2.png differ diff --git a/assets/sprites/textures/carrot_stage_3.png b/assets/sprites/textures/carrot_stage_3.png new file mode 100644 index 0000000..02740e5 Binary files /dev/null and b/assets/sprites/textures/carrot_stage_3.png differ diff --git a/assets/sprites/textures/carrot_stage_4.png b/assets/sprites/textures/carrot_stage_4.png new file mode 100644 index 0000000..f2ac67e Binary files /dev/null and b/assets/sprites/textures/carrot_stage_4.png differ diff --git a/assets/sprites/textures/empty_bucket.png b/assets/sprites/textures/empty_bucket.png new file mode 100644 index 0000000..5176ea7 Binary files /dev/null and b/assets/sprites/textures/empty_bucket.png differ diff --git a/assets/sprites/textures/hoe.png b/assets/sprites/textures/hoe.png new file mode 100644 index 0000000..29db045 Binary files /dev/null and b/assets/sprites/textures/hoe.png differ diff --git a/assets/sprites/textures/key.png b/assets/sprites/textures/key.png new file mode 100644 index 0000000..fc7854c Binary files /dev/null and b/assets/sprites/textures/key.png differ diff --git a/assets/sprites/textures/knife.png b/assets/sprites/textures/knife.png new file mode 100644 index 0000000..b6e1a26 Binary files /dev/null and b/assets/sprites/textures/knife.png differ diff --git a/assets/sprites/textures/log.png b/assets/sprites/textures/log.png new file mode 100644 index 0000000..29dc3e6 Binary files /dev/null and b/assets/sprites/textures/log.png differ diff --git a/assets/sprites/textures/onion.png b/assets/sprites/textures/onion.png new file mode 100644 index 0000000..6bb444d Binary files /dev/null and b/assets/sprites/textures/onion.png differ diff --git a/assets/sprites/textures/pickaxe.png b/assets/sprites/textures/pickaxe.png new file mode 100644 index 0000000..587c31d Binary files /dev/null and b/assets/sprites/textures/pickaxe.png differ diff --git a/assets/sprites/textures/pitchfork.png b/assets/sprites/textures/pitchfork.png new file mode 100644 index 0000000..6f46308 Binary files /dev/null and b/assets/sprites/textures/pitchfork.png differ diff --git a/assets/sprites/textures/potato.png b/assets/sprites/textures/potato.png new file mode 100644 index 0000000..ad88136 Binary files /dev/null and b/assets/sprites/textures/potato.png differ diff --git a/assets/sprites/textures/potato_seeds.png b/assets/sprites/textures/potato_seeds.png new file mode 100644 index 0000000..ab36283 Binary files /dev/null and b/assets/sprites/textures/potato_seeds.png differ diff --git a/assets/sprites/textures/potato_stage_1.png b/assets/sprites/textures/potato_stage_1.png new file mode 100644 index 0000000..f179596 Binary files /dev/null and b/assets/sprites/textures/potato_stage_1.png differ diff --git a/assets/sprites/textures/potato_stage_2.png b/assets/sprites/textures/potato_stage_2.png new file mode 100644 index 0000000..b18bc79 Binary files /dev/null and b/assets/sprites/textures/potato_stage_2.png differ diff --git a/assets/sprites/textures/potato_stage_3.png b/assets/sprites/textures/potato_stage_3.png new file mode 100644 index 0000000..8784924 Binary files /dev/null and b/assets/sprites/textures/potato_stage_3.png differ diff --git a/assets/sprites/textures/potato_stage_4.png b/assets/sprites/textures/potato_stage_4.png new file mode 100644 index 0000000..b5dae97 Binary files /dev/null and b/assets/sprites/textures/potato_stage_4.png differ diff --git a/assets/sprites/textures/pumpkin.png b/assets/sprites/textures/pumpkin.png new file mode 100644 index 0000000..fee4a1b Binary files /dev/null and b/assets/sprites/textures/pumpkin.png differ diff --git a/assets/sprites/textures/pumpkin_seeds.png b/assets/sprites/textures/pumpkin_seeds.png new file mode 100644 index 0000000..a5da0e9 Binary files /dev/null and b/assets/sprites/textures/pumpkin_seeds.png differ diff --git a/assets/sprites/textures/pumpkin_stage_1.png b/assets/sprites/textures/pumpkin_stage_1.png new file mode 100644 index 0000000..f4f3e7e Binary files /dev/null and b/assets/sprites/textures/pumpkin_stage_1.png differ diff --git a/assets/sprites/textures/pumpkin_stage_2.png b/assets/sprites/textures/pumpkin_stage_2.png new file mode 100644 index 0000000..8cf03d1 Binary files /dev/null and b/assets/sprites/textures/pumpkin_stage_2.png differ diff --git a/assets/sprites/textures/pumpkin_stage_3.png b/assets/sprites/textures/pumpkin_stage_3.png new file mode 100644 index 0000000..fc60a49 Binary files /dev/null and b/assets/sprites/textures/pumpkin_stage_3.png differ diff --git a/assets/sprites/textures/pumpkin_stage_4.png b/assets/sprites/textures/pumpkin_stage_4.png new file mode 100644 index 0000000..a035ef7 Binary files /dev/null and b/assets/sprites/textures/pumpkin_stage_4.png differ diff --git a/assets/sprites/textures/shovel.png b/assets/sprites/textures/shovel.png new file mode 100644 index 0000000..a2ef784 Binary files /dev/null and b/assets/sprites/textures/shovel.png differ diff --git a/assets/sprites/textures/straw.png b/assets/sprites/textures/straw.png new file mode 100644 index 0000000..2cd2b42 Binary files /dev/null and b/assets/sprites/textures/straw.png differ diff --git a/assets/sprites/textures/sword.png b/assets/sprites/textures/sword.png new file mode 100644 index 0000000..0f227cc Binary files /dev/null and b/assets/sprites/textures/sword.png differ diff --git a/assets/sprites/textures/tomato.png b/assets/sprites/textures/tomato.png new file mode 100644 index 0000000..9f080ea Binary files /dev/null and b/assets/sprites/textures/tomato.png differ diff --git a/assets/sprites/textures/tomato_seeds.png b/assets/sprites/textures/tomato_seeds.png new file mode 100644 index 0000000..33c7e3c Binary files /dev/null and b/assets/sprites/textures/tomato_seeds.png differ diff --git a/assets/sprites/textures/tomato_stage_1.png b/assets/sprites/textures/tomato_stage_1.png new file mode 100644 index 0000000..cf364c8 Binary files /dev/null and b/assets/sprites/textures/tomato_stage_1.png differ diff --git a/assets/sprites/textures/tomato_stage_2.png b/assets/sprites/textures/tomato_stage_2.png new file mode 100644 index 0000000..eb613fb Binary files /dev/null and b/assets/sprites/textures/tomato_stage_2.png differ diff --git a/assets/sprites/textures/tomato_stage_3.png b/assets/sprites/textures/tomato_stage_3.png new file mode 100644 index 0000000..d9ee030 Binary files /dev/null and b/assets/sprites/textures/tomato_stage_3.png differ diff --git a/assets/sprites/textures/tomato_stage_4.png b/assets/sprites/textures/tomato_stage_4.png new file mode 100644 index 0000000..40cf8df Binary files /dev/null and b/assets/sprites/textures/tomato_stage_4.png differ diff --git a/assets/sprites/textures/water_bucket.png b/assets/sprites/textures/water_bucket.png new file mode 100644 index 0000000..ea9d33f Binary files /dev/null and b/assets/sprites/textures/water_bucket.png differ diff --git a/assets/sprites/textures/watering_can.png b/assets/sprites/textures/watering_can.png new file mode 100644 index 0000000..ae58c96 Binary files /dev/null and b/assets/sprites/textures/watering_can.png differ diff --git a/assets/sprites/textures/wheat.png b/assets/sprites/textures/wheat.png new file mode 100644 index 0000000..6c707e7 Binary files /dev/null and b/assets/sprites/textures/wheat.png differ diff --git a/assets/sprites/tiny_town.png b/assets/sprites/tiny_town.png deleted file mode 100644 index 1655d1d..0000000 Binary files a/assets/sprites/tiny_town.png and /dev/null differ diff --git a/build.ts b/build.ts index 16c5167..1b80b04 100644 --- a/build.ts +++ b/build.ts @@ -1,4 +1,5 @@ import { copy } from "@std/fs"; +import { createCanvas, loadImage } from "@gfx/canvas-wasm"; const BUILD_FOLDER = "build"; @@ -7,8 +8,82 @@ function clear_folder() { Deno.mkdir(BUILD_FOLDER); } -function build_assets() { - copy("assets", `${BUILD_FOLDER}/assets`); +function build_fonts() { + copy(`assets/fonts`, `${BUILD_FOLDER}/assets/fonts`); +} + +function next_power_of_two(value: number): number { + return Math.pow(2, Math.ceil(Math.log2(value))); +} + +const SPRITE_SIZE = 16; + +function calculate_atlas_size(count: number) { + const raw_sprites_per_side = Math.ceil(Math.sqrt(count)); + const raw_size = raw_sprites_per_side * SPRITE_SIZE; + const size = next_power_of_two(raw_size); + + return { + sprites_per_side: size / SPRITE_SIZE, + size, + }; +} + +async function build_atlas_from_folder(folder: string) { + let sprite_count = 0; + for (const entry of Deno.readDirSync(folder)) { + console.assert(entry.isFile && entry.name.endsWith(".png")); + sprite_count += 1; + } + + const atlas = calculate_atlas_size(sprite_count); + + const canvas = createCanvas(atlas.size, atlas.size); + const ctx = canvas.getContext("2d"); + + const atlas_info: Record = {}; + + // purple and black missing texture at x:0 y:0 wow ! + ctx.fillStyle = "magenta"; + ctx.fillRect(0, 0, 8, 8); + ctx.fillRect(8, 8, 8, 8); + ctx.fillStyle = "black"; + ctx.fillRect(8, 0, 8, 8); + ctx.fillRect(0, 8, 8, 8); + + let index = 1; + for (const entry of Deno.readDirSync(folder)) { + const sprite = await loadImage(`${folder}/${entry.name}`); + const row = Math.floor(index / atlas.sprites_per_side); + const column = index % atlas.sprites_per_side; + ctx.drawImage(sprite, column * SPRITE_SIZE, row * SPRITE_SIZE); + index += 1; + + const id = `bworld:${entry.name.replace(".png", "")}`; + atlas_info[id] = { x: column, y: row }; + } + + Deno.writeFileSync(`${BUILD_FOLDER}/${folder}.png`, canvas.toBuffer()); + Deno.writeTextFileSync(`${BUILD_FOLDER}/${folder}.json`, JSON.stringify(atlas_info)); +} + +async function build_sprites() { + for (const entry of Deno.readDirSync("assets/sprites")) { + if (entry.name.endsWith(".png")) { + copy(`assets/sprites/${entry.name}`, `${BUILD_FOLDER}/assets/sprites/${entry.name}`); + } else if (entry.isDirectory) { + await build_atlas_from_folder(`assets/sprites/${entry.name}`); + } + } +} + +async function build_assets() { + Deno.mkdir(`${BUILD_FOLDER}/assets`, { recursive: true }); + copy("assets/ASSETS.md", `${BUILD_FOLDER}/assets/ASSETS.md`); + + build_fonts(); + Deno.mkdir(`${BUILD_FOLDER}/assets/sprites`, { recursive: true }); + await build_sprites(); } async function build_client() { @@ -23,7 +98,7 @@ async function build_client() { async function build() { const now = performance.now(); clear_folder(); - build_assets(); + await build_assets(); await build_client(); console.log(`Built in ${(performance.now() - now).toFixed(2)}ms`); } diff --git a/client/assets.ts b/client/assets.ts index 40cb99b..9f3304e 100644 --- a/client/assets.ts +++ b/client/assets.ts @@ -1,4 +1,4 @@ -type Asset = HTMLImageElement | HTMLAudioElement | string; +type Asset = HTMLImageElement | HTMLAudioElement | string | Record; export class AssetManager { static instance = new AssetManager(); @@ -47,6 +47,12 @@ export class AssetManager { this.assets[key] = await resp.text(); }; this.loading_promises.push(promise()); + } else if (src.endsWith(".json")) { + const promise = async () => { + const resp = await fetch(src); + this.assets[key] = await resp.json(); + }; + this.loading_promises.push(promise()); } } diff --git a/client/main.ts b/client/main.ts index 6f005a4..8f7f361 100644 --- a/client/main.ts +++ b/client/main.ts @@ -62,9 +62,12 @@ if (!canvas) { InputManager.initialize(canvas); AssetManager.instance.load("bworld:assets_text", "/assets/ASSETS.md"); + +AssetManager.instance.load("bworld:textures", "/assets/sprites/textures.png"); +AssetManager.instance.load("bworld:textures_info", "/assets/sprites/textures.json"); + AssetManager.instance.load("bworld:player", "/assets/sprites/player.png"); AssetManager.instance.load("bworld:roguelike", "/assets/sprites/roguelike.png"); -AssetManager.instance.load("bworld:tiny_town", "/assets/sprites/tiny_town.png"); AssetManager.instance.load("bworld:ui", "/assets/sprites/ui.png"); await AssetManager.instance.load_all(); diff --git a/client/player.ts b/client/player.ts index 139bf07..3d5fe9c 100644 --- a/client/player.ts +++ b/client/player.ts @@ -32,7 +32,10 @@ export function create_player() { // 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:bomb", 5)); + 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:bomb", 64)); player.add(new Camera(-100, -100)); return player; diff --git a/client/systems/rendering/render_utils.ts b/client/systems/rendering/render_utils.ts index d297885..84ca9f8 100644 --- a/client/systems/rendering/render_utils.ts +++ b/client/systems/rendering/render_utils.ts @@ -107,7 +107,7 @@ export function draw_nine_slice( export function draw_item(ctx: CanvasRenderingContext2D, item: ItemStack, x: number, y: number) { const sprite_region = get_sprite_region(item.type_id); ctx.drawImage( - AssetManager.instance.get("bworld:tiny_town"), + AssetManager.instance.get("bworld:textures"), sprite_region.x * 16, sprite_region.y * 16, 16, diff --git a/common/constants.ts b/common/constants.ts index 82ed2e0..d0c8846 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -4,8 +4,3 @@ export interface SpriteRegion { x: number; y: number; } - -export const ITEM_SPRITES: Record = { - "bworld:pickaxe": { x: 7, y: 9 }, - "bworld:bomb": { x: 9, y: 8 }, -}; diff --git a/common/utils.ts b/common/utils.ts index e34f0c7..240b62c 100644 --- a/common/utils.ts +++ b/common/utils.ts @@ -1,4 +1,5 @@ -import { ITEM_SPRITES, SpriteRegion } from "./constants.ts"; +import { AssetManager } from "../client/assets.ts"; +import { SpriteRegion } from "./constants.ts"; export function point_inside_rec( point_x: number, @@ -14,6 +15,9 @@ export function point_inside_rec( point_y < rec_y + rec_h; } +type TexturesInfo = Record; + export function get_sprite_region(id: string): SpriteRegion { - return ITEM_SPRITES[id] ?? { x: 0, y: 0 }; + const textures_info = AssetManager.instance.get("bworld:textures_info"); + return textures_info?.[id] ?? { x: 0, y: 0 }; } diff --git a/deno.json b/deno.json index 9e2729c..55f8078 100644 --- a/deno.json +++ b/deno.json @@ -15,6 +15,7 @@ }, "imports": { "$/": "./", + "@gfx/canvas-wasm": "jsr:@gfx/canvas-wasm@^0.4.2", "@std/fs": "jsr:@std/fs@^1.0.23", "marked": "npm:marked@^17.0.3" } diff --git a/deno.lock b/deno.lock index 4e69697..f10b053 100644 --- a/deno.lock +++ b/deno.lock @@ -1,12 +1,23 @@ { "version": "5", "specifiers": { + "jsr:@gfx/canvas-wasm@~0.4.2": "0.4.2", + "jsr:@std/encoding@1.0.5": "1.0.5", "jsr:@std/fs@^1.0.23": "1.0.23", "jsr:@std/internal@^1.0.12": "1.0.12", "jsr:@std/path@^1.1.4": "1.1.4", "npm:marked@^17.0.3": "17.0.3" }, "jsr": { + "@gfx/canvas-wasm@0.4.2": { + "integrity": "d653be3bd12cb2fa9bbe5d1b1f041a81b91d80b68502761204aaf60e4592532a", + "dependencies": [ + "jsr:@std/encoding" + ] + }, + "@std/encoding@1.0.5": { + "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04" + }, "@std/fs@1.0.23": { "integrity": "3ecbae4ce4fee03b180fa710caff36bb5adb66631c46a6460aaad49515565a37", "dependencies": [ @@ -32,6 +43,7 @@ }, "workspace": { "dependencies": [ + "jsr:@gfx/canvas-wasm@~0.4.2", "jsr:@std/fs@^1.0.23", "npm:marked@^17.0.3" ]