Mystery Game #23
← Back to Games List
// Side-Scrolling Adventure
const entity = {
x: 100,
y: 0,
width: 30,
height: 50,
dx: 0,
dy: 0,
onGround: false,
facing: 1
};
const physics = {
gravity: 0.5,
jumpForce: -12,
moveSpeed: 5,
friction: 0.8
};
const terrain = [
{x: 0, y: 400, width: 800, height: 40},
{x: 200, y: 300, width: 100, height: 20},
{x: 400, y: 250, width: 100, height: 20},
{x: 600, y: 350, width: 100, height: 20}
];
const hazards = [
{x: 300, y: 380, width: 60, height: 20},
{x: 500, y: 380, width: 60, height: 20}
];
const collectibles = [
{x: 250, y: 250, collected: false},
{x: 450, y: 200, collected: false},
{x: 650, y: 300, collected: false}
];
let points = 0;
let isActive = true;
function updatePhysics() {
if (!isActive) return;
// Apply gravity
entity.dy += physics.gravity;
// Apply movement
entity.x += entity.dx;
entity.y += entity.dy;
// Apply friction
entity.dx *= physics.friction;
// Check ground collision
entity.onGround = false;
for (const platform of terrain) {
if (checkCollision(entity, platform)) {
if (entity.dy > 0) {
entity.y = platform.y - entity.height;
entity.dy = 0;
entity.onGround = true;
} else if (entity.dy < 0) {
entity.y = platform.y + platform.height;
entity.dy = 0;
}
}
}
// Check hazard collision
for (const hazard of hazards) {
if (checkCollision(entity, hazard)) {
gameOver();
return;
}
}
// Check collectible collision
for (const item of collectibles) {
if (!item.collected &&
Math.abs(entity.x + entity.width/2 - item.x) < 20 &&
Math.abs(entity.y + entity.height/2 - item.y) < 20) {
item.collected = true;
points += 100;
}
}
// Keep in bounds
if (entity.x < 0) entity.x = 0;
if (entity.x > canvas.width - entity.width) {
entity.x = canvas.width - entity.width;
}
// Check fall death
if (entity.y > canvas.height) {
gameOver();
}
}
function checkCollision(a, b) {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
function gameOver() {
isActive = false;
}
function render(ctx) {
// Clear canvas
ctx.fillStyle = '#87CEEB';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw terrain
ctx.fillStyle = '#5A3A22';
for (const platform of terrain) {
ctx.fillRect(platform.x, platform.y,
platform.width, platform.height);
}
// Draw hazards
ctx.fillStyle = '#FF0000';
for (const hazard of hazards) {
ctx.fillRect(hazard.x, hazard.y,
hazard.width, hazard.height);
}
// Draw collectibles
ctx.fillStyle = '#FFD700';
for (const item of collectibles) {
if (!item.collected) {
ctx.beginPath();
ctx.arc(item.x, item.y, 10, 0, Math.PI * 2);
ctx.fill();
}
}
// Draw entity
ctx.fillStyle = '#008000';
ctx.fillRect(entity.x, entity.y,
entity.width, entity.height);
// Draw score
ctx.fillStyle = 'black';
ctx.font = '20px Arial';
ctx.fillText('Score: ' + points, 10, 30);
if (!isActive) {
ctx.fillStyle = 'black';
ctx.font = '40px Arial';
ctx.fillText('Game Over!', canvas.width/2 - 100, canvas.height/2);
}
}
document.addEventListener('keydown', (e) => {
if (!isActive) return;
switch(e.key) {
case 'ArrowLeft':
entity.dx = -physics.moveSpeed;
entity.facing = -1;
break;
case 'ArrowRight':
entity.dx = physics.moveSpeed;
entity.facing = 1;
break;
case ' ':
case 'ArrowUp':
if (entity.onGround) {
entity.dy = physics.jumpForce;
entity.onGround = false;
}
break;
}
});
# Side-Scrolling Adventure Implementation
import pygame
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Entity:
x: float
y: float
width: int = 30
height: int = 50
dx: float = 0
dy: float = 0
on_ground: bool = False
facing: int = 1
@dataclass
class Physics:
gravity: float = 0.5
jump_force: float = -12
move_speed: float = 5
friction: float = 0.8
@dataclass
class Platform:
x: int
y: int
width: int
height: int
@dataclass
class Collectible:
x: int
y: int
collected: bool = False
class PlatformerGame:
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('Side-Scrolling Adventure')
self.clock = pygame.time.Clock()
# Game objects
self.entity = Entity(100, 0)
self.physics = Physics()
# Level objects
self.terrain = [
Platform(0, 400, 800, 40),
Platform(200, 300, 100, 20),
Platform(400, 250, 100, 20),
Platform(600, 350, 100, 20)
]
self.hazards = [
Platform(300, 380, 60, 20),
Platform(500, 380, 60, 20)
]
self.collectibles = [
Collectible(250, 250),
Collectible(450, 200),
Collectible(650, 300)
]
# Game state
self.points = 0
self.is_active = True
def check_collision(self, a: Entity, b: Platform) -> bool:
"""Check collision between two rectangles"""
return (a.x < b.x + b.width and
a.x + a.width > b.x and
a.y < b.y + b.height and
a.y + a.height > b.y)
def update_physics(self):
"""Update game physics"""
if not self.is_active:
return
# Apply gravity
self.entity.dy += self.physics.gravity
# Apply movement
self.entity.x += self.entity.dx
self.entity.y += self.entity.dy
# Apply friction
self.entity.dx *= self.physics.friction
# Check ground collision
self.entity.on_ground = False
for platform in self.terrain:
if self.check_collision(self.entity, platform):
if self.entity.dy > 0:
self.entity.y = platform.y - self.entity.height
self.entity.dy = 0
self.entity.on_ground = True
elif self.entity.dy < 0:
self.entity.y = platform.y + platform.height
self.entity.dy = 0
# Check hazard collision
for hazard in self.hazards:
if self.check_collision(self.entity, hazard):
self.game_over()
return
# Check collectible collision
for item in self.collectibles:
if (not item.collected and
abs(self.entity.x + self.entity.width/2 - item.x) < 20 and
abs(self.entity.y + self.entity.height/2 - item.y) < 20):
item.collected = True
self.points += 100
# Keep in bounds
if self.entity.x < 0:
self.entity.x = 0
if self.entity.x > self.width - self.entity.width:
self.entity.x = self.width - self.entity.width
# Check fall death
if self.entity.y > self.height:
self.game_over()
def game_over(self):
"""End the game"""
self.is_active = False
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 not self.is_active:
continue
if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
if self.entity.on_ground:
self.entity.dy = self.physics.jump_force
self.entity.on_ground = False
# Continuous key input
if self.is_active:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.entity.dx = -self.physics.move_speed
self.entity.facing = -1
elif keys[pygame.K_RIGHT]:
self.entity.dx = self.physics.move_speed
self.entity.facing = 1
return True
def draw(self):
"""Draw the game state"""
# Clear screen
self.screen.fill((135, 206, 235)) # Sky blue
# Draw terrain
for platform in self.terrain:
pygame.draw.rect(self.screen, (90, 58, 34), # Brown
(platform.x, platform.y,
platform.width, platform.height))
# Draw hazards
for hazard in self.hazards:
pygame.draw.rect(self.screen, (255, 0, 0), # Red
(hazard.x, hazard.y,
hazard.width, hazard.height))
# Draw collectibles
for item in self.collectibles:
if not item.collected:
pygame.draw.circle(self.screen, (255, 215, 0), # Gold
(item.x, item.y), 10)
# Draw entity
pygame.draw.rect(self.screen, (0, 128, 0), # Green
(int(self.entity.x), int(self.entity.y),
self.entity.width, self.entity.height))
# Draw score
font = pygame.font.Font(None, 36)
score_text = font.render(f'Score: {self.points}',
True, (0, 0, 0))
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, (0, 0, 0))
text_rect = game_over.get_rect(
center=(self.width//2, self.height//2))
self.screen.blit(game_over, text_rect)
pygame.display.flip()
def run(self):
"""Main game loop"""
running = True
while running:
running = self.handle_input()
self.update_physics()
self.draw()
self.clock.tick(60)
pygame.quit()
if __name__ == '__main__':
game = PlatformerGame()
game.run()
Play Game