Skip to content
This repository was archived by the owner on Nov 12, 2024. It is now read-only.

Commit dcba23c

Browse files
committed
Implement isometric level support
Refactor isometric grid rendering Fix isometric level demo Improve isometric level support and add more demo examples Lint addIsometricLevel: Mirror width and height property names from addLevel Remove unnecessary from2dTo1dIndex method of isometricLevel Rename and lint isometricLevel interface to match levels
1 parent 9c4c3f3 commit dcba23c

File tree

5 files changed

+258
-0
lines changed

5 files changed

+258
-0
lines changed

assets/sprites/iso_grass.png

1.96 KB
Loading
2.38 KB
Loading

demo/isometricLevel.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Build levels with addIsometricLevel()
2+
3+
// Start game
4+
kaboom()
5+
6+
// Load assets
7+
loadSprite("grass", "/sprites/iso_grass.png")
8+
loadSprite("darker_grass", "/sprites/iso_grass_darker.png")
9+
10+
gravity(0)
11+
camScale(0.33)
12+
camPos(vec2(100, 1000))
13+
14+
addIsometricLevel([
15+
// Design the isometric level layout with symbols
16+
// 15x15 grid in this case so we have a perfect tiled square diamond shaped map
17+
"@@@@@@@@@@@@@@@",
18+
"@@@@@@@@@@@@@@@",
19+
"@@@@@@@@@@@@@@@",
20+
"@@@@!@@@@!@@@@@",
21+
"@@@@@@@@@@@@@@@",
22+
"@@@@@@@@@@@@@@@",
23+
"@@@@@!@@@!@@@@@",
24+
"@@@@@@!!!@@@@@@",
25+
"@@@@@@@@@@@@@@@",
26+
"@@@@@@@@@@@@@@@",
27+
"@@@@@@@@@@@@@@@",
28+
"@@@@@@@@@@@@@@@",
29+
"@@@@@@@@@@@@@@@",
30+
"@@@@@@@@@@@@@@@",
31+
"@@@@@@@@@@@@@@@",
32+
], {
33+
// The size of each grid
34+
width: 144,
35+
height: 71,
36+
// Define what each symbol means (in components)
37+
"@": () => [
38+
sprite("grass"),
39+
],
40+
"!": () => [
41+
sprite("darker_grass"),
42+
],
43+
})
44+
45+
addIsometricLevel([
46+
// 15x9 grid
47+
"@@@@@@@@@@@@@@@",
48+
"@@@@@@@@@@@@@@@",
49+
"@@@@@@@!@@@@@@@",
50+
"@@@@@@@!@@@@@@@",
51+
"@@@@@@@!@@@@@@@",
52+
"@@@@@@@!@@@@@@@",
53+
"@@@@@@@!@@@@@@@",
54+
"@@@@@@@@@@@@@@@",
55+
"@@@@@@@!@@@@@@@",
56+
"@@@@@@@@@@@@@@@",
57+
"@@@@@@@@@@@@@@@",
58+
], {
59+
width: 144,
60+
height: 71,
61+
"@": () => [
62+
sprite("grass"),
63+
],
64+
"!": () => [
65+
sprite("darker_grass"),
66+
],
67+
// The position of the top left block
68+
pos: vec2(0, 1200),
69+
})

src/kaboom.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ import {
142142
BoomOpt,
143143
PeditFile,
144144
Shape,
145+
IsometricLevelOpt,
146+
IsometricLevel,
145147
} from "./types"
146148

147149
import FPSCounter from "./fps"
@@ -5094,6 +5096,18 @@ export default (gopt: KaboomOpt = {}): KaboomCtx => {
50945096

50955097
}
50965098

