automateyournetwork/PrincipleSkinner

Turn: 6a2db295351e33b0efca0fb1c1c6ca6868224fc9217e9a57899c8d042cf4c2f2

User

Prompt
Turn 8: Implement lives system and ball reset

Assistant

Response
Added resetBall() to return ball to center with random horizontal direction. Implemented loseLife() function that decrements lives, checks for game over (game.lost=true, game.running=false), or resets ball if lives remain. Ball now stops moving when game.running=false. Added spacebar to start game. Added UI overlays: "Press SPACE to Start" before game begins, "GAME OVER" with final score when lives reach 0. Lives system fully functional.
View Raw Turn JSON
{
  "assistant": {
    "text": "Added resetBall() to return ball to center with random horizontal direction. Implemented loseLife() function that decrements lives, checks for game over (game.lost=true, game.running=false), or resets ball if lives remain. Ball now stops moving when game.running=false. Added spacebar to start game. Added UI overlays: \"Press SPACE to Start\" before game begins, \"GAME OVER\" with final score when lives reach 0. Lives system fully functional.",
    "type": "message"
  },
  "context": {
    "artifacts": [
      {
        "content": "// Arkanoid Game - PrincipleSkinner Method (Ralph + GAIT)\n// Turn 1: Canvas foundation and game initialization\n// Turn 2: Paddle object with rendering\n// Turn 3: Paddle keyboard controls\n// Turn 4: Ball object with physics\n// Turn 5: Ball-paddle collision detection\n// Turn 6: Brick grid system\n// Turn 7: Ball-brick collision detection\n// Turn 8: Lives system and ball reset\n\n// Canvas setup\nconst canvas = document.getElementById('gameCanvas');\nconst ctx = canvas.getContext('2d');\n\n// Game state\nconst game = {\n    score: 0,\n    lives: 3,\n    running: false,\n    won: false,\n    lost: false\n};\n\n// Paddle object\nconst paddle = {\n    width: 100,\n    height: 15,\n    x: canvas.width / 2 - 50,\n    y: canvas.height - 40,\n    speed: 7,\n    dx: 0\n};\n\n// Ball object\nconst ball = {\n    radius: 8,\n    x: canvas.width / 2,\n    y: canvas.height / 2,\n    dx: 4,\n    dy: -4,\n    speed: 4\n};\n\n// Brick configuration\nconst brickConfig = {\n    rows: 5,\n    cols: 10,\n    width: 70,\n    height: 20,\n    padding: 10,\n    offsetTop: 60,\n    offsetLeft: 35\n};\n\n// Brick colors by row\nconst brickColors = ['#ff0000', '#ff7700', '#ffff00', '#00ff00', '#0077ff'];\n\n// Create brick grid\nconst bricks = [];\nfunction createBricks() {\n    for (let row = 0; row < brickConfig.rows; row++) {\n        bricks[row] = [];\n        for (let col = 0; col < brickConfig.cols; col++) {\n            bricks[row][col] = {\n                x: col * (brickConfig.width + brickConfig.padding) + brickConfig.offsetLeft,\n                y: row * (brickConfig.height + brickConfig.padding) + brickConfig.offsetTop,\n                status: 1, // 1 = visible, 0 = destroyed\n                color: brickColors[row]\n            };\n        }\n    }\n}\n\n// Draw paddle\nfunction drawPaddle() {\n    ctx.fillStyle = '#00ff00';\n    ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);\n\n    // Add glow effect\n    ctx.shadowBlur = 10;\n    ctx.shadowColor = '#00ff00';\n    ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);\n    ctx.shadowBlur = 0;\n}\n\n// Draw ball\nfunction drawBall() {\n    ctx.beginPath();\n    ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n    ctx.fillStyle = '#00ffff';\n    ctx.fill();\n\n    // Add glow effect\n    ctx.shadowBlur = 15;\n    ctx.shadowColor = '#00ffff';\n    ctx.fill();\n    ctx.shadowBlur = 0;\n    ctx.closePath();\n}\n\n// Draw bricks\nfunction drawBricks() {\n    for (let row = 0; row < brickConfig.rows; row++) {\n        for (let col = 0; col < brickConfig.cols; col++) {\n            const brick = bricks[row][col];\n            if (brick.status === 1) {\n                ctx.fillStyle = brick.color;\n                ctx.fillRect(brick.x, brick.y, brickConfig.width, brickConfig.height);\n\n                // Add border\n                ctx.strokeStyle = '#ffffff';\n                ctx.lineWidth = 2;\n                ctx.strokeRect(brick.x, brick.y, brickConfig.width, brickConfig.height);\n            }\n        }\n    }\n}\n\n// Update UI\nfunction updateUI() {\n    document.getElementById('score').textContent = game.score;\n    document.getElementById('lives').textContent = game.lives;\n}\n\n// Update paddle position\nfunction updatePaddle() {\n    paddle.x += paddle.dx;\n\n    // Keep paddle within bounds\n    if (paddle.x < 0) {\n        paddle.x = 0;\n    }\n    if (paddle.x + paddle.width > canvas.width) {\n        paddle.x = canvas.width - paddle.width;\n    }\n}\n\n// Check ball-paddle collision\nfunction checkPaddleCollision() {\n    // Ball is at paddle height\n    if (ball.y + ball.radius >= paddle.y &&\n        ball.y - ball.radius <= paddle.y + paddle.height) {\n        // Ball is within paddle width\n        if (ball.x >= paddle.x && ball.x <= paddle.x + paddle.width) {\n            // Reverse ball direction\n            ball.dy = -Math.abs(ball.dy);\n\n            // Add spin based on where ball hits paddle\n            const hitPos = (ball.x - paddle.x) / paddle.width; // 0 to 1\n            ball.dx = (hitPos - 0.5) * 8; // -4 to 4 range for spin effect\n        }\n    }\n}\n\n// Check ball-brick collisions\nfunction checkBrickCollision() {\n    for (let row = 0; row < brickConfig.rows; row++) {\n        for (let col = 0; col < brickConfig.cols; col++) {\n            const brick = bricks[row][col];\n            if (brick.status === 1) {\n                // Check if ball overlaps with brick\n                if (ball.x + ball.radius > brick.x &&\n                    ball.x - ball.radius < brick.x + brickConfig.width &&\n                    ball.y + ball.radius > brick.y &&\n                    ball.y - ball.radius < brick.y + brickConfig.height) {\n\n                    // Destroy brick\n                    brick.status = 0;\n\n                    // Bounce ball\n                    ball.dy = -ball.dy;\n\n                    // Increase score\n                    game.score += 10;\n                    updateUI();\n\n                    return; // Only one brick per frame\n                }\n            }\n        }\n    }\n}\n\n// Reset ball to center\nfunction resetBall() {\n    ball.x = canvas.width / 2;\n    ball.y = canvas.height / 2;\n    ball.dx = 4 * (Math.random() > 0.5 ? 1 : -1); // Random direction\n    ball.dy = -4;\n}\n\n// Lose a life\nfunction loseLife() {\n    game.lives--;\n    updateUI();\n\n    if (game.lives <= 0) {\n        game.lost = true;\n        game.running = false;\n    } else {\n        resetBall();\n    }\n}\n\n// Update ball position and handle wall collisions\nfunction updateBall() {\n    if (!game.running) return;\n\n    ball.x += ball.dx;\n    ball.y += ball.dy;\n\n    // Wall collisions (left and right)\n    if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {\n        ball.dx = -ball.dx;\n    }\n\n    // Ceiling collision\n    if (ball.y - ball.radius < 0) {\n        ball.dy = -ball.dy;\n    }\n\n    // Check collisions\n    checkPaddleCollision();\n    checkBrickCollision();\n\n    // Ball falls below paddle - lose life\n    if (ball.y + ball.radius > canvas.height) {\n        loseLife();\n    }\n}\n\n// Clear canvas\nfunction clearCanvas() {\n    ctx.fillStyle = '#000000';\n    ctx.fillRect(0, 0, canvas.width, canvas.height);\n}\n\n// Render game\nfunction render() {\n    clearCanvas();\n    drawBricks();\n    drawPaddle();\n    drawBall();\n\n    // Show start message\n    if (!game.running && !game.lost) {\n        ctx.fillStyle = '#ffffff';\n        ctx.font = '24px Arial';\n        ctx.textAlign = 'center';\n        ctx.fillText('Press SPACE to Start', canvas.width / 2, canvas.height / 2 + 100);\n    }\n\n    // Show game over message\n    if (game.lost) {\n        ctx.fillStyle = '#ff0000';\n        ctx.font = '48px Arial';\n        ctx.textAlign = 'center';\n        ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2);\n        ctx.font = '20px Arial';\n        ctx.fillStyle = '#ffffff';\n        ctx.fillText('Final Score: ' + game.score, canvas.width / 2, canvas.height / 2 + 40);\n    }\n}\n\n// Game loop\nfunction gameLoop() {\n    updatePaddle();\n    updateBall();\n    render();\n    requestAnimationFrame(gameLoop);\n}\n\n// Keyboard controls\nfunction keyDown(e) {\n    if (e.key === 'ArrowLeft' || e.key === 'a') {\n        paddle.dx = -paddle.speed;\n    } else if (e.key === 'ArrowRight' || e.key === 'd') {\n        paddle.dx = paddle.speed;\n    } else if (e.key === ' ' && !game.running && !game.lost) {\n        // Start game with spacebar\n        game.running = true;\n    }\n}\n\nfunction keyUp(e) {\n    if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'ArrowRight' || e.key === 'd') {\n        paddle.dx = 0;\n    }\n}\n\n// Initialize game\nfunction init() {\n    console.log('Arkanoid initialized - Canvas: ' + canvas.width + 'x' + canvas.height);\n    createBricks();\n    updateUI();\n    render();\n\n    // Add event listeners\n    document.addEventListener('keydown', keyDown);\n    document.addEventListener('keyup', keyUp);\n\n    // Start game loop\n    gameLoop();\n}\n\n// Start game on load\nwindow.addEventListener('load', init);",
        "path": "game.js"
      }
    ],
    "pinned_context": {
      "branch": "principalskinner-arkanoid",
      "items": [],
      "memory_id": "086e39ec4fb04bd965bcc97353b8c325dcc80d406e6b5b840ae8db97796c6775",
      "pinned_items": 0,
      "schema": "gait.context.v0"
    }
  },
  "created_at": "2026-01-09T09:33:31",
  "model": {
    "provider": "vscode-copilot"
  },
  "schema": "gait.turn.v0",
  "tokens": {
    "by_role": {},
    "estimated": true,
    "input_total": 10,
    "output_total": 93
  },
  "tools": {},
  "user": {
    "text": "Turn 8: Implement lives system and ball reset",
    "type": "message"
  },
  "visibility": "private"
}