Skip to content

Commit 05f0511

Browse files
committed
add bed
1 parent 59a5f1c commit 05f0511

File tree

5 files changed

+51
-40
lines changed

5 files changed

+51
-40
lines changed

assets/bedDouble.glb

22.8 KB
Binary file not shown.

client/public/assets/bedDouble.glb

22.8 KB
Binary file not shown.

client/src/game-client.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,18 @@ export class GameClient {
168168
this.scene.add(pole);
169169
this.worldObjects.push(pole);
170170

171+
// Load and place bed next to house (to the right side, 200 units from house center)
172+
WorldObjectFactory.loadBed(-300, -400)
173+
.then((bed) => {
174+
if (this.scene) {
175+
this.scene.add(bed);
176+
this.worldObjects.push(bed);
177+
}
178+
})
179+
.catch((error) => {
180+
console.error('Failed to load bed:', error);
181+
});
182+
171183
// Initialize height opacity manager for floor visibility controls
172184
this.heightOpacityManager = new HeightOpacityManager(this.worldObjects);
173185

client/src/world/WorldObjectFactory.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
* - Trees (procedural and simple)
77
* - Houses
88
* - Poles
9+
* - Furniture (loaded from GLB files)
910
*/
1011

1112
import * as THREE from 'three';
13+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
1214
import { Tree, TreePreset } from '@dgreenheck/ez-tree';
1315
import { HouseBuilder } from './HouseBuilder';
1416

@@ -155,4 +157,40 @@ export class WorldObjectFactory {
155157
group.position.set(x, 0, z);
156158
return group;
157159
}
160+
161+
/**
162+
* Loads a bed model from GLB file and places it at the specified position.
163+
* @param x - X position
164+
* @param z - Z position
165+
* @returns Promise that resolves to the loaded bed group
166+
*/
167+
public static async loadBed(x: number, z: number): Promise<THREE.Group> {
168+
const loader = new GLTFLoader();
169+
170+
return new Promise((resolve, reject) => {
171+
loader.load(
172+
'/assets/bedDouble.glb',
173+
(gltf) => {
174+
const bed = gltf.scene;
175+
176+
// Enable shadows on all meshes
177+
bed.traverse((child) => {
178+
if (child instanceof THREE.Mesh) {
179+
child.castShadow = true;
180+
child.receiveShadow = true;
181+
}
182+
});
183+
184+
// Position the bed
185+
bed.position.set(x, 0, z);
186+
187+
resolve(bed);
188+
},
189+
undefined,
190+
(error) => {
191+
reject(error);
192+
}
193+
);
194+
});
195+
}
158196
}

server/src/main.rs

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ mod physics;
2323
mod websocket;
2424

2525
use db::{create_pool, save_all_entities, set_game_time_minutes};
26-
use game::{Entity, EntityType, GameState, Position, Rotation};
26+
use game::GameState;
2727
use messages::GameMessage;
28-
use rand::Rng;
29-
use uuid::Uuid;
3028
use websocket::handle_websocket;
3129

3230
/// Application state shared across all request handlers.
@@ -55,7 +53,6 @@ pub struct AppState {
5553
/// - Entity persistence (every 60 seconds)
5654
/// - Physics simulation (60 FPS)
5755
/// - World state broadcasting (10 FPS)
58-
/// - Bouncy ball spawning (every 60 seconds)
5956
/// 4. HTTP/WebSocket server
6057
#[tokio::main]
6158
async fn main() -> anyhow::Result<()> {
@@ -171,42 +168,6 @@ async fn main() -> anyhow::Result<()> {
171168
}
172169
});
173170

174-
// Background task: Spawn a new bouncy ball at a random point on the ground every real-time minute
175-
// Ground is 10000x10000 units, so random positions are within ±5000 for x and z
176-
let game_state_for_ball_spawn = app_state.game.clone();
177-
tokio::spawn(async move {
178-
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(60));
179-
loop {
180-
interval.tick().await;
181-
// Generate random position on the ground
182-
// Create RNG inside loop to avoid Send issues
183-
let x = rand::thread_rng().gen_range(-5000.0..5000.0);
184-
let z = rand::thread_rng().gen_range(-5000.0..5000.0);
185-
// Ball starts at y=500 (5 meters) for visibility, physics will handle falling
186-
let y = 500.0;
187-
188-
// Create new ball entity
189-
let ball_id = format!("ball_{}", Uuid::new_v4());
190-
let ball_entity = Entity {
191-
id: ball_id.clone(),
192-
entity_type: EntityType::Ball,
193-
position: Position { x, y, z },
194-
rotation: Rotation {
195-
x: 0.0,
196-
y: 0.0,
197-
z: 0.0,
198-
},
199-
};
200-
201-
// Add entity to game state (this will also create the physics body)
202-
let mut game = game_state_for_ball_spawn.write().await;
203-
game.add_entity(ball_entity);
204-
drop(game);
205-
206-
tracing::info!("Spawned new bouncy ball at ({x}, {z})");
207-
}
208-
});
209-
210171
// Set up HTTP routes
211172
let app = Router::new()
212173
// WebSocket endpoint for game client connections

0 commit comments

Comments
 (0)