5099+
function isometricGrid(isometricLevel: IsometricLevel, position: Vec2) {
5100+
5101+
return {
5102+
5103+
id: "isometricGrid",
5104+
gridPos: position.clone(),
5105+
level: isometricLevel,
5106+
5107+
}
5108+
5109+
}
5110+
50975111
function addLevel(map: string[], opt: LevelOpt): GameObj<PosComp | LevelComp> {
50985112

50995113
if (!opt.width || !opt.height) {
@@ -5193,6 +5207,106 @@ export default (gopt: KaboomOpt = {}): KaboomCtx => {
51935207

51945208
}
51955209

5210+
function addIsometricLevel(map: string[], options: IsometricLevelOpt): IsometricLevel {
5211+
if (!options.width || !options.height) {
5212+
throw new Error("Must provide isometric level tile width & height.")
5213+
}
5214+
5215+
const objects: GameObj[] = []
5216+
const offset = vec2(options.pos || vec2(0))
5217+
5218+
const halfTileWidth = Math.floor(options.width / 2)
5219+
const halfTileHeight = Math.floor(options.height / 2)
5220+
5221+
const maxWidthInTiles = map.reduce((width, row): number => Math.max(width, row.length), 0)
5222+
const heightInTiles = map.length
5223+
5224+
const isometricLevel = {
5225+
offset() {
5226+
return offset.clone()
5227+
},
5228+
5229+
gridWidth() {
5230+
return options.width
5231+
},
5232+
5233+
gridHeight() {
5234+
return options.height
5235+
},
5236+
5237+
getPos: (...args): Vec2 => {
5238+
const p = vec2(...args)
5239+
return vec2((p.x - p.y) * halfTileWidth, (p.x + p.y) * halfTileHeight)
5240+
},
5241+
5242+
spawn: (position: Vec2, symbol: string): GameObj => {
5243+
const comps = (() => {
5244+
if (options[symbol]) {
5245+
if (typeof options[symbol] !== "function") {
5246+
throw new Error("isometric level symbol def must be a function returning a component list")
5247+
}
5248+
return options[symbol](position)
5249+
} else if (options.any) {
5250+
return options.any(symbol, position)
5251+
}
5252+
})()
5253+
5254+
if (!comps) {
5255+
return
5256+
}
5257+
5258+
const posComp = vec2(
5259+
offset.x + position.x,
5260+
offset.y + position.y,
5261+
)
5262+
5263+
for (const comp of comps) {
5264+
if (comp.id === "pos") {
5265+
posComp.x += comp.pos.x
5266+
posComp.y += comp.pos.y
5267+
5268+
break
5269+
}
5270+
}
5271+
5272+
comps.push(pos(posComp))
5273+
comps.push(isometricGrid(this, position))
5274+
5275+
const object = add(comps)
5276+
objects.push(object)
5277+
5278+
return object
5279+
},
5280+
5281+
width() {
5282+
return maxWidthInTiles * options.width
5283+
},
5284+
5285+
height() {
5286+
return heightInTiles * options.height
5287+
},
5288+
5289+
destroy() {
5290+
for (const someObject of objects) {
5291+
destroy(someObject)
5292+
}
5293+
},
5294+
}
5295+
5296+
for (let row = 0; row < heightInTiles; row++) {
5297+
for (let col = 0; col < maxWidthInTiles; col++) {
5298+
const position = isometricLevel.getPos(col, row)
5299+
const rowContent: string = map[row]
5300+
const symbols: string[] = rowContent.split("")
5301+
const symbol = symbols[col]
5302+
5303+
isometricLevel.spawn(position, symbol)
5304+
}
5305+
}
5306+
5307+
return isometricLevel
5308+
}
5309+
51965310
function record(frameRate?): Recording {
51975311

51985312
const stream = app.canvas.captureStream(frameRate)
@@ -6180,6 +6294,8 @@ export default (gopt: KaboomOpt = {}): KaboomCtx => {
61806294
go,
61816295
// level
61826296
addLevel,
6297+
// isometric level
6298+
addIsometricLevel,
61836299
// storage
61846300
getData,
61856301
setData,

src/types.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,46 @@ export interface KaboomCtx {
16501650
* ```
16511651
*/
16521652
addLevel(map: string[], options: LevelOpt): GameObj,
1653+
/**
1654+
* Construct a isometric level based on symbols.
1655+
*
1656+
* @section IsometricLevel
1657+
*
1658+
* @example
1659+
* ```js
1660+
* addIsometricLevel([
1661+
* // Design the isometric level layout with symbols
1662+
* // 15x15 grid in this case so we have a perfect tiled square diamond shaped map
1663+
* "@@@@@@@@@@@@@@@",
1664+
* "@@@@@@@@@@@@@@@",
1665+
* "@@@@@@@@@@@@@@@",
1666+
* "@@@@!@@@@!@@@@@",
1667+
* "@@@@@@@@@@@@@@@",
1668+
* "@@@@@@@@@@@@@@@",
1669+
* "@@@@@!@@@!@@@@@",
1670+
* "@@@@@@!!!@@@@@@",
1671+
* "@@@@@@@@@@@@@@@",
1672+
* "@@@@@@@@@@@@@@@",
1673+
* "@@@@@@@@@@@@@@@",
1674+
* "@@@@@@@@@@@@@@@",
1675+
* "@@@@@@@@@@@@@@@",
1676+
* "@@@@@@@@@@@@@@@",
1677+
* "@@@@@@@@@@@@@@@",
1678+
* ], {
1679+
* // The size of each grid
1680+
* width: 144,
1681+
* height: 71,
1682+
* // Define what each symbol means (in components)
1683+
* "@": () => [
1684+
* sprite("grass"),
1685+
* ],
1686+
* "!": () => [
1687+
* sprite("darker_grass"),
1688+
* ],
1689+
* })
1690+
* ```
1691+
*/
1692+
addIsometricLevel(map: string[], options: IsometricLevelOpt): IsometricLevel,
16531693
/**
16541694
* Get data from local storage, if not present can set to a default value.
16551695
*
@@ -4313,6 +4353,39 @@ export interface LevelComp extends Comp {
43134353
levelHeight(): number,
43144354
}
43154355

4356+
export interface IsometricLevelOpt {
4357+
/**
4358+
* Width of each block.
4359+
*/
4360+
width: number,
4361+
/**
4362+
* Height of each block.
4363+
*/
4364+
height: number,
4365+
/**
4366+
* Position of the first block.
4367+
*/
4368+
pos?: Vec2,
4369+
/**
4370+
* Called when encountered an undefined symbol.
4371+
*/
4372+
any?: (s: string, pos: Vec2) => CompList<any> | undefined,
4373+
// TODO: should return CompList<any>
4374+
[sym: string]: any,
4375+
}
4376+
4377+
export interface IsometricLevel {
4378+
spawn(position: Vec2, symbol: string): GameObj,
4379+
gridWidth(): number,
4380+
gridHeight(): number,
4381+
offset(): Vec2,
4382+
getPos(p: Vec2): Vec2,
4383+
getPos(x: number, y: number): Vec2,
4384+
width(): number,
4385+
height(): number,
4386+
destroy(): void,
4387+
}
4388+
43164389
export interface BoomOpt {
43174390
/**
43184391
* Animation speed.

0 commit comments

Comments
 (0)