|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #1a1a1a; } |
|
.controls { position: fixed; top: 10px; left: 10px; color: white; } |
|
button { margin: 5px; padding: 5px 10px; } |
|
#gameArea { cursor: crosshair; } |
|
.info-panel { |
|
position: fixed; |
|
top: 10px; |
|
right: 10px; |
|
color: white; |
|
background: rgba(0,0,0,0.7); |
|
padding: 15px; |
|
border-radius: 5px; |
|
font-family: Arial, sans-serif; |
|
} |
|
.score { |
|
font-size: 24px; |
|
font-weight: bold; |
|
margin-bottom: 10px; |
|
} |
|
.points-popup { |
|
position: absolute; |
|
color: #4CAF50; |
|
font-weight: bold; |
|
font-family: Arial, sans-serif; |
|
pointer-events: none; |
|
animation: floatUp 1s ease-out forwards; |
|
} |
|
@keyframes floatUp { |
|
0% { transform: translateY(0); opacity: 1; } |
|
100% { transform: translateY(-50px); opacity: 0; } |
|
} |
|
.drawing-guide { |
|
position: fixed; |
|
bottom: 10px; |
|
left: 10px; |
|
color: white; |
|
background: rgba(0,0,0,0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="controls"> |
|
<button onclick="addRobot()">Add Random Robot (+5 pts)</button> |
|
<button onclick="togglePause()">Pause/Play</button> |
|
</div> |
|
<div class="info-panel"> |
|
<div class="score">Score: <span id="scoreDisplay">0</span></div> |
|
<div>Robots: <span id="robotCount">0</span></div> |
|
</div> |
|
<div class="drawing-guide"> |
|
Click and drag to draw new robots (+5 pts). Collisions give +5 pts and growth! |
|
</div> |
|
<svg id="gameArea" width="800" height="600" style="background: #000;"> |
|
<rect width="800" height="600" fill="none" stroke="#333" stroke-width="4"/> |
|
<line id="drawingLine" stroke="white" stroke-width="2" stroke-dasharray="5,5" visibility="hidden"/> |
|
</svg> |
|
|
|
<script> |
|
const svg = document.getElementById('gameArea'); |
|
const drawingLine = document.getElementById('drawingLine'); |
|
const robots = []; |
|
let paused = false; |
|
let isDrawing = false; |
|
let startX, startY; |
|
let score = 0; |
|
|
|
function updateScore(points, x, y) { |
|
score += points; |
|
document.getElementById('scoreDisplay').textContent = score; |
|
document.getElementById('robotCount').textContent = robots.length; |
|
|
|
|
|
const popup = document.createElement('div'); |
|
popup.className = 'points-popup'; |
|
popup.textContent = `+${points}`; |
|
popup.style.left = `${x}px`; |
|
popup.style.top = `${y}px`; |
|
document.body.appendChild(popup); |
|
|
|
|
|
setTimeout(() => popup.remove(), 1000); |
|
} |
|
|
|
class Robot { |
|
constructor(x, y, speed, direction, length) { |
|
this.segments = []; |
|
this.speed = speed || 2 + Math.random() * 2; |
|
this.direction = direction || Math.random() * Math.PI * 2; |
|
this.length = length || 5 + Math.floor(Math.random() * 5); |
|
this.color = `hsl(${Math.random() * 360}, 80%, 50%)`; |
|
this.x = x || Math.random() * 700 + 50; |
|
this.y = y || Math.random() * 500 + 50; |
|
|
|
this.createSegments(); |
|
} |
|
|
|
createSegments() { |
|
|
|
this.segments.forEach(seg => seg.element.remove()); |
|
this.segments = []; |
|
|
|
|
|
for (let i = 0; i < this.length; i++) { |
|
const segment = document.createElementNS("http://www.w3.org/2000/svg", "circle"); |
|
segment.setAttribute("r", "8"); |
|
segment.setAttribute("fill", this.color); |
|
svg.appendChild(segment); |
|
this.segments.push({ |
|
element: segment, |
|
x: this.x, |
|
y: this.y |
|
}); |
|
} |
|
} |
|
|
|
grow() { |
|
this.length += 1; |
|
this.createSegments(); |
|
} |
|
|
|
update() { |
|
|
|
this.x += Math.cos(this.direction) * this.speed; |
|
this.y += Math.sin(this.direction) * this.speed; |
|
|
|
|
|
if (this.x < 10 || this.x > 790) { |
|
this.direction = Math.PI - this.direction; |
|
this.mutate(); |
|
} |
|
if (this.y < 10 || this.y > 590) { |
|
this.direction = -this.direction; |
|
this.mutate(); |
|
} |
|
|
|
|
|
for (let i = this.segments.length - 1; i > 0; i--) { |
|
this.segments[i].x = this.segments[i - 1].x; |
|
this.segments[i].y = this.segments[i - 1].y; |
|
} |
|
this.segments[0].x = this.x; |
|
this.segments[0].y = this.y; |
|
|
|
|
|
this.segments.forEach(segment => { |
|
segment.element.setAttribute("cx", segment.x); |
|
segment.element.setAttribute("cy", segment.y); |
|
}); |
|
} |
|
|
|
mutate() { |
|
|
|
this.speed = Math.max(1, Math.min(6, this.speed + (Math.random() - 0.5))); |
|
this.color = `hsl(${Math.random() * 360}, 80%, 50%)`; |
|
this.segments.forEach(segment => { |
|
segment.element.setAttribute("fill", this.color); |
|
}); |
|
} |
|
|
|
checkCollision(other) { |
|
const dx = this.x - other.x; |
|
const dy = this.y - other.y; |
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
if (distance < 16) { |
|
|
|
const angle = Math.atan2(dy, dx); |
|
this.direction = angle + Math.PI / 2; |
|
other.direction = angle - Math.PI / 2; |
|
|
|
|
|
this.grow(); |
|
other.grow(); |
|
this.mutate(); |
|
other.mutate(); |
|
|
|
|
|
const svgRect = svg.getBoundingClientRect(); |
|
const popupX = svgRect.left + this.x; |
|
const popupY = svgRect.top + this.y; |
|
updateScore(5, popupX, popupY); |
|
} |
|
} |
|
} |
|
|
|
|
|
svg.addEventListener('mousedown', (e) => { |
|
const rect = svg.getBoundingClientRect(); |
|
startX = e.clientX - rect.left; |
|
startY = e.clientY - rect.top; |
|
isDrawing = true; |
|
|
|
drawingLine.setAttribute('x1', startX); |
|
drawingLine.setAttribute('y1', startY); |
|
drawingLine.setAttribute('x2', startX); |
|
drawingLine.setAttribute('y2', startY); |
|
drawingLine.setAttribute('visibility', 'visible'); |
|
}); |
|
|
|
svg.addEventListener('mousemove', (e) => { |
|
if (isDrawing) { |
|
const rect = svg.getBoundingClientRect(); |
|
const currentX = e.clientX - rect.left; |
|
const currentY = e.clientY - rect.top; |
|
|
|
drawingLine.setAttribute('x2', currentX); |
|
drawingLine.setAttribute('y2', currentY); |
|
} |
|
}); |
|
|
|
svg.addEventListener('mouseup', (e) => { |
|
if (isDrawing) { |
|
const rect = svg.getBoundingClientRect(); |
|
const endX = e.clientX - rect.left; |
|
const endY = e.clientY - rect.top; |
|
|
|
const dx = endX - startX; |
|
const dy = endY - startY; |
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
const direction = Math.atan2(dy, dx); |
|
|
|
const speed = Math.min(6, distance / 50); |
|
const length = Math.max(3, Math.min(12, Math.floor(distance / 30))); |
|
robots.push(new Robot(startX, startY, speed, direction, length)); |
|
|
|
|
|
updateScore(5, e.clientX, e.clientY); |
|
|
|
drawingLine.setAttribute('visibility', 'hidden'); |
|
isDrawing = false; |
|
} |
|
}); |
|
|
|
svg.addEventListener('mouseleave', () => { |
|
if (isDrawing) { |
|
drawingLine.setAttribute('visibility', 'hidden'); |
|
isDrawing = false; |
|
} |
|
}); |
|
|
|
function addRobot() { |
|
const robot = new Robot(); |
|
robots.push(robot); |
|
|
|
const svgRect = svg.getBoundingClientRect(); |
|
updateScore(5, svgRect.left + robot.x, svgRect.top + robot.y); |
|
} |
|
|
|
function togglePause() { |
|
paused = !paused; |
|
} |
|
|
|
function update() { |
|
if (!paused) { |
|
robots.forEach(robot => robot.update()); |
|
|
|
for (let i = 0; i < robots.length; i++) { |
|
for (let j = i + 1; j < robots.length; j++) { |
|
robots[i].checkCollision(robots[j]); |
|
} |
|
} |
|
} |
|
requestAnimationFrame(update); |
|
} |
|
|
|
|
|
for (let i = 0; i < 3; i++) { |
|
addRobot(); |
|
} |
|
|
|
update(); |
|
</script> |
|
</body> |
|
</html> |