Mystery Game #18
← Back to Games List
// Space Navigation Game
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const navigator = {
x: canvas.width / 2,
y: canvas.height / 2,
radius: 15,
angle: 0,
dx: 0,
dy: 0,
thrust: 0.5,
rotationSpeed: 0.1,
isRotatingLeft: false,
isRotatingRight: false,
isThrusting: false
};
const projectiles = [];
const obstacles = [];
let points = 0;
let isActive = true;
function createObstacle() {
const angle = Math.random() * Math.PI * 2;
const distance = Math.max(canvas.width, canvas.height);
obstacles.push({
x: canvas.width/2 + Math.cos(angle) * distance,
y: canvas.height/2 + Math.sin(angle) * distance,
dx: Math.random() * 4 - 2,
dy: Math.random() * 4 - 2,
radius: 20 + Math.random() * 20,
vertices: 8 + Math.floor(Math.random() * 4),
rotation: Math.random() * Math.PI * 2,
rotationSpeed: (Math.random() - 0.5) * 0.1
});
}
function shoot() {
projectiles.push({
x: navigator.x + Math.cos(navigator.angle) * navigator.radius,
y: navigator.y + Math.sin(navigator.angle) * navigator.radius,
dx: Math.cos(navigator.angle) * 7 + navigator.dx,
dy: Math.sin(navigator.angle) * 7 + navigator.dy,
lifetime: 60
});
}
function updateGame() {
if (!isActive) return;
// Update navigator
if (navigator.isRotatingLeft) navigator.angle -= navigator.rotationSpeed;
if (navigator.isRotatingRight) navigator.angle += navigator.rotationSpeed;
if (navigator.isThrusting) {
navigator.dx += Math.cos(navigator.angle) * navigator.thrust;
navigator.dy += Math.sin(navigator.angle) * navigator.thrust;
}
navigator.x += navigator.dx;
navigator.y += navigator.dy;
// Wrap around screen
if (navigator.x < 0) navigator.x = canvas.width;
if (navigator.x > canvas.width) navigator.x = 0;
if (navigator.y < 0) navigator.y = canvas.height;
if (navigator.y > canvas.height) navigator.y = 0;
// Update projectiles
for (let i = projectiles.length - 1; i >= 0; i--) {
const p = projectiles[i];
p.x += p.dx;
p.y += p.dy;
p.lifetime--;
// Remove expired projectiles
if (p.lifetime <= 0) {
projectiles.splice(i, 1);
continue;
}
// Wrap projectiles
if (p.x < 0) p.x = canvas.width;
if (p.x > canvas.width) p.x = 0;
if (p.y < 0) p.y = canvas.height;
if (p.y > canvas.height) p.y = 0;
}
// Update obstacles
for (let i = obstacles.length - 1; i >= 0; i--) {
const o = obstacles[i];
o.x += o.dx;
o.y += o.dy;
o.rotation += o.rotationSpeed;
// Wrap obstacles
if (o.x < 0) o.x = canvas.width;
if (o.x > canvas.width) o.x = 0;
if (o.y < 0) o.y = canvas.height;
if (o.y > canvas.height) o.y = 0;
// Check collision with projectiles
for (let j = projectiles.length - 1; j >= 0; j--) {
const p = projectiles[j];
const dx = p.x - o.x;
const dy = p.y - o.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < o.radius) {
obstacles.splice(i, 1);
projectiles.splice(j, 1);
points += 100;
if (obstacles.length < 5) createObstacle();
break;
}
}
// Check collision with navigator
const dx = navigator.x - o.x;
const dy = navigator.y - o.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < o.radius + navigator.radius) {
gameOver();
}
}
}
function render() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw navigator
ctx.save();
ctx.translate(navigator.x, navigator.y);
ctx.rotate(navigator.angle);
ctx.beginPath();
ctx.moveTo(navigator.radius, 0);
ctx.lineTo(-navigator.radius, -navigator.radius/2);
ctx.lineTo(-navigator.radius/2, 0);
ctx.lineTo(-navigator.radius, navigator.radius/2);
ctx.closePath();
ctx.strokeStyle = 'white';
ctx.stroke();
ctx.restore();
// Draw projectiles
ctx.fillStyle = 'white';
projectiles.forEach(p => {
ctx.beginPath();
ctx.arc(p.x, p.y, 2, 0, Math.PI * 2);
ctx.fill();
});
// Draw obstacles
ctx.strokeStyle = 'white';
obstacles.forEach(o => {
ctx.save();
ctx.translate(o.x, o.y);
ctx.rotate(o.rotation);
ctx.beginPath();
for (let i = 0; i < o.vertices; i++) {
const angle = (i / o.vertices) * Math.PI * 2;
const x = Math.cos(angle) * o.radius;
const y = Math.sin(angle) * o.radius;
if (i === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
ctx.closePath();
ctx.stroke();
ctx.restore();
});
// Draw score
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.fillText('Score: ' + points, 10, 30);
if (!isActive) {
ctx.fillStyle = 'white';
ctx.font = '40px Arial';
ctx.fillText('Game Over!', canvas.width/2 - 100, canvas.height/2);
}
}
function gameOver() {
isActive = false;
}
// Controls
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowLeft':
navigator.isRotatingLeft = true;
break;
case 'ArrowRight':
navigator.isRotatingRight = true;
break;
case 'ArrowUp':
navigator.isThrusting = true;
break;
case ' ':
if (isActive) shoot();
break;
}
});
document.addEventListener('keyup', (e) => {
switch(e.key) {
case 'ArrowLeft':
navigator.isRotatingLeft = false;
break;
case 'ArrowRight':
navigator.isRotatingRight = false;
break;
case 'ArrowUp':
navigator.isThrusting = false;
break;
}
});
# Space Navigation Game Implementation
import pygame
import math
import random
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Ship:
x: float
y: float
radius: int = 15
angle: float = 0
dx: float = 0
dy: float = 0
thrust: float = 0.5
rotation_speed: float = 0.1
is_rotating_left: bool = False
is_rotating_right: bool = False
is_thrusting: bool = False
@dataclass
class Projectile:
x: float
y: float
dx: float
dy: float
lifetime: int = 60
@dataclass
class Obstacle:
x: float
y: float
dx: float
dy: float
radius: float
vertices: int
rotation: float
rotation_speed: float
class SpaceGame:
def __init__(self):
pygame.init()
# Game settings
self.width = 800
self.height = 600
# Initialize display
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Space Navigation')
self.clock = pygame.time.Clock()
# Game objects
self.ship = Ship(self.width / 2, self.height / 2)
self.projectiles: List[Projectile] = []
self.obstacles: List[Obstacle] = []
# Game state
self.points = 0
self.is_active = True
# Create initial obstacles
for _ in range(5):
self.create_obstacle()
def create_obstacle(self):
"""Create a new obstacle at screen edge"""
angle = random.random() * math.pi * 2
distance = max(self.width, self.height)
self.obstacles.append(
Obstacle(
x=self.width/2 + math.cos(angle) * distance,
y=self.height/2 + math.sin(angle) * distance,
dx=random.random() * 4 - 2,
dy=random.random() * 4 - 2,
radius=20 + random.random() * 20,
vertices=8 + random.randint(0, 3),
rotation=random.random() * math.pi * 2,
rotation_speed=(random.random() - 0.5) * 0.1
)
)
def shoot(self):
"""Create new projectile"""
self.projectiles.append(
Projectile(
x=self.ship.x + math.cos(self.ship.angle) * self.ship.radius,
y=self.ship.y + math.sin(self.ship.angle) * self.ship.radius,
dx=math.cos(self.ship.angle) * 7 + self.ship.dx,
dy=math.sin(self.ship.angle) * 7 + self.ship.dy
)
)
def wrap_position(self, x: float, y: float) -> Tuple[float, float]:
"""Wrap position around screen edges"""
if x < 0:
x = self.width
elif x > self.width:
x = 0
if y < 0:
y = self.height
elif y > self.height:
y = 0
return x, y
def handle_input(self) -> bool:
"""Handle keyboard input"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.ship.is_rotating_left = True
elif event.key == pygame.K_RIGHT:
self.ship.is_rotating_right = True
elif event.key == pygame.K_UP:
self.ship.is_thrusting = True
elif event.key == pygame.K_SPACE and self.is_active:
self.shoot()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
self.ship.is_rotating_left = False
elif event.key == pygame.K_RIGHT:
self.ship.is_rotating_right = False
elif event.key == pygame.K_UP:
self.ship.is_thrusting = False
return True
def update_game(self):
"""Update game state"""
if not self.is_active:
return
# Update ship
if self.ship.is_rotating_left:
self.ship.angle -= self.ship.rotation_speed
if self.ship.is_rotating_right:
self.ship.angle += self.ship.rotation_speed
if self.ship.is_thrusting:
self.ship.dx += math.cos(self.ship.angle) * self.ship.thrust
self.ship.dy += math.sin(self.ship.angle) * self.ship.thrust
self.ship.x += self.ship.dx
self.ship.y += self.ship.dy
self.ship.x, self.ship.y = self.wrap_position(self.ship.x, self.ship.y)
# Update projectiles
for projectile in self.projectiles[:]:
projectile.x += projectile.dx
projectile.y += projectile.dy
projectile.x, projectile.y = self.wrap_position(
projectile.x, projectile.y)
projectile.lifetime -= 1
if projectile.lifetime <= 0:
self.projectiles.remove(projectile)
# Update obstacles
for obstacle in self.obstacles[:]:
obstacle.x += obstacle.dx
obstacle.y += obstacle.dy
obstacle.x, obstacle.y = self.wrap_position(
obstacle.x, obstacle.y)
obstacle.rotation += obstacle.rotation_speed
# Check collision with projectiles
for projectile in self.projectiles[:]:
dx = projectile.x - obstacle.x
dy = projectile.y - obstacle.y
distance = math.sqrt(dx * dx + dy * dy)
if distance < obstacle.radius:
self.obstacles.remove(obstacle)
self.projectiles.remove(projectile)
self.points += 100
if len(self.obstacles) < 5:
self.create_obstacle()
break
# Check collision with ship
if obstacle in self.obstacles: # Make sure it wasn't destroyed
dx = self.ship.x - obstacle.x
dy = self.ship.y - obstacle.y
distance = math.sqrt(dx * dx + dy * dy)
if distance < obstacle.radius + self.ship.radius:
self.game_over()
def draw(self):
"""Draw the game state"""
# Clear screen
self.screen.fill((0, 0, 0)) # Black background
# Draw ship
points = [
(self.ship.radius, 0),
(-self.ship.radius, -self.ship.radius/2),
(-self.ship.radius/2, 0),
(-self.ship.radius, self.ship.radius/2)
]
# Rotate and translate points
rotated_points = []
for x, y in points:
rx = (x * math.cos(self.ship.angle) -
y * math.sin(self.ship.angle))
ry = (x * math.sin(self.ship.angle) +
y * math.cos(self.ship.angle))
rotated_points.append(
(rx + self.ship.x, ry + self.ship.y))
pygame.draw.polygon(self.screen, (255, 255, 255),
rotated_points, 1)
# Draw projectiles
for projectile in self.projectiles:
pygame.draw.circle(self.screen, (255, 255, 255),
(int(projectile.x), int(projectile.y)), 2)
# Draw obstacles
for obstacle in self.obstacles:
points = []
for i in range(obstacle.vertices):
angle = (i / obstacle.vertices * math.pi * 2 +
obstacle.rotation)
x = math.cos(angle) * obstacle.radius + obstacle.x
y = math.sin(angle) * obstacle.radius + obstacle.y
points.append((int(x), int(y)))
pygame.draw.polygon(self.screen, (255, 255, 255),
points, 1)
# Draw score
font = pygame.font.Font(None, 36)
score_text = font.render(f'Score: {self.points}',
True, (255, 255, 255))
self.screen.blit(score_text, (10, 10))
# Draw game over
if not self.is_active:
font = pygame.font.Font(None, 64)
game_over = font.render('Game Over!', True, (255, 255, 255))
game_over_rect = game_over.get_rect(
center=(self.width//2, self.height//2))
self.screen.blit(game_over, game_over_rect)
pygame.display.flip()
def game_over(self):
"""End the game"""
self.is_active = False
def run(self):
"""Main game loop"""
running = True
while running:
running = self.handle_input()
self.update_game()
self.draw()
self.clock.tick(60)
pygame.quit()
if __name__ == '__main__':
game = SpaceGame()
game.run()
Play Game