awacke1's picture
Create index.html
229648c verified
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chofko's Diverse Ecosystem Simulator</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
<style>
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
.controls button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
#score {
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: white;
background-color: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 5px;
}
</style>
</head>
<body>
<a-scene>
<a-assets>
<img id="sky" src="/api/placeholder/1024/512" alt="surrealist sky">
</a-assets>
<a-sky src="#sky"></a-sky>
<a-plane position="0 0 -4" rotation="-90 0 0" width="100" height="100" color="#7BC8A4"></a-plane>
<a-entity id="entities"></a-entity>
<a-entity id="camera" camera look-controls position="0 40 0" rotation="-90 0 0"></a-entity>
</a-scene>
<div id="score">Score: 0</div>
<div class="controls">
<button onmousedown="startMove('left')" onmouseup="stopMove('left')" ontouchstart="startMove('left')" ontouchend="stopMove('left')">Left</button>
<button onmousedown="startMove('right')" onmouseup="stopMove('right')" ontouchstart="startMove('right')" ontouchend="stopMove('right')">Right</button>
<button onmousedown="startMove('up')" onmouseup="stopMove('up')" ontouchstart="startMove('up')" ontouchend="stopMove('up')">Up</button>
<button onmousedown="startMove('down')" onmouseup="stopMove('down')" ontouchstart="startMove('down')" ontouchend="stopMove('down')">Down</button>
<button onclick="toggleSpeed()">Toggle Speed</button>
</div>
<script>
const entitiesEl = document.querySelector('#entities');
const entities = [];
const initialEntityCount = 100;
let score = 0;
const maxEntities = 300;
let isSlowMode = false;
const primitiveTypes = ['a-sphere', 'a-box', 'a-cone', 'a-cylinder', 'a-tetrahedron', 'a-octahedron'];
const typeColors = {
'a-sphere': ['#FF69B4', '#FF1493'],
'a-box': ['#4169E1', '#1E90FF'],
'a-cone': ['#32CD32', '#00FF00'],
'a-cylinder': ['#FFD700', '#FFA500'],
'a-tetrahedron': ['#8A2BE2', '#9400D3'],
'a-octahedron': ['#FF4500', '#FF6347']
};
class Entity {
constructor(x, z, isPlayer = false, type = null, gender = null, radius = null) {
this.isPlayer = isPlayer;
this.type = type || (isPlayer ? 'a-sphere' : primitiveTypes[Math.floor(Math.random() * primitiveTypes.length)]);
this.gender = gender || (Math.random() < 0.5 ? 'male' : 'female');
this.el = document.createElement(this.type);
this.radius = radius || (isPlayer ? 1.5 : 0.5);
this.color = isPlayer ? '#FF00FF' : typeColors[this.type][this.gender === 'male' ? 0 : 1];
if (this.type === 'a-sphere' || this.type === 'a-cylinder') {
this.el.setAttribute('radius', this.radius);
} else {
this.el.setAttribute('width', this.radius * 2);
this.el.setAttribute('height', this.radius * 2);
this.el.setAttribute('depth', this.radius * 2);
}
this.el.setAttribute('color', this.color);
this.el.setAttribute('position', {x: x, y: this.radius, z: z});
entitiesEl.appendChild(this.el);
this.velocity = {
x: isPlayer ? 0 : (Math.random() - 0.5) * 0.2,
z: isPlayer ? 0 : (Math.random() - 0.5) * 0.2
};
this.acceleration = { x: 0, z: 0 };
if (!isPlayer) {
entities.push(this);
}
if (isPlayer) {
// Add a text label above the player
this.label = document.createElement('a-text');
this.label.setAttribute('value', 'PLAYER');
this.label.setAttribute('align', 'center');
this.label.setAttribute('position', {x: 0, y: this.radius * 2, z: 0});
this.label.setAttribute('scale', {x: 5, y: 5, z: 5});
this.label.setAttribute('color', '#FFFFFF');
this.el.appendChild(this.label);
}
}
update(deltaTime) {
this.velocity.x += this.acceleration.x * deltaTime;
this.velocity.z += this.acceleration.z * deltaTime;
this.velocity.x *= 0.99;
this.velocity.z *= 0.99;
const position = this.el.getAttribute('position');
position.x += this.velocity.x * deltaTime;
position.z += this.velocity.z * deltaTime;
if (Math.abs(position.x) > 50) {
this.velocity.x *= -1;
position.x = Math.sign(position.x) * 50;
}
if (Math.abs(position.z) > 50) {
this.velocity.z *= -1;
position.z = Math.sign(position.z) * 50;
}
this.el.setAttribute('position', position);
this.acceleration = { x: 0, z: 0 };
}
applyForce(force) {
this.acceleration.x += force.x / this.radius;
this.acceleration.z += force.z / this.radius;
}
grow(amount) {
this.radius += amount;
if (this.type === 'a-sphere' || this.type === 'a-cylinder') {
this.el.setAttribute('radius', this.radius);
} else {
this.el.setAttribute('width', this.radius * 2);
this.el.setAttribute('height', this.radius * 2);
this.el.setAttribute('depth', this.radius * 2);
}
const position = this.el.getAttribute('position');
position.y = this.radius;
this.el.setAttribute('position', position);
if (this.isPlayer && this.label) {
this.label.setAttribute('position', {x: 0, y: this.radius * 2, z: 0});
}
}
remove() {
entitiesEl.removeChild(this.el);
const index = entities.indexOf(this);
if (index > -1) {
entities.splice(index, 1);
}
}
}
const player = new Entity(0, 0, true);
let moveDirection = { x: 0, z: 0 };
function createEntities() {
for (let i = 0; i < initialEntityCount; i++) {
new Entity(
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100
);
}
}
function spawnNewEntity() {
if (entities.length < maxEntities && Math.random() < 0.02) {
new Entity(
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100
);
}
}
function startMove(direction) {
switch(direction) {
case 'left': moveDirection.x = -1; break;
case 'right': moveDirection.x = 1; break;
case 'up': moveDirection.z = -1; break;
case 'down': moveDirection.z = 1; break;
}
}
function stopMove(direction) {
switch(direction) {
case 'left': case 'right': moveDirection.x = 0; break;
case 'up': case 'down': moveDirection.z = 0; break;
}
}
function toggleSpeed() {
isSlowMode = !isSlowMode;
}
function canEat(entity1, entity2) {
const typeIndex = primitiveTypes.indexOf(entity1.type);
const otherTypeIndex = primitiveTypes.indexOf(entity2.type);
return (typeIndex + 1) % primitiveTypes.length === otherTypeIndex;
}
function tryMating(entity1, entity2) {
if (entity1.type === entity2.type && entity1.gender !== entity2.gender && Math.random() < 0.1) {
const childRadius = (entity1.radius + entity2.radius) / 2 * 0.8;
new Entity(
(entity1.el.getAttribute('position').x + entity2.el.getAttribute('position').x) / 2,
(entity1.el.getAttribute('position').z + entity2.el.getAttribute('position').z) / 2,
false,
entity1.type,
Math.random() < 0.5 ? 'male' : 'female',
childRadius
);
}
}
function checkCollisions() {
const playerPosition = player.el.getAttribute('position');
for (let i = 0; i < entities.length; i++) {
const entity = entities[i];
const entityPosition = entity.el.getAttribute('position');
const dx = playerPosition.x - entityPosition.x;
const dz = playerPosition.z - entityPosition.z;
const distance = Math.sqrt(dx * dx + dz * dz);
if (distance < player.radius + entity.radius) {
if (player.radius > entity.radius * 1.5 && canEat(player, entity)) {
player.grow(entity.radius * 0.02); // Further reduced growth rate
entity.remove();
score += 1;
updateScore();
i--;
} else {
const angle = Math.atan2(dz, dx);
const force = 0.01 / distance;
player.applyForce({ x: -Math.cos(angle) * force, z: -Math.sin(angle) * force });
entity.applyForce({ x: Math.cos(angle) * force, z: Math.sin(angle) * force });
}
}
for (let j = i + 1; j < entities.length; j++) {
const otherEntity = entities[j];
const otherPosition = otherEntity.el.getAttribute('position');
const entityDx = entityPosition.x - otherPosition.x;
const entityDz = entityPosition.z - otherPosition.z;
const entityDistance = Math.sqrt(entityDx * entityDx + entityDz * entityDz);
if (entityDistance < entity.radius + otherEntity.radius) {
if (entity.radius > otherEntity.radius * 1.2 && canEat(entity, otherEntity)) {
entity.grow(otherEntity.radius * 0.1);
otherEntity.remove();
j--;
} else if (otherEntity.radius > entity.radius * 1.2 && canEat(otherEntity, entity)) {
otherEntity.grow(entity.radius * 0.1);
entity.remove();
i--;
break;
} else {
tryMating(entity, otherEntity);
const angle = Math.atan2(entityDz, entityDx);
const force = 0.005 / entityDistance;
entity.applyForce({ x: -Math.cos(angle) * force, z: -Math.sin(angle) * force });
otherEntity.applyForce({ x: Math.cos(angle) * force, z: Math.sin(angle) * force });
}
}
}
}
}
function updateScore() {
document.getElementById('score').textContent = `Score: ${score}`;
}
let lastTime = 0;
function gameLoop(timestamp) {
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
const speedFactor = isSlowMode ? 0.5 : 1;
player.applyForce({
x: moveDirection.x * 0.0005 * speedFactor,
z: moveDirection.z * 0.0005 * speedFactor
});
entities.forEach(e => e.update(deltaTime * speedFactor));
player.update(deltaTime * speedFactor);
checkCollisions();
spawnNewEntity();
requestAnimationFrame(gameLoop);
}
document.querySelector('a-scene').addEventListener('loaded', function () {
createEntities();
requestAnimationFrame(gameLoop);
});
document.addEventListener('keydown', (event) => {
switch(event.key) {
case 'ArrowLeft': startMove('left'); break;
case 'ArrowRight': startMove('right'); break;
case 'ArrowUp': startMove('up'); break;
case 'ArrowDown': startMove('down'); break;
case 'Shift': toggleSpeed(); break;
}
});
document.addEventListener('keyup', (event) => {
switch(event.key) {
case 'ArrowLeft': stopMove('left'); break;
case 'ArrowRight': stopMove('right'); break;
case 'ArrowUp': stopMove('up'); break;
case 'ArrowDown': stopMove('down'); break;
}
});
</script>
</body>
</html>