165 lines
4.2 KiB
JavaScript
165 lines
4.2 KiB
JavaScript
/**
|
|
* Railtrack Pro - World Management
|
|
* Handles grid system, track placement, and world state
|
|
* @author Railtrack Pro Development Team
|
|
*/
|
|
|
|
class World {
|
|
constructor(renderer) {
|
|
this.renderer = renderer;
|
|
this.gridSize = 100;
|
|
this.gridUnit = 1; // Grid unit size
|
|
this.tracks = [];
|
|
this.selectedType = null;
|
|
this.snapDistance = 0.1;
|
|
this.isPlacementMode = false;
|
|
|
|
this.initGrid();
|
|
}
|
|
|
|
/**
|
|
* Initialize grid system
|
|
*/
|
|
initGrid() {
|
|
this.gridHelper = this.renderer.gridHelper;
|
|
console.log('[World] Grid system initialized');
|
|
}
|
|
|
|
/**
|
|
* Snap position to nearest grid point
|
|
*/
|
|
snapToGrid(position) {
|
|
const x = Math.round(position.x / this.gridUnit) * this.gridUnit;
|
|
const z = Math.round(position.z / this.gridUnit) * this.gridUnit;
|
|
return new THREE.Vector3(x, 0, z);
|
|
}
|
|
|
|
/**
|
|
* Check if position is valid for track placement
|
|
*/
|
|
isValidPlacement(position) {
|
|
// Check bounds
|
|
if (Math.abs(position.x) > this.gridSize || Math.abs(position.z) > this.gridSize) {
|
|
return false;
|
|
}
|
|
|
|
// Check collisions with existing tracks
|
|
const positionSnap = this.snapToGrid(position);
|
|
const collisionBuffer = this.snapDistance * 2;
|
|
|
|
for (const track of this.tracks) {
|
|
if (track.mesh === null) continue;
|
|
|
|
const trackPos = track.mesh.position;
|
|
const distance = positionSnap.distanceTo(trackPos);
|
|
|
|
if (distance < collisionBuffer) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Add track piece to world
|
|
*/
|
|
addTrackPiece(type, position, rotation) {
|
|
if (!this.isValidPlacement(position)) {
|
|
console.warn('[World] Invalid placement position');
|
|
return null;
|
|
}
|
|
|
|
const track = new TrackPiece(type, position, rotation);
|
|
track.create(this.renderer.scene);
|
|
this.tracks.push(track);
|
|
|
|
// Update stats
|
|
Game.updateStats(this.tracks.length);
|
|
|
|
console.log(`[World] Added ${type} track at ${position.x.toFixed(1)}, ${position.z.toFixed(1)}`);
|
|
return track;
|
|
}
|
|
|
|
/**
|
|
* Remove track piece from world
|
|
*/
|
|
removeTrackPiece(trackPiece) {
|
|
const index = this.tracks.indexOf(trackPiece);
|
|
if (index > -1) {
|
|
this.tracks.splice(index, 1);
|
|
this.renderer.removeTrackPiece(trackPiece.mesh);
|
|
Game.updateStats(this.tracks.length);
|
|
Game.updateSelectedInfo(null);
|
|
|
|
console.log(`[World] Removed track piece`);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get track piece at position
|
|
*/
|
|
getTrackAtPosition(position) {
|
|
for (const track of this.tracks) {
|
|
if (track.mesh === null) continue;
|
|
|
|
const distance = position.distanceTo(track.mesh.position);
|
|
if (distance < this.snapDistance) {
|
|
return track;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Connect tracks at junctions
|
|
*/
|
|
connectTracks(track1, track2) {
|
|
// Simple connection logic
|
|
// In full implementation, check compatibility and adjust orientation
|
|
console.log('[World] Connecting tracks');
|
|
}
|
|
|
|
/**
|
|
* Clear all tracks
|
|
*/
|
|
clear() {
|
|
for (const track of this.tracks) {
|
|
this.removeTrackPiece(track);
|
|
}
|
|
this.tracks = [];
|
|
Game.updateStats(0);
|
|
console.log('[World] All tracks cleared');
|
|
}
|
|
|
|
/**
|
|
* Get world statistics
|
|
*/
|
|
getStats() {
|
|
const counts = {
|
|
straight: 0,
|
|
curved: 0,
|
|
junction: 0,
|
|
signal: 0
|
|
};
|
|
|
|
for (const track of this.tracks) {
|
|
if (counts[track.type] !== undefined) {
|
|
counts[track.type]++;
|
|
}
|
|
}
|
|
|
|
return {
|
|
total: this.tracks.length,
|
|
...counts
|
|
};
|
|
}
|
|
}
|
|
|
|
// Export for module usage
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = World;
|
|
}
|