Feature/Gameloop enhancements (#17)
Reviewed-on: #17 Co-authored-by: Juan Sebastian Montoya <juansmm@outlook.com> Co-committed-by: Juan Sebastian Montoya <juansmm@outlook.com>
This commit is contained in:
parent
77bd5bb395
commit
323f0be900
15 changed files with 1629 additions and 37 deletions
|
|
@ -4,6 +4,9 @@ import { MeshComponent } from '../components/MeshComponent.js';
|
|||
import { Collidable } from '../components/Collidable.js';
|
||||
import { Health } from '../components/Health.js';
|
||||
import { Invincibility } from '../components/Invincibility.js';
|
||||
import { ObstacleType } from '../components/ObstacleType.js';
|
||||
import { CoinType } from '../components/CoinType.js';
|
||||
import { PowerUp } from '../components/PowerUp.js';
|
||||
import { PlayerTag, CoinTag, ObstacleTag, BoundaryConstrained } from '../components/Tags.js';
|
||||
import { GameConfig } from './GameConfig.js';
|
||||
|
||||
|
|
@ -65,19 +68,58 @@ export class EntityFactory {
|
|||
/**
|
||||
* Create a collectible coin entity
|
||||
* @param {number} [index=0] - Unique index for animation offset
|
||||
* @param {string} [type] - Optional coin type ('gold', 'silver', 'diamond', 'health')
|
||||
* @returns {EntityId} The coin entity ID
|
||||
*/
|
||||
createCoin(index = 0) {
|
||||
createCoin(index = 0, type = null) {
|
||||
const entity = this.world.createEntity();
|
||||
|
||||
// Create mesh
|
||||
const geometry = new window.THREE.SphereGeometry(0.3, 16, 16);
|
||||
// Determine coin type (weighted random if not specified)
|
||||
let coinType = type;
|
||||
if (!coinType) {
|
||||
const rand = Math.random();
|
||||
if (rand < 0.6) {
|
||||
coinType = 'gold'; // 60% gold
|
||||
} else if (rand < 0.85) {
|
||||
coinType = 'silver'; // 25% silver
|
||||
} else if (rand < 0.95) {
|
||||
coinType = 'diamond'; // 10% diamond
|
||||
} else {
|
||||
coinType = 'health'; // 5% health
|
||||
}
|
||||
}
|
||||
|
||||
const typeComponent = new CoinType(coinType);
|
||||
|
||||
// Create mesh with different colors/sizes based on type
|
||||
let size = 0.3;
|
||||
let color = 0xFFD700; // Gold
|
||||
let emissive = 0xFFD700;
|
||||
let emissiveIntensity = 0.3;
|
||||
|
||||
if (coinType === 'silver') {
|
||||
color = 0xC0C0C0;
|
||||
emissive = 0xC0C0C0;
|
||||
size = 0.25;
|
||||
} else if (coinType === 'diamond') {
|
||||
color = 0x00FFFF;
|
||||
emissive = 0x00FFFF;
|
||||
emissiveIntensity = 0.6;
|
||||
size = 0.4;
|
||||
} else if (coinType === 'health') {
|
||||
color = 0x00FF00;
|
||||
emissive = 0x00FF00;
|
||||
emissiveIntensity = 0.4;
|
||||
size = 0.35;
|
||||
}
|
||||
|
||||
const geometry = new window.THREE.SphereGeometry(size, 16, 16);
|
||||
const material = new window.THREE.MeshStandardMaterial({
|
||||
color: 0xFFD700,
|
||||
color: color,
|
||||
metalness: 0.8,
|
||||
roughness: 0.2,
|
||||
emissive: 0xFFD700,
|
||||
emissiveIntensity: 0.3
|
||||
emissive: emissive,
|
||||
emissiveIntensity: emissiveIntensity
|
||||
});
|
||||
const mesh = new window.THREE.Mesh(geometry, material);
|
||||
mesh.castShadow = true;
|
||||
|
|
@ -92,6 +134,7 @@ export class EntityFactory {
|
|||
this.world.addComponent(entity, new Transform(x, 0.5, z));
|
||||
this.world.addComponent(entity, new MeshComponent(mesh));
|
||||
this.world.addComponent(entity, new Collidable(0.8, 'coin'));
|
||||
this.world.addComponent(entity, typeComponent);
|
||||
this.world.addComponent(entity, new CoinTag(index));
|
||||
|
||||
return entity;
|
||||
|
|
@ -99,15 +142,42 @@ export class EntityFactory {
|
|||
|
||||
/**
|
||||
* Create an obstacle entity
|
||||
* @param {string} [type] - Optional obstacle type ('normal', 'fast', 'chasing', 'spinning')
|
||||
* @returns {EntityId} The obstacle entity ID
|
||||
*/
|
||||
createObstacle() {
|
||||
createObstacle(type = null) {
|
||||
const entity = this.world.createEntity();
|
||||
|
||||
// Create mesh
|
||||
// Determine obstacle type (weighted random if not specified)
|
||||
let obstacleType = type;
|
||||
if (!obstacleType) {
|
||||
const rand = Math.random();
|
||||
if (rand < 0.5) {
|
||||
obstacleType = 'normal';
|
||||
} else if (rand < 0.7) {
|
||||
obstacleType = 'fast';
|
||||
} else if (rand < 0.85) {
|
||||
obstacleType = 'chasing';
|
||||
} else {
|
||||
obstacleType = 'spinning';
|
||||
}
|
||||
}
|
||||
|
||||
const typeComponent = new ObstacleType(obstacleType);
|
||||
|
||||
// Create mesh with different colors based on type
|
||||
const geometry = new window.THREE.BoxGeometry(1.5, 2, 1.5);
|
||||
let color = 0xFF4500; // Default orange-red
|
||||
if (obstacleType === 'fast') {
|
||||
color = 0xFF0000; // Red
|
||||
} else if (obstacleType === 'chasing') {
|
||||
color = 0x8B0000; // Dark red
|
||||
} else if (obstacleType === 'spinning') {
|
||||
color = 0xFF6347; // Tomato
|
||||
}
|
||||
|
||||
const material = new window.THREE.MeshStandardMaterial({
|
||||
color: 0xFF4500,
|
||||
color: color,
|
||||
metalness: 0.3,
|
||||
roughness: 0.7
|
||||
});
|
||||
|
|
@ -123,11 +193,12 @@ export class EntityFactory {
|
|||
posZ = (Math.random() - 0.5) * (this.groundSize - 4);
|
||||
} while (Math.abs(posX) < 3 && Math.abs(posZ) < 3);
|
||||
|
||||
// Random velocity
|
||||
// Base velocity (will be modified by ObstacleSystem for different types)
|
||||
const baseSpeed = 0.05;
|
||||
const velocity = new Velocity(
|
||||
(Math.random() - 0.5) * 0.05,
|
||||
(Math.random() - 0.5) * baseSpeed * typeComponent.speedMultiplier,
|
||||
0,
|
||||
(Math.random() - 0.5) * 0.05
|
||||
(Math.random() - 0.5) * baseSpeed * typeComponent.speedMultiplier
|
||||
);
|
||||
|
||||
// Add components
|
||||
|
|
@ -135,12 +206,89 @@ export class EntityFactory {
|
|||
this.world.addComponent(entity, velocity);
|
||||
this.world.addComponent(entity, new MeshComponent(mesh));
|
||||
this.world.addComponent(entity, new Collidable(1.5, 'obstacle'));
|
||||
this.world.addComponent(entity, typeComponent);
|
||||
this.world.addComponent(entity, new ObstacleTag());
|
||||
this.world.addComponent(entity, new BoundaryConstrained(this.groundSize));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a power-up entity
|
||||
* @param {string} [type] - Optional power-up type ('speed', 'shield', 'multiplier', 'magnet')
|
||||
* @returns {EntityId} The power-up entity ID
|
||||
*/
|
||||
createPowerUp(type = null) {
|
||||
const entity = this.world.createEntity();
|
||||
|
||||
// Determine power-up type (random if not specified)
|
||||
let powerUpType = type;
|
||||
if (!powerUpType) {
|
||||
const rand = Math.random();
|
||||
if (rand < 0.25) {
|
||||
powerUpType = 'speed';
|
||||
} else if (rand < 0.5) {
|
||||
powerUpType = 'shield';
|
||||
} else if (rand < 0.75) {
|
||||
powerUpType = 'multiplier';
|
||||
} else {
|
||||
powerUpType = 'magnet';
|
||||
}
|
||||
}
|
||||
|
||||
// Get duration based on type
|
||||
let duration = 10;
|
||||
let color = 0x00FF00;
|
||||
let size = 0.4;
|
||||
|
||||
switch (powerUpType) {
|
||||
case 'speed':
|
||||
duration = GameConfig.POWERUP_DURATION_SPEED;
|
||||
color = 0x00FFFF; // Cyan
|
||||
break;
|
||||
case 'shield':
|
||||
duration = GameConfig.POWERUP_DURATION_SHIELD;
|
||||
color = 0x0000FF; // Blue
|
||||
break;
|
||||
case 'multiplier':
|
||||
duration = GameConfig.POWERUP_DURATION_MULTIPLIER;
|
||||
color = 0xFF00FF; // Magenta
|
||||
break;
|
||||
case 'magnet':
|
||||
duration = GameConfig.POWERUP_DURATION_MAGNET;
|
||||
color = 0xFFFF00; // Yellow
|
||||
break;
|
||||
}
|
||||
|
||||
const powerUpComponent = new PowerUp(powerUpType, duration);
|
||||
|
||||
// Create mesh
|
||||
const geometry = new window.THREE.OctahedronGeometry(size, 0);
|
||||
const material = new window.THREE.MeshStandardMaterial({
|
||||
color: color,
|
||||
metalness: 0.9,
|
||||
roughness: 0.1,
|
||||
emissive: color,
|
||||
emissiveIntensity: 0.5
|
||||
});
|
||||
const mesh = new window.THREE.Mesh(geometry, material);
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
this.scene.add(mesh);
|
||||
|
||||
// Random position
|
||||
const x = (Math.random() - 0.5) * (this.groundSize - 4);
|
||||
const z = (Math.random() - 0.5) * (this.groundSize - 4);
|
||||
|
||||
// Add components
|
||||
this.world.addComponent(entity, new Transform(x, 1, z));
|
||||
this.world.addComponent(entity, new MeshComponent(mesh));
|
||||
this.world.addComponent(entity, new Collidable(0.6, 'powerup'));
|
||||
this.world.addComponent(entity, powerUpComponent);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove entity and its mesh from scene
|
||||
* @param {EntityId} entityId - The entity to destroy
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue