Skip to content

Commit

Permalink
[WIP] Implement isometric level support
Browse files Browse the repository at this point in the history
  • Loading branch information
gugiserman committed Nov 10, 2021
1 parent 297f146 commit acd8ec0
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
Binary file added assets/sprites/iso_grass.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions demo/isometricLevel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Build levels with addIsometricLevel()

// Start game
kaboom()

// Load assets
loadSprite("grass", "/sprites/iso_grass.png")

gravity(0)

const level = addIsometricLevel([
// Design the level layout with symbols
"@",
"@@",
"@@@",
"@@@@",
"@@@@@",
"@@@@@@",
"@@@@@@@",
"@@@@@@@@",
"@@@@@@@@@",
"@@@@@@@@@@",
"@@@@@@@@@@@",
"@@@@@@@@@@@@",
"@@@@@@@@@@@@@",
"@@@@@@@@@@@@",
"@@@@@@@@@@@",
"@@@@@@@@@@",
"@@@@@@@@@",
"@@@@@@@@",
"@@@@@@@",
"@@@@@@",
"@@@@@",
"@@@@",
"@@@",
"@@",
"@",
], {
// The size of each grid
tileWidth: 144,
tileHeight: 71,
// The position of the top left block
// pos: vec2(100, 200),
// Define what each symbol means (in components)
"@": () => [
sprite("grass"),
],
})
137 changes: 137 additions & 0 deletions src/kaboom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ import {
LevelOpt,
Cursor,
Recording,
IsometricLevelOpt,
IsometricLevel,
} from "./types";

import kaboomPlugin from "./plugins/kaboom";
Expand Down Expand Up @@ -2351,6 +2353,42 @@ function grid(level: Level, p: Vec2) {

}

function isometricGrid(isometricLevel: IsometricLevel, position: Vec2) {

return {

id: "isometricGrid",
gridPos: position.clone(),

setGridPos(...args) {
const p = vec2(...args);
this.gridPos = p.clone();
this.pos = vec2(
isometricLevel.offset().x + this.gridPos.x * isometricLevel.gridWidth(),
isometricLevel.offset().y + this.gridPos.y * isometricLevel.gridHeight()
);
},

moveLeft() {
this.setGridPos(this.gridPos.add(vec2(-1, 0)));
},

moveRight() {
this.setGridPos(this.gridPos.add(vec2(1, 0)));
},

moveUp() {
this.setGridPos(this.gridPos.add(vec2(0, -1)));
},

moveDown() {
this.setGridPos(this.gridPos.add(vec2(0, 1)));
},

};

}

function addLevel(map: string[], opt: LevelOpt): Level {

if (!opt.width || !opt.height) {
Expand Down Expand Up @@ -2458,6 +2496,103 @@ function addLevel(map: string[], opt: LevelOpt): Level {

}

function addIsometricLevel(map: string[], options: IsometricLevelOpt): IsometricLevel {
if (map.length % 2 === 0) {
throw new Error("Must provide isometric level map array of odd length.")
}

if (!options.tileWidth || !options.tileHeight) {
throw new Error("Must provide isometric level tile width & height.");
}

const objects: GameObj[] = [];
const offset = vec2(options.pos || vec2(0));

const halfTileWidth = options.tileWidth / 2;
const halfTileHeight = options.tileHeight / 2;

const maxWidthInTiles = map.reduce((width, row): number => Math.max(width, row.length), 0)
const heightInTiles = map.length;

const isometricLevel = {
offset() {
return offset.clone();
},

gridWidth() {
return options.tileWidth;
},

gridHeight() {
return options.tileHeight;
},

fromIsometricCoordinatesToScreenPos: (row: number, col: number): Vec2 => {
return vec2((col - row) * halfTileWidth, (col + row) * halfTileHeight);
},

from2dTo1dIndex: (row: number, col: number): number => {
return row * maxWidthInTiles + col
},

spawn: (position: Vec2, symbol: string): GameObj => {
const comps = (() => {
if (options[symbol]) {
if (typeof options[symbol] !== "function") {
throw new Error("isometric level symbol def must be a function returning a component list");
}
return options[symbol](position);
} else if (options.any) {
return options.any(symbol, position);
}
})();

if (!comps) {
return;
}

// const posComp = vec2(
// offset.x + position.x * options.tileWidth,
// offset.y + position.y * options.tileHeight
// );

// for (const comp of comps) {
// if (comp.id === "pos") {
// posComp.x += comp.pos.x;
// posComp.y += comp.pos.y;

// break;
// }
// }

comps.push(pos(position));
comps.push(isometricGrid(this, position));

const object = add(comps);
objects.push(object);

return object;
},
};

for (let row = 0; row < heightInTiles; row++) {
for (let col = 0; col < maxWidthInTiles; col++) {
const position = isometricLevel.fromIsometricCoordinatesToScreenPos(row, col);
const index = isometricLevel.from2dTo1dIndex(row, col);
const symbols: string = map[index] || '';
const symbol = symbols[col]

if (!symbol) {
break
}

isometricLevel.spawn(position, symbol);
}
}

return isometricLevel;
}

function record(frameRate?): Recording {

const stream = app.canvas.captureStream(frameRate);
Expand Down Expand Up @@ -2714,6 +2849,8 @@ const ctx: KaboomCtx = {
go,
// level
addLevel,
// isometric level
addIsometricLevel,
// storage
getData,
setData,
Expand Down
28 changes: 28 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3806,6 +3806,27 @@ export interface LevelOpt {
[sym: string]: any,
}

export interface IsometricLevelOpt {
/**
* Width of each block.
*/
tileWidth: number,
/**
* Height of each block.
*/
tileHeight: number,
/**
* Position of the first block.
*/
pos?: Vec2,
/**
* Called when encountered an undefined symbol.
*/
any?: (s: string, pos: Vec2) => CompList<any> | undefined,
// TODO: should return CompList<any>
[sym: string]: any,
}

export interface Level {
getPos(p: Vec2): Vec2,
getPos(x: number, y: number): Vec2,
Expand All @@ -3818,3 +3839,10 @@ export interface Level {
offset(): Vec2,
destroy(),
}

export interface IsometricLevel {
spawn(position: Vec2, symbol: string): GameObj,
gridWidth(): number,
gridHeight(): number,
offset(): Vec2,
}

0 comments on commit acd8ec0

Please sign in to comment.