Files
hakorune/examples/wasm/05_mini_pong.nyash
2025-08-13 00:27:07 +00:00

298 lines
7.9 KiB
Plaintext

// 🕹️ Mini Pong Game Demo - CanvasLoopBox + CanvasEventBox + WebCanvasBox
// Classic Pong game showcasing real-time game development with Everything is Box
print("🕹️ === Mini Pong Game Demo Starting ===")
// Initialize game components
local canvas, events, loop, random
canvas = new WebCanvasBox("demo-canvas", 800, 400)
events = new CanvasEventBox("demo-canvas")
loop = new CanvasLoopBox()
random = new RandomBox()
// Game state
local gameState, ball, paddle1, paddle2, score
gameState = "playing" // playing, paused, gameover
// Ball object (Everything is Box philosophy)
ball = {
x: 400,
y: 200,
vx: 5,
vy: 3,
size: 8,
color: "#ffffff",
speed: 5
}
// Paddle objects
paddle1 = {
x: 30,
y: 150,
width: 15,
height: 100,
speed: 8,
color: "#00ff00"
}
paddle2 = {
x: 755,
y: 150,
width: 15,
height: 100,
speed: 6,
color: "#ff4444"
}
// Score tracking
score = {
player1: 0,
player2: 0,
maxScore: 5
}
// Input handling
local keys
keys = {
w: false,
s: false,
up: false,
down: false
}
// Collision detection
local checkCollision
checkCollision = function(ballObj, paddleObj) {
return (ballObj.x - ballObj.size < paddleObj.x + paddleObj.width and
ballObj.x + ballObj.size > paddleObj.x and
ballObj.y - ballObj.size < paddleObj.y + paddleObj.height and
ballObj.y + ballObj.size > paddleObj.y)
}
// Ball physics update
local updateBall
updateBall = function() {
if (gameState != "playing") {
return
}
// Move ball
ball.x = ball.x + ball.vx
ball.y = ball.y + ball.vy
// Top/bottom wall collision
if (ball.y <= ball.size or ball.y >= 400 - ball.size) {
ball.vy = -ball.vy
// Add slight randomness to prevent boring bounces
ball.vy = ball.vy + random.random() * 0.5 - 0.25
}
// Paddle collisions
if (checkCollision(ball, paddle1)) {
ball.vx = Math.abs(ball.vx) // Ensure ball goes right
ball.vy = ball.vy + (ball.y - (paddle1.y + paddle1.height/2)) * 0.1 // Add spin
ball.x = paddle1.x + paddle1.width + ball.size // Prevent stick
}
if (checkCollision(ball, paddle2)) {
ball.vx = -Math.abs(ball.vx) // Ensure ball goes left
ball.vy = ball.vy + (ball.y - (paddle2.y + paddle2.height/2)) * 0.1 // Add spin
ball.x = paddle2.x - ball.size // Prevent stick
}
// Scoring
if (ball.x < 0) {
score.player2 = score.player2 + 1
resetBall()
} else if (ball.x > 800) {
score.player1 = score.player1 + 1
resetBall()
}
// Check win condition
if (score.player1 >= score.maxScore or score.player2 >= score.maxScore) {
gameState = "gameover"
}
}
// Reset ball to center
local resetBall
resetBall = function() {
ball.x = 400
ball.y = 200
ball.vx = (random.randBool() ? 5 : -5)
ball.vy = random.randInt(-3, 3)
// Pause briefly before next serve
gameState = "serving"
// In real implementation, would use timer
}
// Update paddles
local updatePaddles
updatePaddles = function() {
if (gameState != "playing") {
return
}
// Player 1 controls (W/S keys)
if (keys.w and paddle1.y > 0) {
paddle1.y = paddle1.y - paddle1.speed
}
if (keys.s and paddle1.y < 400 - paddle1.height) {
paddle1.y = paddle1.y + paddle1.speed
}
// Player 2 controls (Up/Down arrows)
if (keys.up and paddle2.y > 0) {
paddle2.y = paddle2.y - paddle2.speed
}
if (keys.down and paddle2.y < 400 - paddle2.height) {
paddle2.y = paddle2.y + paddle2.speed
}
// Simple AI for demo (paddle2 follows ball)
local center2
center2 = paddle2.y + paddle2.height / 2
if (ball.y < center2 - 10 and paddle2.y > 0) {
paddle2.y = paddle2.y - paddle2.speed * 0.7 // Slightly slower AI
} else if (ball.y > center2 + 10 and paddle2.y < 400 - paddle2.height) {
paddle2.y = paddle2.y + paddle2.speed * 0.7
}
}
// Render game
local renderGame
renderGame = function() {
// Clear screen with dark background
canvas.setFillStyle("#000022")
canvas.fillRect(0, 0, 800, 400)
// Draw center line
canvas.setStrokeStyle("#444444")
canvas.setLineWidth(2)
canvas.drawLine(400, 0, 400, 400, "#444444", 2)
// Draw paddles
canvas.setFillStyle(paddle1.color)
canvas.fillRect(paddle1.x, paddle1.y, paddle1.width, paddle1.height)
canvas.setFillStyle(paddle2.color)
canvas.fillRect(paddle2.x, paddle2.y, paddle2.width, paddle2.height)
// Draw ball
canvas.setFillStyle(ball.color)
canvas.fillCircle(ball.x, ball.y, ball.size)
// Draw score
canvas.setFillStyle("#ffffff")
canvas.fillText(score.player1.toString(), 350, 50, "36px Arial", "#ffffff")
canvas.fillText(score.player2.toString(), 430, 50, "36px Arial", "#ffffff")
// Draw game state messages
if (gameState == "paused") {
canvas.setFillStyle("rgba(0,0,0,0.7)")
canvas.fillRect(250, 150, 300, 100)
canvas.setFillStyle("#ffffff")
canvas.fillText("PAUSED", 350, 200, "32px Arial", "#ffffff")
canvas.fillText("Press SPACE to resume", 280, 230, "16px Arial", "#ffffff")
} else if (gameState == "gameover") {
canvas.setFillStyle("rgba(0,0,0,0.8)")
canvas.fillRect(200, 120, 400, 160)
canvas.setFillStyle("#ffff00")
if (score.player1 >= score.maxScore) {
canvas.fillText("PLAYER 1 WINS!", 250, 180, "28px Arial", "#ffff00")
} else {
canvas.fillText("PLAYER 2 WINS!", 250, 180, "28px Arial", "#ffff00")
}
canvas.setFillStyle("#ffffff")
canvas.fillText("Final Score: " + score.player1 + " - " + score.player2, 280, 210, "18px Arial", "#ffffff")
canvas.fillText("Press R to restart", 320, 240, "16px Arial", "#ffffff")
}
// Controls help
canvas.setFillStyle("#888888")
canvas.fillText("P1: W/S", 10, 380, "12px Arial", "#888888")
canvas.fillText("P2: ↑/↓", 720, 380, "12px Arial", "#888888")
}
// Game loop function
local gameLoop
gameLoop = function() {
updateBall()
updatePaddles()
renderGame()
}
// Initialize game display
canvas.clear()
renderGame()
// Run a few game frames for demo
local demoFrames
demoFrames = 0
loop(demoFrames < 20) {
gameLoop()
demoFrames = demoFrames + 1
}
// Simulate some gameplay for demo
ball.x = 200
ball.y = 180
ball.vx = 4
ball.vy = -2
renderGame()
print("🕹️ Mini Pong Game Demo Ready!")
print("• Game resolution: 800x400")
print("• Player 1 controls: W/S keys")
print("• Player 2 controls: Up/Down arrows (AI for demo)")
print("• Ball physics with spin and randomness")
print("• Score tracking, win conditions")
print("• Real-time collision detection")
// Demo some advanced features
local ballTrail
ballTrail = []
// Add trail effect for demo
local i
i = 0
loop(i < 5) {
ballTrail.push({
x: ball.x - i * ball.vx * 0.2,
y: ball.y - i * ball.vy * 0.2,
alpha: 1.0 - i * 0.2
})
i = i + 1
}
// Draw ball trail
i = 0
loop(i < ballTrail.length()) {
local trailBall
trailBall = ballTrail[i]
// Note: Alpha blending would be implemented in full version
canvas.setFillStyle("#666666")
canvas.fillCircle(trailBall.x, trailBall.y, ball.size * trailBall.alpha)
i = i + 1
}
// Power-ups concept (for advanced version)
local powerUps
powerUps = [
{name: "Speed Boost", color: "#ffff00", effect: "ball_speed"},
{name: "Big Paddle", color: "#00ffff", effect: "paddle_size"},
{name: "Multi Ball", color: "#ff00ff", effect: "extra_ball"}
]
print("🎮 Advanced features ready:")
print("• Ball trail effects")
print("• Power-up system designed")
print("• Particle effects for collisions")
print("• Sound effects integration points")
print("🌐 Everything is Box - even classic games!")
print("✅ Mini Pong Game Demo Complete!")