Skip to content

Commit be4cafe

Browse files
committed
change units to meters
1 parent fc83c48 commit be4cafe

File tree

15 files changed

+277
-209
lines changed

15 files changed

+277
-209
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ node_modules/
88
dist/
99
*.log
1010

11+
# Local dev logs
12+
.devlogs/
13+
1114
# Environment
1215
.env
1316
.env.local

client/src/camera/CameraController.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ interface CameraRotation {
3232
export class CameraController {
3333
private readonly camera: THREE.PerspectiveCamera;
3434
private rotation: CameraRotation = { theta: 0, phi: 0.5 };
35-
private distance: number = 1000;
35+
private distance: number = 10;
3636
private anchored: boolean = false;
3737
private focusPoint: THREE.Vector3 | null = null;
3838

3939
// Configuration
40-
private readonly minDistance: number = 200;
41-
private readonly maxDistance: number = 5000;
40+
private readonly minDistance: number = 2;
41+
private readonly maxDistance: number = 50;
4242
private readonly rotationSpeed: number = 0.02;
43-
private readonly freeMoveSpeed: number = 50;
43+
private readonly freeMoveSpeed: number = 0.5;
4444

4545
constructor(aspectRatio: number) {
46-
this.camera = new THREE.PerspectiveCamera(75, aspectRatio, 10, 100000);
47-
this.camera.position.set(0, 500, 1000);
46+
this.camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
47+
this.camera.position.set(0, 5, 10);
4848
this.camera.lookAt(0, 0, 0);
4949
}
5050

@@ -147,7 +147,7 @@ export class CameraController {
147147
this.camera.position.set(targetX + x, targetY + y, targetZ + z);
148148

149149
// Look at the target point
150-
const target = new THREE.Vector3(targetX, targetY + 150, targetZ);
150+
const target = new THREE.Vector3(targetX, targetY + 1.5, targetZ);
151151
this.camera.lookAt(target);
152152
}
153153

@@ -158,6 +158,6 @@ export class CameraController {
158158

159159
public setInitialPosition(player: Player): void {
160160
const pos = player.mesh.position;
161-
this.camera.position.set(pos.x, pos.y + 500, pos.z + 1000);
161+
this.camera.position.set(pos.x, pos.y + 5, pos.z + 10);
162162
}
163163
}

client/src/entities/Entity.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class Entity {
8888

8989
private createBallMesh(): THREE.Mesh {
9090
// Create a bouncy ball - a sphere with a bright color
91-
const geometry = new THREE.SphereGeometry(50, 32, 32); // 50 unit radius (0.5m in game units)
91+
const geometry = new THREE.SphereGeometry(0.5, 32, 32); // 0.5m radius
9292
const material = new THREE.MeshStandardMaterial({
9393
color: 0xff0000, // Bright red
9494
roughness: 0.3,

client/src/entities/Player.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as THREE from 'three';
88

99
/**
1010
* 3D position in the game world.
11-
* Units are in centimeters (1 unit = 1 cm).
11+
* Units are in meters (1 unit = 1 m).
1212
*/
1313
export interface Position {
1414
/** X coordinate (horizontal, east-west) */
@@ -269,46 +269,46 @@ export class Player {
269269
const group = new THREE.Group();
270270

271271
// Body (torso)
272-
const bodyGeometry = new THREE.BoxGeometry(60, 80, 40);
272+
const bodyGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.4);
273273
const bodyMaterial = new THREE.MeshStandardMaterial({ color: 0x4a90e2 });
274274
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
275-
body.position.y = 110;
275+
body.position.y = 1.1;
276276
body.castShadow = true;
277277
group.add(body);
278278

279279
// Head
280-
const headGeometry = new THREE.BoxGeometry(40, 40, 40);
280+
const headGeometry = new THREE.BoxGeometry(0.4, 0.4, 0.4);
281281
const headMaterial = new THREE.MeshStandardMaterial({ color: 0xffdbac });
282282
const head = new THREE.Mesh(headGeometry, headMaterial);
283-
head.position.y = 170;
283+
head.position.y = 1.7;
284284
head.castShadow = true;
285285
group.add(head);
286286

287287
// Legs
288-
const legGeometry = new THREE.BoxGeometry(20, 70, 20);
288+
const legGeometry = new THREE.BoxGeometry(0.2, 0.7, 0.2);
289289
const legMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
290290

291291
const leftLeg = new THREE.Mesh(legGeometry, legMaterial);
292-
leftLeg.position.set(-15, 35, 0);
292+
leftLeg.position.set(-0.15, 0.35, 0);
293293
leftLeg.castShadow = true;
294294
group.add(leftLeg);
295295

296296
const rightLeg = new THREE.Mesh(legGeometry, legMaterial);
297-
rightLeg.position.set(15, 35, 0);
297+
rightLeg.position.set(0.15, 0.35, 0);
298298
rightLeg.castShadow = true;
299299
group.add(rightLeg);
300300

301301
// Arms
302-
const armGeometry = new THREE.BoxGeometry(20, 70, 20);
302+
const armGeometry = new THREE.BoxGeometry(0.2, 0.7, 0.2);
303303
const armMaterial = new THREE.MeshStandardMaterial({ color: 0x4a90e2 });
304304

305305
const leftArm = new THREE.Mesh(armGeometry, armMaterial);
306-
leftArm.position.set(-40, 110, 0);
306+
leftArm.position.set(-0.4, 1.1, 0);
307307
leftArm.castShadow = true;
308308
group.add(leftArm);
309309

310310
const rightArm = new THREE.Mesh(armGeometry, armMaterial);
311-
rightArm.position.set(40, 110, 0);
311+
rightArm.position.set(0.4, 1.1, 0);
312312
rightArm.castShadow = true;
313313
group.add(rightArm);
314314

@@ -329,8 +329,8 @@ export class Player {
329329
const texture = new THREE.CanvasTexture(canvas);
330330
const spriteMaterial = new THREE.SpriteMaterial({ map: texture });
331331
const sprite = new THREE.Sprite(spriteMaterial);
332-
sprite.position.y = 250;
333-
sprite.scale.set(200, 50, 100);
332+
sprite.position.y = 2.5;
333+
sprite.scale.set(2.0, 0.5, 1.0);
334334
group.add(sprite);
335335

336336
// Activity info box (above name label)
@@ -345,8 +345,8 @@ export class Player {
345345
const activityTexture = new THREE.CanvasTexture(activityCanvas);
346346
const activitySpriteMaterial = new THREE.SpriteMaterial({ map: activityTexture });
347347
const activitySprite = new THREE.Sprite(activitySpriteMaterial);
348-
activitySprite.position.y = 310;
349-
activitySprite.scale.set(240, 36, 100);
348+
activitySprite.position.y = 3.1;
349+
activitySprite.scale.set(2.4, 0.36, 1.0);
350350
group.add(activitySprite);
351351

352352
return { group, leftLeg, rightLeg, leftArm, rightArm, activityCanvas, activityTexture };

client/src/environment/DayNightCycle.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class DayNightCycle {
2525
private readonly moonMesh: THREE.Mesh;
2626

2727
// Configuration
28-
private readonly sunRadius: number = 5000;
28+
private readonly sunRadius: number = 50;
2929
private readonly dayColor = new THREE.Color(0x87ceeb);
3030
private readonly sunsetColor = new THREE.Color(0xff4500);
3131
private readonly nightColor = new THREE.Color(0x000022);
@@ -88,28 +88,28 @@ export class DayNightCycle {
8888

8989
private createSunLight(): THREE.DirectionalLight {
9090
const light = new THREE.DirectionalLight(0xffffff, 1.0);
91-
light.position.set(0, 10000, 0);
91+
light.position.set(0, 100, 0);
9292
light.castShadow = true;
9393

9494
// Shadow camera setup
95-
light.shadow.camera.left = -5000;
96-
light.shadow.camera.right = 5000;
97-
light.shadow.camera.top = 5000;
98-
light.shadow.camera.bottom = -5000;
95+
light.shadow.camera.left = -50;
96+
light.shadow.camera.right = 50;
97+
light.shadow.camera.top = 50;
98+
light.shadow.camera.bottom = -50;
9999
light.shadow.mapSize.width = 2048;
100100
light.shadow.mapSize.height = 2048;
101101

102102
return light;
103103
}
104104

105105
private createSunMesh(): THREE.Mesh {
106-
const geometry = new THREE.SphereGeometry(200, 32, 32);
106+
const geometry = new THREE.SphereGeometry(2, 32, 32);
107107
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
108108
return new THREE.Mesh(geometry, material);
109109
}
110110

111111
private createMoonMesh(): THREE.Mesh {
112-
const geometry = new THREE.SphereGeometry(150, 32, 32);
112+
const geometry = new THREE.SphereGeometry(1.5, 32, 32);
113113
const material = new THREE.MeshBasicMaterial({ color: 0xcccccc });
114114
return new THREE.Mesh(geometry, material);
115115
}

client/src/game-client.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,31 +145,32 @@ export class GameClient {
145145

146146
// Initialize random movement controller
147147
// Movement configuration (scaled for 60x game time)
148-
// 6000 units/game minute = 100 units/frame at 60 FPS
149-
// Lawn boundaries (ground size 10000, so half = 5000, minus margin for player body)
148+
// Lawn boundaries (ground size 100m, so half = 50m, minus margin for player body)
150149
this.randomMovement = new RandomMovementController({
151-
moveSpeed: 100,
150+
moveSpeed: 1,
152151
rotationSpeed: 0.2,
153152
bounds: {
154-
minX: -4970,
155-
maxX: 4970,
156-
minZ: -4970,
157-
maxZ: 4970
153+
minX: -49.7,
154+
maxX: 49.7,
155+
minZ: -49.7,
156+
maxZ: 49.7
158157
}
159158
});
160159

161160
// Create world objects
162-
const house = WorldObjectFactory.createHouse(-600, -400);
161+
const house = WorldObjectFactory.createHouse(-6, -4);
163162
this.scene.add(house);
164163
this.worldObjects.push(house);
165164

166-
// Pole next to house (100 units to the right)
167-
const pole = WorldObjectFactory.createPole(-500, -400);
165+
// Pole next to house (~1m to the right)
166+
const pole = WorldObjectFactory.createPole(-5, -4);
168167
this.scene.add(pole);
169168
this.worldObjects.push(pole);
170169

171-
// Load and place bed at (2500, 2500)
172-
WorldObjectFactory.loadBed(2500, 2500)
170+
// Load and place bed near the house so it's immediately visible.
171+
// House is centered at (-6, -4) with a 12m x 10m footprint (units are meters).
172+
// Place the bed on the first-floor level (foundationHeight ~ 0.4m, floor at ~0.41m).
173+
WorldObjectFactory.loadBed(-7.5, -2.5, 0.42)
173174
.then((bed) => {
174175
if (this.scene) {
175176
this.scene.add(bed);
@@ -212,7 +213,7 @@ export class GameClient {
212213
// Height-based opacity: 1-9 hide objects above (n * 3m), 0 resets
213214
if (key >= '1' && key <= '9') {
214215
const level = parseInt(key, 10);
215-
const heightThreshold = level * 300; // 300cm = 3m per level
216+
const heightThreshold = level * 3; // 3m per level
216217
this.heightOpacityManager?.setHeightOpacity(heightThreshold);
217218
} else if (key === '0') {
218219
this.heightOpacityManager?.setHeightOpacity(null); // Reset to fully opaque

client/src/world/HeightOpacityManager.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as THREE from 'three';
22

33
// Floor height constants (matching WorldObjectFactory/HouseBuilder)
4-
const FOUNDATION_HEIGHT = 40;
5-
const FLOOR_HEIGHT = 270;
6-
const FLOOR1_TOP = FOUNDATION_HEIGHT + FLOOR_HEIGHT; // 310cm
7-
const FLOOR2_TOP = FOUNDATION_HEIGHT + FLOOR_HEIGHT * 2; // 580cm
4+
// Units: meters
5+
const FOUNDATION_HEIGHT = 0.4;
6+
const FLOOR_HEIGHT = 2.7;
7+
const FLOOR1_TOP = FOUNDATION_HEIGHT + FLOOR_HEIGHT; // 3.1m
8+
const FLOOR2_TOP = FOUNDATION_HEIGHT + FLOOR_HEIGHT * 2; // 5.8m
89

910
const HIDDEN_OPACITY = 0.15;
1011
const VISIBLE_OPACITY = 1.0;
@@ -25,7 +26,7 @@ export class HeightOpacityManager {
2526
* Sets opacity for objects based on height threshold.
2627
* Objects above the threshold become semi-transparent.
2728
* Doors and roof elements are made transparent along with walls at the same floor level.
28-
* @param heightThreshold - Height in cm above which objects become transparent. null = fully opaque.
29+
* @param heightThreshold - Height in meters above which objects become transparent. null = fully opaque.
2930
*/
3031
public setHeightOpacity(heightThreshold: number | null): void {
3132
for (const obj of this.worldObjects) {
@@ -45,8 +46,8 @@ export class HeightOpacityManager {
4546

4647
if (occlusionType === 'door' && floorLevel !== undefined) {
4748
// Doors become transparent when their floor's walls would be transparent
48-
// Floor 1 doors: transparent when threshold < floor1Top (310cm)
49-
// Floor 2 doors: transparent when threshold < floor2Top (580cm)
49+
// Floor 1 doors: transparent when threshold < floor1Top (3.1m)
50+
// Floor 2 doors: transparent when threshold < floor2Top (5.8m)
5051
const floorTop = floorLevel === 1 ? FLOOR1_TOP : FLOOR2_TOP;
5152
targetOpacity = heightThreshold < floorTop ? HIDDEN_OPACITY : VISIBLE_OPACITY;
5253
} else if (occlusionType === 'roof') {

client/src/world/HouseBuilder.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
* - Roof with chimney
99
* - Porch
1010
*
11-
* All dimensions are in centimeters (1 unit = 1 cm).
11+
* World units are meters (1 unit = 1 m).
12+
*
13+
* NOTE: This builder is currently authored in centimeters for readability of
14+
* traditional architectural dimensions, then the final group is scaled by 0.01
15+
* to convert to meters.
1216
*/
1317

1418
import * as THREE from 'three';
@@ -22,7 +26,7 @@ import * as THREE from 'three';
2226
export class HouseBuilder {
2327
private readonly group: THREE.Group;
2428

25-
// Realistic house dimensions (1 unit = 1 cm)
29+
// Realistic house dimensions (authored in centimeters, converted to meters via group scale)
2630
// Total footprint: 12m x 10m (1200cm x 1000cm)
2731
private readonly width = 1200; // 12 meters wide
2832
private readonly depth = 1000; // 10 meters deep
@@ -94,6 +98,9 @@ export class HouseBuilder {
9498
this.addChimney();
9599
this.addPorch();
96100

101+
// Convert authored-centimeter dimensions to world meters.
102+
this.group.scale.set(0.01, 0.01, 0.01);
103+
97104
return this.group;
98105
}
99106

0 commit comments

Comments
 (0)