From 37a91de848d873fbb8e264a9f8dcf6f3f4c13c0d Mon Sep 17 00:00:00 2001 From: Maciej Samborski Date: Sun, 5 Jan 2025 23:52:15 +0100 Subject: [PATCH] Added Sprite, Spritesheet and made batching actually do shit --- src/js/assets.js | 24 ++---- src/js/assets.ts | 32 +++----- src/js/draw.js | 155 +++++++++++++++++-------------------- src/js/draw.ts | 189 +++++++++++++++++++++------------------------ src/js/graphics.js | 59 +++++++++++--- src/js/graphics.ts | 88 ++++++++++++++++----- src/js/script.js | 33 ++++---- src/js/script.ts | 36 ++++----- src/js/world.js | 43 ++++++----- src/js/world.ts | 57 ++++++++------ 10 files changed, 373 insertions(+), 343 deletions(-) diff --git a/src/js/assets.js b/src/js/assets.js index 04ebab7..2eea889 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -1,36 +1,26 @@ -import { Texture } from "./graphics.js"; +import { Vec2 } from "./common.js"; +import { Texture, Spritesheet } from "./graphics.js"; export const Colors = { Red: [1, 0, 0, 1], Green: [0, 1, 0, 1], Blue: [0, 0, 1, 1], Brown: [0.341, 0.337, 0.204, 1], }; -export function AssetToTileFill(name) { - let asset = assets.get(name); - return { - left: asset, - top: asset, - right: asset, - }; -} export class Assets { assets = new Map(); - loaded = false; push(name, asset) { if (this.assets.get(name) !== undefined) throw new Error("Asset name occupied!"); this.assets.set(name, asset); } get(name) { - if (!this.loaded) - throw new Error("Tried to assess assets without loading them!"); - return this.assets.get(name); + let a = this.assets.get(name); + if (a === undefined) + throw new Error("Couldn't find asset: " + name); + return a; } async load(gfx) { - assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); - assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png")); - assets.push("log", await Texture.load(gfx, "../../assets/log.png")); - this.loaded = true; + assets.push("sprites", new Spritesheet(await Texture.load(gfx, "../../assets/sprites.png"), new Vec2(16, 16))); } } export const assets = new Assets(); diff --git a/src/js/assets.ts b/src/js/assets.ts index f344dbb..168607c 100644 --- a/src/js/assets.ts +++ b/src/js/assets.ts @@ -1,5 +1,5 @@ -import {Graphics, Texture} from "./graphics.js"; -import {TileFill} from "./world.js"; +import {Vec2} from "./common.js"; +import {Graphics, Texture, Spritesheet} from "./graphics.js"; export type Color = [number, number, number, number] @@ -10,21 +10,10 @@ export const Colors = { Brown : [0.341, 0.337, 0.204, 1] as Color, } -export type Asset = Texture; - -export function AssetToTileFill(name: string): TileFill { - let asset = assets.get(name); - - return { - left: asset, - top: asset, - right: asset, - }; -} +export type Asset = Texture | Spritesheet; export class Assets { assets: Map = new Map(); - loaded: boolean = false; push(name: string, asset: Asset) { if (this.assets.get(name) !== undefined) @@ -34,18 +23,15 @@ export class Assets { } get(name: string): Asset { - if (!this.loaded) - throw new Error("Tried to assess assets without loading them!"); - - return this.assets.get(name)!; + let a = this.assets.get(name); + if (a === undefined) + throw new Error("Couldn't find asset: " + name); + + return a; } async load(gfx: Graphics) { - assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); - assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png")); - assets.push("log", await Texture.load(gfx, "../../assets/log.png")); - - this.loaded = true; + assets.push("sprites", new Spritesheet(await Texture.load(gfx, "../../assets/sprites.png"), new Vec2(16, 16))); } } diff --git a/src/js/draw.js b/src/js/draw.js index d17d747..f8899fb 100644 --- a/src/js/draw.js +++ b/src/js/draw.js @@ -1,30 +1,20 @@ import { Vec3 } from "./common.js"; -import { Texture, DrawTag } from "./graphics.js"; +import { DrawTag, Sprite } from "./graphics.js"; import { TileEdge } from "./world.js"; -// TODO: Don't assume tile size is same in all directions -function cull(point, screen, tileSize) { - if (point.x + tileSize < screen.x) - return true; - if (point.x + tileSize > screen.x + screen.z) - return true; - if (point.y - tileSize < screen.y) - return true; - if (point.y + tileSize > screen.y + screen.w) - return true; - return false; -} +import * as Assets from "./assets.js"; // Attrib format // position color uv -// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 +// (3) (4) (3) => 3 + 4 + 3 = 10 <=> vertexSize == 10 export class Rectangle { - fill; - attribs = ["a_position", "a_color", "a_tex_position"]; + attribs = ["a_position", "a_color", "a_tex"]; tags = []; data = []; - stride = 0; - vertexStride = 0; - constructor(fill, tags, attribs) { - this.fill = fill; + vertexSize = 10; + sprites = Assets.assets.get("sprites"); + constructor(tags, sprites, attribs) { + if (sprites !== undefined) { + this.sprites = sprites; + } if (attribs !== undefined) { this.attribs = attribs; } @@ -32,61 +22,59 @@ export class Rectangle { this.tags = tags; } } - overrideDraw(draw) { - this.draw = draw; - } - draw(gfx, corners) { - if (this.fill instanceof Texture) { - this.data = [ - corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0, - corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0, - corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1, - corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1, - corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0, - corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1, - ]; - } - else { - this.data = [ - corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - ]; - } - this.vertexStride = 9; - this.stride = this.vertexStride * 4; - gfx.toRender.push({ ...this }); - } - drawExts(gfx, position, exts) { - if (this.fill instanceof Texture) { - this.data = [ - position.x, position.y, position.z, 0, 0, 0, 0, 0, 0, - position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0, - position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1, - position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1, - position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0, - position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1, - ]; - } - else { - this.data = [ - position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - ]; - } - this.vertexStride = 9; - this.stride = this.vertexStride * 4; + commit(gfx) { gfx.toRender.push(this); } + draw(corners, fill) { + if (fill instanceof Sprite) { + let uvs = Assets.assets.get("sprites").getUVs(fill.id); + this.data.push([ + corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1, + corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1, + corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + ]); + } + else { + let color = fill; + this.data.push([ + corners[0].x, corners[0].y, corners[0].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[2].x, corners[2].y, corners[2].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0, + ]); + } + } + drawExts(position, exts, fill) { + if (fill instanceof Sprite) { + let uvs = Assets.assets.get("sprites").getUVs(fill.id); + this.data.push([ + position.x, position.y, position.z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1, + position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1, + position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + ]); + } + else { + let color = fill; + this.data.push([ + position.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x + exts.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + ]); + } + } } -export function drawIsometricCube(gfx, position, exts, color, edge) { +export function drawIsometricCube(position, exts, r, fill, edge) { let points = [ // Left Top position, @@ -101,41 +89,39 @@ export function drawIsometricCube(gfx, position, exts, color, edge) { new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), ]; - let r = new Rectangle(color.top, [ - DrawTag.ISO, - ]); // Top - r.draw(gfx, [ + r.draw([ points[0], points[1], points[3], points[2], - ]); + ], fill.top); // Right Edge if (edge == TileEdge.Right || edge == TileEdge.Both) { - r.fill = color.right; - r.draw(gfx, [ + r.draw([ points[3], points[2], points[4], points[5], - ]); + ], fill.right); } // Left Edge if (edge == TileEdge.Left || edge == TileEdge.Both) { - r.fill = color.left; - r.draw(gfx, [ + r.draw([ points[0], points[2], points[4], points[6], - ]); + ], fill.left); } } export function drawIsometricGrid(gfx, grid) { let position = { ...grid.position }; let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let tileCoord = new Vec3(0, 0, 0); + let rect = new Rectangle([ + DrawTag.ISO, + ]); // TODO: Optimize this // 1. Grid based occlusion culling // 2. frustum culling @@ -152,7 +138,7 @@ export function drawIsometricGrid(gfx, grid) { position.x += grid.tileSize; continue; } - drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); + drawIsometricCube(new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, rect, tile.fill, tile.edge); position.x += grid.tileSize; } position.y -= grid.tileSize; @@ -160,4 +146,5 @@ export function drawIsometricGrid(gfx, grid) { } position.y = grid.position.y; } + rect.commit(gfx); } diff --git a/src/js/draw.ts b/src/js/draw.ts index 50e2aeb..7d45d0f 100644 --- a/src/js/draw.ts +++ b/src/js/draw.ts @@ -1,40 +1,25 @@ -import { Vec3, Vec2, Vec4 } from "./common.js" -import { Graphics, Texture, Drawable, DrawTag } from "./graphics.js"; -import { TileEdge, TileFill, Grid } from "./world.js"; +import { Vec3, Vec2 } from "./common.js" +import { Graphics, Drawable, DrawTag, Sprite, Spritesheet } from "./graphics.js"; +import { TileEdge, TileFill, TileFillament, Grid } from "./world.js"; import * as Assets from "./assets.js"; -// TODO: Don't assume tile size is same in all directions -function cull(point: Vec3, screen: Vec4, tileSize: number): boolean { - if (point.x + tileSize < screen.x) - return true; - - if (point.x + tileSize > screen.x + screen.z) - return true; - - if (point.y - tileSize < screen.y) - return true; - - if (point.y + tileSize > screen.y + screen.w) - return true; - - return false; -} - // Attrib format // position color uv -// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 +// (3) (4) (3) => 3 + 4 + 3 = 10 <=> vertexSize == 10 export class Rectangle implements Drawable { - fill: Texture | Assets.Color; - attribs: string[] = ["a_position", "a_color", "a_tex_position"]; + attribs: string[] = ["a_position", "a_color", "a_tex"]; tags: Array = []; - data: number[] = []; - stride: number = 0; - vertexStride: number = 0; + data: number[][] = []; + vertexSize: number = 10; - constructor(fill: Texture | Assets.Color, tags?: Array, attribs?: string[]) { - this.fill = fill; + sprites: Spritesheet = Assets.assets.get("sprites") as Spritesheet; + + constructor(tags?: Array, sprites?: Spritesheet, attribs?: string[]) { + if (sprites !== undefined) { + this.sprites = sprites; + } if (attribs !== undefined) { this.attribs = attribs; @@ -45,68 +30,68 @@ export class Rectangle implements Drawable { } } - overrideDraw(draw: (...args: any[]) => void) { - this.draw = draw; - } - - draw(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3]) { - if (this.fill instanceof Texture) { - this.data = [ - corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0, - corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0, - corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1, - - corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1, - corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0, - corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1, - ] - } else { - this.data = [ - corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - - corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - ] - } - - this.vertexStride = 9; - this.stride = this.vertexStride * 4 - gfx.toRender.push({...this}); - } - - drawExts(gfx: Graphics, position: Vec3, exts: Vec2) { - if (this.fill instanceof Texture) { - this.data = [ - position.x, position.y, position.z, 0, 0, 0, 0, 0, 0, - position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0, - position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1, - - position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1, - position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0, - position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1, - ] - } else { - this.data = [ - position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - - position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0, - ] - } - - this.vertexStride = 9; - this.stride = this.vertexStride * 4 + commit(gfx: Graphics) { gfx.toRender.push(this); } + + draw(corners: [Vec3, Vec3, Vec3, Vec3], fill: TileFillament) { + if (fill instanceof Sprite) { + let uvs = (Assets.assets.get("sprites") as Spritesheet).getUVs(fill.id); + + this.data.push([ + corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1, + corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + + corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1, + corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + ]); + } else { + let color = fill; + + this.data.push([ + corners[0].x, corners[0].y, corners[0].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0, + + corners[2].x, corners[2].y, corners[2].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0, + corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0, + ]); + } + } + + drawExts(position: Vec3, exts: Vec2, fill: TileFillament) { + if (fill instanceof Sprite) { + let uvs = (Assets.assets.get("sprites") as Spritesheet).getUVs(fill.id); + + this.data.push([ + position.x, position.y, position.z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1, + position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + + position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1, + position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1, + position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1, + ]); + } else { + let color = fill; + + this.data.push([ + position.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + + position.x + exts.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0, + ]); + } + } } -export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) { +export function drawIsometricCube(position: Vec3, exts: Vec3, r: Rectangle, fill: TileFill, edge: TileEdge) { let points = [ // Left Top position, @@ -122,49 +107,40 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), ]; - let r = new Rectangle(color.top, [ - DrawTag.ISO, - ]); - // Top r.draw( - gfx, [ points[0], points[1], points[3], points[2], ], + fill.top ); // Right Edge - if (edge == TileEdge.Right || edge == TileEdge.Both) { - r.fill = color.right; - r.draw( - gfx, [ points[3], points[2], points[4], points[5], - ] + ], + fill.right ); } // Left Edge if (edge == TileEdge.Left || edge == TileEdge.Both) { - r.fill = color.left; - r.draw( - gfx, [ points[0], points[2], points[4], points[6], - ] + ], + fill.left ); } } @@ -173,6 +149,9 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) { let position = {...grid.position} as Vec3; let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let tileCoord = new Vec3(0, 0, 0); + let rect = new Rectangle([ + DrawTag.ISO, + ]); // TODO: Optimize this // 1. Grid based occlusion culling @@ -193,7 +172,13 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) { continue; } - drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); + drawIsometricCube( + new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), + exts, + rect, + tile.fill, + tile.edge + ); position.x += grid.tileSize; } @@ -202,4 +187,6 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) { } position.y = grid.position.y; } + + rect.commit(gfx); } diff --git a/src/js/graphics.js b/src/js/graphics.js index 9871d9f..2e98a43 100644 --- a/src/js/graphics.js +++ b/src/js/graphics.js @@ -92,15 +92,16 @@ export class Graphics { } draw() { for (let o of this.toRender) { + const data = o.data.flat(); this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo); - this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW); + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(data), this.ctx.STATIC_DRAW); let aid = 0; for (let a of o.attribs) { let attr = this.getAttribute(a); if (!attr.formatted) throw new Error("Tried to use unformatted attribute!"); this.ctx.enableVertexAttribArray(attr.loc); - this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4); + this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.vertexSize * 4, aid * 4); aid += attr.size; } // Generalize the tag uniforms aka. don't hard code them @@ -112,15 +113,9 @@ export class Graphics { } } } - if (o.fill instanceof Texture) { - this.ctx.uniform1i(this.getUniform("u_isTex"), 1); - o.fill.bind(this); - } - this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride); - if (o.fill instanceof Texture) { - this.ctx.uniform1i(this.getUniform("u_isTex"), 0); - o.fill.unbind(this); - } + o.sprites?.bind(this); + this.ctx.drawArrays(this.ctx.TRIANGLES, 0, data.length / o.vertexSize); + o.sprites?.unbind(this); for (let t of o.tags) { switch (t) { case DrawTag.ISO: { @@ -183,6 +178,48 @@ export class Texture { gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); } } +export class Sprite { + id = 0; + constructor(id) { + this.id = id; + } + static id(id) { + return new Sprite(id); + } + static tile(id) { + let s = new Sprite(id); + return { + left: s, + top: s, + right: s, + }; + } +} +; +export class Spritesheet { + texture; // Texture is a horizontal spritesheet + spriteSize; // width and height of one sprite + spriteCount; // number of sprites + constructor(texture, spriteSize) { + this.texture = texture; + this.spriteSize = spriteSize; + this.spriteCount = texture.width / spriteSize.x; + } + getUVs(id) { + return [ + new Vec2((this.spriteSize.x * id) / this.texture.width, 0), + new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, 0), + new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, -1), + new Vec2((this.spriteSize.x * id) / this.texture.width, -1), + ]; + } + bind(gfx) { + this.texture.bind(gfx); + } + unbind(gfx) { + this.texture.unbind(gfx); + } +} async function loadTexture(path) { return new Promise(resolve => { const img = new Image(); diff --git a/src/js/graphics.ts b/src/js/graphics.ts index b14db2f..891e270 100644 --- a/src/js/graphics.ts +++ b/src/js/graphics.ts @@ -1,5 +1,5 @@ -import * as Assets from "./assets.js"; import {Vec2, Vec3, Vec4} from "./common.js"; +import { TileFillament, TileFill } from "./world.js"; export function fullscreenCanvas(gfx: Graphics, id: string) { const canvas = document.getElementById(id) as HTMLCanvasElement; @@ -57,13 +57,13 @@ export enum DrawTag { } export interface Drawable { - fill: Texture | Assets.Color; attribs: string[]; tags: Array; - data: Array; - vertexStride: number; - stride: number; + data: number[][]; + vertexSize: number; + + sprites: Spritesheet | undefined; } export class Graphics { @@ -131,8 +131,10 @@ export class Graphics { draw() { for (let o of this.toRender) { + const data = o.data.flat(); + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo); - this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW); + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(data), this.ctx.STATIC_DRAW); let aid = 0; for (let a of o.attribs) { @@ -141,7 +143,7 @@ export class Graphics { throw new Error("Tried to use unformatted attribute!"); this.ctx.enableVertexAttribArray(attr.loc); - this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4); + this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.vertexSize * 4, aid * 4); aid += attr.size; } @@ -154,20 +156,12 @@ export class Graphics { } } } + + o.sprites?.bind(this); + + this.ctx.drawArrays(this.ctx.TRIANGLES, 0, data.length / o.vertexSize); - if (o.fill instanceof Texture) - { - this.ctx.uniform1i(this.getUniform("u_isTex"), 1); - o.fill.bind(this); - } - - this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride); - - if (o.fill instanceof Texture) - { - this.ctx.uniform1i(this.getUniform("u_isTex"), 0); - o.fill.unbind(this); - } + o.sprites?.unbind(this); for (let t of o.tags) { switch (t) { @@ -177,7 +171,6 @@ export class Graphics { } } } - } // TODO: Maybe add persistent rendering? @@ -251,6 +244,59 @@ export class Texture { } } +export type SpriteId = number; + +export class Sprite { + id: SpriteId = 0; + + private constructor(id: SpriteId) { + this.id = id; + } + + static id(id: SpriteId): Sprite { + return new Sprite(id); + } + + static tile(id: SpriteId): TileFill { + let s = new Sprite(id); + + return { + left: s, + top: s, + right: s, + } + } +}; + +export class Spritesheet { + texture: Texture; // Texture is a horizontal spritesheet + spriteSize: Vec2; // width and height of one sprite + spriteCount: number; // number of sprites + + constructor(texture: Texture, spriteSize: Vec2) { + this.texture = texture; + this.spriteSize = spriteSize; + this.spriteCount = texture.width / spriteSize.x; + } + + getUVs(id: number): [Vec2, Vec2, Vec2, Vec2] { + return [ + new Vec2((this.spriteSize.x * id) / this.texture.width, 0), + new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, 0), + new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, -1), + new Vec2((this.spriteSize.x * id) / this.texture.width, -1), + ]; + } + + bind(gfx: Graphics) { + this.texture.bind(gfx); + } + + unbind(gfx: Graphics) { + this.texture.unbind(gfx); + } +} + async function loadTexture(path: string): Promise { return new Promise(resolve => { const img = new Image(); diff --git a/src/js/script.js b/src/js/script.js index 6bebe9e..6f82926 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -1,22 +1,21 @@ import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js"; -import { Graphics, fullscreenCanvas, Camera } from "./graphics.js"; +import { Graphics, fullscreenCanvas, Camera, Sprite } from "./graphics.js"; import * as drawing from "./draw.js"; import * as wasm from "./wasm.js"; import { Input } from "./input.js"; -import { bush, Grid, Tile, tree } from "./world.js"; +import { Grid, Tile, tree } from "./world.js"; import * as Assets from "./assets.js"; const vertexShader = `#version 300 es layout(location = 0) in vec3 a_position; - layout(location = 1) in vec2 a_tex_position; + layout(location = 1) in vec3 a_tex; layout(location = 2) in vec4 a_color; out vec4 v_color; - out vec2 v_tex_position; + out vec3 v_tex; uniform mat4 u_matrix; uniform bool u_isIso; - uniform bool u_isTex; mat4 Iso = mat4( 1, -1, 0, 0, @@ -38,11 +37,8 @@ const vertexShader = `#version 300 es gl_Position = orthographic; - if (u_isTex) { - v_tex_position = a_tex_position; - } else { - v_color = a_color; - } + v_tex = a_tex; + v_color = a_color; } `; const fragmentShader = `#version 300 es @@ -50,15 +46,14 @@ const fragmentShader = `#version 300 es precision highp float; in vec4 v_color; - in vec2 v_tex_position; + in vec3 v_tex; out vec4 outColor; uniform sampler2D u_texture; - uniform bool u_isTex; void main() { - if (u_isTex) { - outColor = texture(u_texture, v_tex_position); + if (v_tex.z == 1.0) { + outColor = texture(u_texture, v_tex.xy); } else { outColor = v_color; } @@ -131,23 +126,21 @@ function addDefaultKeybinds(input, camera) { a.format(3, ctx.FLOAT, false, 0); a = gfx.createAttribute("a_color"); a.format(4, ctx.FLOAT, false, 0); - a = gfx.createAttribute("a_tex_position"); - a.format(2, ctx.FLOAT, false, 0); + a = gfx.createAttribute("a_tex"); + a.format(3, ctx.FLOAT, false, 0); gfx.createUniform("u_matrix"); gfx.createUniform("u_isIso"); - gfx.createUniform("u_isTex"); let camera = new Camera(new Vec3(0, 0, -1)); await Assets.assets.load(gfx); let m = Mat4.isometric(); let size = 100; let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); grid.fillLayer(new Tile({ - top: Assets.assets.get("grass"), + top: Sprite.id(0), right: Assets.Colors.Brown, left: Assets.Colors.Brown, }), 0); - tree(grid, new Vec2(size / 2, size / 2)); - bush(grid, new Vec2(size / 2 + 4, size / 2 + 4)); + tree(grid, new Vec2(5, 5)); //for (let i = 0; i < 10; i++) { // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); //} diff --git a/src/js/script.ts b/src/js/script.ts index bba8808..c1b49a7 100644 --- a/src/js/script.ts +++ b/src/js/script.ts @@ -1,24 +1,23 @@ import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js"; -import { Graphics, fullscreenCanvas, Camera, DrawTag } from "./graphics.js"; +import { Graphics, fullscreenCanvas, Camera, Sprite } from "./graphics.js"; import * as drawing from "./draw.js"; import * as wasm from "./wasm.js"; import { Input } from "./input.js"; -import {bush, Grid, Tile, TileEdge, tree} from "./world.js"; +import {Grid, Tile, TileEdge, tree} from "./world.js"; import * as Assets from "./assets.js"; const vertexShader = `#version 300 es layout(location = 0) in vec3 a_position; - layout(location = 1) in vec2 a_tex_position; + layout(location = 1) in vec3 a_tex; layout(location = 2) in vec4 a_color; out vec4 v_color; - out vec2 v_tex_position; + out vec3 v_tex; uniform mat4 u_matrix; uniform bool u_isIso; - uniform bool u_isTex; mat4 Iso = mat4( 1, -1, 0, 0, @@ -40,11 +39,8 @@ const vertexShader = gl_Position = orthographic; - if (u_isTex) { - v_tex_position = a_tex_position; - } else { - v_color = a_color; - } + v_tex = a_tex; + v_color = a_color; } `; @@ -54,15 +50,14 @@ const fragmentShader = precision highp float; in vec4 v_color; - in vec2 v_tex_position; + in vec3 v_tex; out vec4 outColor; uniform sampler2D u_texture; - uniform bool u_isTex; void main() { - if (u_isTex) { - outColor = texture(u_texture, v_tex_position); + if (v_tex.z == 1.0) { + outColor = texture(u_texture, v_tex.xy); } else { outColor = v_color; } @@ -178,12 +173,11 @@ function addDefaultKeybinds(input: Input, camera: Camera) { a.format(3, ctx.FLOAT, false, 0) a = gfx.createAttribute("a_color"); a.format(4, ctx.FLOAT, false, 0) - a = gfx.createAttribute("a_tex_position"); - a.format(2, ctx.FLOAT, false, 0) + a = gfx.createAttribute("a_tex"); + a.format(3, ctx.FLOAT, false, 0) gfx.createUniform("u_matrix"); gfx.createUniform("u_isIso"); - gfx.createUniform("u_isTex"); let camera = new Camera(new Vec3(0, 0, -1)); @@ -194,13 +188,11 @@ function addDefaultKeybinds(input: Input, camera: Camera) { let size = 100; let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); grid.fillLayer(new Tile({ - top: Assets.assets.get("grass"), + top: Sprite.id(0), right: Assets.Colors.Brown, left: Assets.Colors.Brown, }), 0); - - tree(grid, new Vec2(size / 2, size / 2)); - bush(grid, new Vec2(size / 2 + 4, size / 2 + 4)); + tree(grid, new Vec2(5, 5)); //for (let i = 0; i < 10; i++) { // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); //} @@ -211,7 +203,7 @@ function addDefaultKeybinds(input: Input, camera: Camera) { const frame = (timestamp: number) => { const deltaTime = (timestamp - prevTimestamp)/1000; prevTimestamp = timestamp; - + fullscreenCanvas(gfx, "game"); draw(gfx, camera, deltaTime, grid); diff --git a/src/js/world.js b/src/js/world.js index 2aee45b..46b47e4 100644 --- a/src/js/world.js +++ b/src/js/world.js @@ -1,5 +1,5 @@ -import * as Assets from "./assets.js"; import { Vec3 } from "./common.js"; +import { Sprite } from "./graphics.js"; export var TileEdge; (function (TileEdge) { TileEdge[TileEdge["None"] = 0] = "None"; @@ -73,25 +73,28 @@ export class Grid { } } export function tree(grid, position) { - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); + let log = Sprite.tile(2); + let leaves = Sprite.tile(1); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 1)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 2)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 3)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(log, TileEdge.None), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); } export function bush(grid, position) { - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); + let leaves = Sprite.tile(1); + grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); + grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(2)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); } diff --git a/src/js/world.ts b/src/js/world.ts index f0a0ffd..2e29613 100644 --- a/src/js/world.ts +++ b/src/js/world.ts @@ -1,6 +1,6 @@ import * as Assets from "./assets.js"; import {Vec2, Vec3} from "./common.js"; -import {Texture} from "./graphics.js"; +import {Sprite} from "./graphics.js"; export enum TileEdge { None, @@ -9,8 +9,12 @@ export enum TileEdge { Both, } -export type TileFillament = Texture | Assets.Color; -export type TileFill = { left: TileFillament, top: TileFillament, right: TileFillament }; +export type TileFillament = Sprite | Assets.Color; +export type TileFill = { + right: TileFillament + left: TileFillament, + top: TileFillament, +}; export class Tile { fill: TileFill = { @@ -31,8 +35,8 @@ export class Tile { export function ColorToTile(c: Assets.Color) { return { - left: c, - top: c, + left: c, + top: c, right: c, }; } @@ -96,27 +100,32 @@ export class Grid { } export function tree(grid: Grid, position: Vec2) { - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3)); - grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); + let log = Sprite.tile(2); + let leaves = Sprite.tile(1); + + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 1)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 2)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 3)); + grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(log, TileEdge.None), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); } export function bush(grid: Grid, position: Vec2) { - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); + let leaves = Sprite.tile(1); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); - grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); + grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); + + grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(2)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); + grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); }