Skip to content

Commit 6bc5ce5

Browse files
committed
feat: introduce biome generation and update tree spawning logic
1 parent 3f7b3ec commit 6bc5ce5

File tree

4 files changed

+80
-21
lines changed

4 files changed

+80
-21
lines changed

games/tribe2/src/components/game-world-controller.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { renderGame } from '../game/renderer/renderer';
66
import { GameInputController } from './game-input-controller';
77
import { BACKGROUND_COLOR } from '../game/constants/rendering-constants';
88
import { HEIGHT_MAP_RESOLUTION, MAP_HEIGHT, MAP_WIDTH } from '../game/constants/world-constants';
9-
import { generateHeightMap, generateTrees, initWorld } from '../game/game-factory';
9+
import { generateBiomeMap, generateHeightMap, generateTrees, initWorld } from '../game/game-factory';
1010
import { createEntities } from '../game/ecs/entity-manager';
1111
import { IntroAnimState, initIntroAnimation, updateIntroAnimation } from './intro-animation';
1212
import { useWebGpuRenderer } from '../context/webgpu-renderer-context';
@@ -65,13 +65,15 @@ export const GameWorldController: React.FC<GameWorldControllerProps> = ({ mode,
6565
let worldState: GameWorldState;
6666
if (mode === 'intro') {
6767
const heightMap = generateHeightMap(MAP_WIDTH, MAP_HEIGHT, HEIGHT_MAP_RESOLUTION);
68+
const biomeMap = generateBiomeMap(heightMap);
6869
const entities = createEntities();
69-
generateTrees(entities, heightMap, HEIGHT_MAP_RESOLUTION);
70+
generateTrees(entities, biomeMap, HEIGHT_MAP_RESOLUTION);
7071
worldState = {
7172
time: 0,
7273
entities: entities,
7374
mapDimensions: { width: MAP_WIDTH, height: MAP_HEIGHT },
7475
heightMap,
76+
biomeMap,
7577
viewportCenter: { x: MAP_WIDTH / 2, y: MAP_HEIGHT / 2 },
7678
viewportZoom: 1.0,
7779
isPaused: false,

games/tribe2/src/game/constants/world-constants.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ export const HEIGHT_MAP_RESOLUTION = 50;
1414
export const WATER_LEVEL = 0.45;
1515

1616
// Biome Constants
17+
/** The normalized height value (0-1) above which snow appears. */
18+
export const SNOW_LEVEL = 0.8;
19+
20+
/** The normalized height value (0-1) above which rock appears. */
21+
export const ROCK_LEVEL = 0.65;
22+
23+
/** The normalized height value (0-1) above which grass appears. */
24+
export const GRASS_LEVEL = 0.5;
25+
26+
/** The normalized height value (0-1) above which sand appears. */
27+
export const SAND_LEVEL = 0.46;
28+
1729
/** The radius of tree entities in pixels. */
1830
export const TREE_RADIUS = 8;
1931

games/tribe2/src/game/game-factory.ts

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import { createEntities, createEntity } from './ecs/entity-manager';
2-
import { HEIGHT_MAP_RESOLUTION, MAP_HEIGHT, MAP_WIDTH, TREE_RADIUS, TREE_SPAWN_THRESHOLD, TREE_SPAWN_DENSITY } from './constants/world-constants';
2+
import {
3+
HEIGHT_MAP_RESOLUTION,
4+
MAP_HEIGHT,
5+
MAP_WIDTH,
6+
TREE_RADIUS,
7+
TREE_SPAWN_DENSITY,
8+
WATER_LEVEL,
9+
SNOW_LEVEL,
10+
ROCK_LEVEL,
11+
GRASS_LEVEL,
12+
SAND_LEVEL,
13+
} from './constants/world-constants';
314
import { Entities, EntityType, BiomeType, GameWorldState } from './types/world-types';
415
import { createNoise2D } from './utils/noise-utils';
516

@@ -37,35 +48,63 @@ export function generateHeightMap(width: number, height: number, resolution: num
3748
}
3849

3950
/**
40-
* Generates tree entities based on the heightmap.
41-
* Trees spawn on land (above TREE_SPAWN_THRESHOLD) with a probability of TREE_SPAWN_DENSITY.
42-
* @param entities The entity manager to add trees to.
51+
* Generates a biome map based on the height map.
4352
* @param heightMap The heightmap of the world.
44-
* @param resolution The size of each height map cell in pixels.
53+
* @returns A 2D array of BiomeType enums.
4554
*/
46-
export function generateTrees(
47-
entities: Entities,
48-
heightMap: number[][],
49-
resolution: number,
50-
): void {
55+
export function generateBiomeMap(heightMap: number[][]): BiomeType[][] {
5156
const gridHeight = heightMap.length;
5257
const gridWidth = heightMap[0]?.length ?? 0;
58+
const biomeMap: BiomeType[][] = Array.from({ length: gridHeight }, () => new Array(gridWidth));
5359

5460
for (let y = 0; y < gridHeight; y++) {
5561
for (let x = 0; x < gridWidth; x++) {
5662
const height = heightMap[y][x];
57-
58-
// Only spawn trees on land (above water level threshold)
59-
if (height > TREE_SPAWN_THRESHOLD) {
63+
if (height > SNOW_LEVEL) {
64+
biomeMap[y][x] = BiomeType.SNOW;
65+
} else if (height > ROCK_LEVEL) {
66+
biomeMap[y][x] = BiomeType.ROCK;
67+
} else if (height > GRASS_LEVEL) {
68+
biomeMap[y][x] = BiomeType.GRASS;
69+
} else if (height > SAND_LEVEL) {
70+
biomeMap[y][x] = BiomeType.SAND;
71+
} else if (height > WATER_LEVEL) {
72+
biomeMap[y][x] = BiomeType.GROUND;
73+
} else {
74+
// Water is not a biome type, but could be handled here if needed
75+
biomeMap[y][x] = BiomeType.GROUND; // Default to ground for below-water cells
76+
}
77+
}
78+
}
79+
80+
return biomeMap;
81+
}
82+
83+
/**
84+
* Generates tree entities based on the biome map.
85+
* Trees spawn on GRASS biome cells with a probability of TREE_SPAWN_DENSITY.
86+
* @param entities The entity manager to add trees to.
87+
* @param biomeMap The biome map of the world.
88+
* @param resolution The size of each map cell in pixels.
89+
*/
90+
export function generateTrees(entities: Entities, biomeMap: BiomeType[][], resolution: number): void {
91+
const gridHeight = biomeMap.length;
92+
const gridWidth = biomeMap[0]?.length ?? 0;
93+
94+
for (let y = 0; y < gridHeight; y++) {
95+
for (let x = 0; x < gridWidth; x++) {
96+
const biome = biomeMap[y][x];
97+
98+
// Only spawn trees on grass
99+
if (biome === BiomeType.GRASS) {
60100
// Random chance to spawn a tree
61101
if (Math.random() < TREE_SPAWN_DENSITY) {
62102
const worldX = x * resolution + Math.random() * resolution;
63103
const worldY = y * resolution + Math.random() * resolution;
64-
104+
65105
createEntity(entities, EntityType.TREE, {
66106
position: { x: worldX, y: worldY },
67107
radius: TREE_RADIUS,
68-
biomeType: BiomeType.TREE,
69108
});
70109
}
71110
}
@@ -80,9 +119,10 @@ export function generateTrees(
80119
export function initWorld(): GameWorldState {
81120
const entities = createEntities();
82121
const heightMap = generateHeightMap(MAP_WIDTH, MAP_HEIGHT, HEIGHT_MAP_RESOLUTION);
122+
const biomeMap = generateBiomeMap(heightMap);
83123

84-
// Generate trees based on heightmap
85-
generateTrees(entities, heightMap, HEIGHT_MAP_RESOLUTION);
124+
// Generate trees based on the biome map
125+
generateTrees(entities, biomeMap, HEIGHT_MAP_RESOLUTION);
86126

87127
const initialWorldState: GameWorldState = {
88128
time: 0,
@@ -92,6 +132,7 @@ export function initWorld(): GameWorldState {
92132
height: MAP_HEIGHT,
93133
},
94134
heightMap,
135+
biomeMap,
95136
viewportCenter: {
96137
x: MAP_WIDTH / 2,
97138
y: MAP_HEIGHT / 2,

games/tribe2/src/game/types/world-types.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export enum EntityType {
1414

1515
export enum BiomeType {
1616
TREE = 'tree',
17+
ROCK = 'rock',
18+
SNOW = 'snow',
19+
SAND = 'sand',
20+
GRASS = 'grass',
21+
GROUND = 'ground',
1722
}
1823

1924
/**
@@ -32,8 +37,6 @@ export interface Entity {
3237
// AI and State Machine components
3338
stateMachine?: StateMachineComponent;
3439
behaviorTree?: BehaviorTreeComponent;
35-
// Biome-specific properties
36-
biomeType?: BiomeType;
3740
}
3841

3942
/**
@@ -56,6 +59,7 @@ export interface GameWorldState {
5659
height: number;
5760
};
5861
heightMap: number[][];
62+
biomeMap: BiomeType[][];
5963
viewportCenter: Vector2D;
6064
viewportZoom: number; // Zoom level (1.0 = normal, 2.0 = 2x zoom in, 0.5 = 2x zoom out)
6165
isPaused: boolean;

0 commit comments

Comments
 (0)