mirror of
https://github.com/soconnor0919/eceg431.git
synced 2025-12-11 06:34:43 -05:00
project09 - clean up
This commit is contained in:
@@ -25,8 +25,9 @@ class Food {
|
|||||||
var int gridX, gridY;
|
var int gridX, gridY;
|
||||||
|
|
||||||
// generate random grid coordinates (8x8 pixel grid)
|
// generate random grid coordinates (8x8 pixel grid)
|
||||||
|
// adjusted for header area (y starts at 33, so grid starts at row 5)
|
||||||
let gridX = Random.between(1, 58) * 8;
|
let gridX = Random.between(1, 58) * 8;
|
||||||
let gridY = Random.between(1, 28) * 8;
|
let gridY = Random.between(5, 28) * 8;
|
||||||
|
|
||||||
do position.setX(gridX);
|
do position.setX(gridX);
|
||||||
do position.setY(gridY);
|
do position.setY(gridY);
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ class Snake {
|
|||||||
let direction = 4; // right
|
let direction = 4; // right
|
||||||
let body = Array.new(maxLength);
|
let body = Array.new(maxLength);
|
||||||
|
|
||||||
// initialize head at screen center
|
// initialize head at screen center (adjusted for header area)
|
||||||
let head = Point.new(256, 128);
|
let head = Point.new(256, 144);
|
||||||
let body[0] = head;
|
let body[0] = head;
|
||||||
|
|
||||||
// create initial body segments
|
// create initial body segments
|
||||||
let body[1] = Point.new(248, 128);
|
let body[1] = Point.new(248, 144);
|
||||||
let body[2] = Point.new(240, 128);
|
let body[2] = Point.new(240, 144);
|
||||||
|
|
||||||
do draw();
|
do draw();
|
||||||
return this;
|
return this;
|
||||||
@@ -146,10 +146,10 @@ class Snake {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check wall collision
|
// check wall collision (adjusted for header area)
|
||||||
method boolean hitWall() {
|
method boolean hitWall() {
|
||||||
return (head.getX() < 8) | (head.getX() > 496) |
|
return (head.getX() < 8) | (head.getX() > 496) |
|
||||||
(head.getY() < 8) | (head.getY() > 240);
|
(head.getY() < 33) | (head.getY() > 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check self collision
|
// check self collision
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ class SnakeGame {
|
|||||||
field boolean gameOver;
|
field boolean gameOver;
|
||||||
field boolean paused;
|
field boolean paused;
|
||||||
field int speed;
|
field int speed;
|
||||||
|
field char lastKey;
|
||||||
|
field int pendingDirection;
|
||||||
|
field boolean restarting;
|
||||||
|
|
||||||
// create new snake game
|
// create new snake game
|
||||||
constructor SnakeGame new() {
|
constructor SnakeGame new() {
|
||||||
@@ -17,6 +20,9 @@ class SnakeGame {
|
|||||||
let gameOver = false;
|
let gameOver = false;
|
||||||
let paused = false;
|
let paused = false;
|
||||||
let speed = 150; // milliseconds between moves
|
let speed = 150; // milliseconds between moves
|
||||||
|
let lastKey = 0;
|
||||||
|
let pendingDirection = 0;
|
||||||
|
let restarting = false;
|
||||||
|
|
||||||
do Random.seed(123); // initialize random generator
|
do Random.seed(123); // initialize random generator
|
||||||
do drawUI();
|
do drawUI();
|
||||||
@@ -33,57 +39,133 @@ class SnakeGame {
|
|||||||
|
|
||||||
// draw game interface elements
|
// draw game interface elements
|
||||||
method void drawUI() {
|
method void drawUI() {
|
||||||
// draw thick border for clear game boundaries
|
// draw header area with border only on third row
|
||||||
do Screen.setColor(true);
|
do Screen.setColor(true);
|
||||||
do Screen.drawRectangle(0, 0, 511, 7); // top border
|
do Screen.drawRectangle(0, 22, 511, 32); // border only on third row
|
||||||
do Screen.drawRectangle(0, 248, 511, 255); // bottom border
|
do Screen.drawRectangle(0, 248, 511, 255); // bottom border
|
||||||
do Screen.drawRectangle(0, 0, 7, 255); // left border
|
do Screen.drawRectangle(0, 32, 7, 255); // left border (starts below header)
|
||||||
do Screen.drawRectangle(504, 0, 511, 255); // right border
|
do Screen.drawRectangle(504, 32, 511, 255); // right border (starts below header)
|
||||||
|
|
||||||
|
do showGameTitle();
|
||||||
do showScore();
|
do showScore();
|
||||||
do showInstructions();
|
do showControls();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display game title
|
||||||
|
method void showGameTitle() {
|
||||||
|
do Output.moveCursor(0, 0);
|
||||||
|
do Output.printString("SNAKE GAME");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display current score
|
// display current score
|
||||||
method void showScore() {
|
method void showScore() {
|
||||||
do Output.moveCursor(0, 0);
|
do Output.moveCursor(1, 0);
|
||||||
do Output.printString("Score: ");
|
do Output.printString("Score: ");
|
||||||
do Output.printInt(score);
|
do Output.printInt(score);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display game instructions
|
// display game controls
|
||||||
method void showInstructions() {
|
method void showControls() {
|
||||||
do Output.moveCursor(0, 20);
|
do Output.moveCursor(0, 35);
|
||||||
do Output.printString("Arrow Keys: Move Space: Pause Q: Quit");
|
do Output.printString("Arrows: Move Space: Pause");
|
||||||
|
do Output.moveCursor(1, 35);
|
||||||
|
do Output.printString("Enter: 2x Speed R: Restart");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display game over message
|
// display game over message
|
||||||
method void showGameOver() {
|
method void showGameOver() {
|
||||||
do Output.moveCursor(12, 20);
|
// draw larger border box (centered on screen)
|
||||||
|
do Screen.setColor(true);
|
||||||
|
do Screen.drawRectangle(100, 80, 412, 180); // outer border
|
||||||
|
do Screen.setColor(false);
|
||||||
|
do Screen.drawRectangle(102, 82, 410, 178); // inner area
|
||||||
|
|
||||||
|
// properly centered text
|
||||||
|
// Box spans columns 12-51 (39 chars wide), center at column 31
|
||||||
|
do Output.moveCursor(10, 26); // "GAME OVER!" (10 chars) centered at 31-5=26
|
||||||
do Output.printString("GAME OVER!");
|
do Output.printString("GAME OVER!");
|
||||||
do Output.moveCursor(14, 18);
|
do Output.moveCursor(12, 23); // "Final Score: XXX" (~16 chars) centered at 31-8=23
|
||||||
do Output.printString("Final Score: ");
|
do Output.printString("Final Score: ");
|
||||||
do Output.printInt(score);
|
do Output.printInt(score);
|
||||||
do Output.moveCursor(16, 15);
|
do Output.moveCursor(14, 15); // "Press R to restart or Q to quit" (32 chars) at 31-16=15
|
||||||
do Output.printString("Press R to restart or Q to quit");
|
do Output.printString("Press R to restart or Q to quit");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle user input
|
// handle user input with key press detection
|
||||||
method void processInput() {
|
method void processInput() {
|
||||||
var char key;
|
var char key;
|
||||||
let key = Keyboard.keyPressed();
|
let key = Keyboard.keyPressed();
|
||||||
|
|
||||||
if (key = 81) { let gameOver = true; } // q - quit
|
// only process if this is a new key press (different from last frame)
|
||||||
if (key = 32) { let paused = ~paused; } // space - pause
|
if ((key > 0) & (~(key = lastKey))) {
|
||||||
if (key = 131) { do snake.setDirection(1); } // up arrow
|
if (key = 81) { let gameOver = true; } // q - quit
|
||||||
if (key = 133) { do snake.setDirection(2); } // down arrow
|
if (key = 32) { let paused = ~paused; } // space - pause
|
||||||
if (key = 130) { do snake.setDirection(3); } // left arrow
|
if ((key = 82) & (~restarting)) { // r - restart anytime (prevent rapid calls)
|
||||||
if (key = 132) { do snake.setDirection(4); } // right arrow
|
let restarting = true;
|
||||||
|
do restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key = 131) { let pendingDirection = 1; } // up arrow - queue for next frame
|
||||||
|
if (key = 133) { let pendingDirection = 2; } // down arrow - queue for next frame
|
||||||
|
if (key = 130) { let pendingDirection = 3; } // left arrow - queue for next frame
|
||||||
|
if (key = 132) { let pendingDirection = 4; } // right arrow - queue for next frame
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastKey = key;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current speed based on whether shift is held
|
||||||
|
method int getCurrentSpeed() {
|
||||||
|
var char key;
|
||||||
|
let key = Keyboard.keyPressed();
|
||||||
|
|
||||||
|
if (key = 128) { // enter key
|
||||||
|
return speed / 2; // 2x speed when enter held
|
||||||
|
}
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restart the game
|
||||||
|
method void restart() {
|
||||||
|
do Screen.clearScreen();
|
||||||
|
do snake.dispose();
|
||||||
|
do food.dispose();
|
||||||
|
let snake = Snake.new();
|
||||||
|
let food = Food.new();
|
||||||
|
do food.spawn();
|
||||||
|
let score = 0;
|
||||||
|
let gameOver = false;
|
||||||
|
let paused = false;
|
||||||
|
let speed = 150;
|
||||||
|
let lastKey = 0;
|
||||||
|
let pendingDirection = 0;
|
||||||
|
let restarting = false;
|
||||||
|
do drawUI();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for input multiple times during wait period
|
||||||
|
method void waitWithInput(int milliseconds) {
|
||||||
|
var int elapsed;
|
||||||
|
var int checkInterval;
|
||||||
|
|
||||||
|
let elapsed = 0;
|
||||||
|
let checkInterval = 20; // check input every 20ms
|
||||||
|
|
||||||
|
while (elapsed < milliseconds) {
|
||||||
|
do processInput();
|
||||||
|
if (gameOver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do Sys.wait(checkInterval);
|
||||||
|
let elapsed = elapsed + checkInterval;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +179,12 @@ class SnakeGame {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply pending direction change at start of frame
|
||||||
|
if (pendingDirection > 0) {
|
||||||
|
do snake.setDirection(pendingDirection);
|
||||||
|
let pendingDirection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// get current head and direction
|
// get current head and direction
|
||||||
let currentHead = snake.getHead();
|
let currentHead = snake.getHead();
|
||||||
let currentDirection = snake.getDirection();
|
let currentDirection = snake.getDirection();
|
||||||
@@ -119,6 +207,7 @@ class SnakeGame {
|
|||||||
do snake.move(ateFood);
|
do snake.move(ateFood);
|
||||||
|
|
||||||
// check collisions after movement
|
// check collisions after movement
|
||||||
|
// check wall collision (adjusted for new header area)
|
||||||
if (snake.hitWall() | snake.hitSelf()) {
|
if (snake.hitWall() | snake.hitSelf()) {
|
||||||
let gameOver = true;
|
let gameOver = true;
|
||||||
return;
|
return;
|
||||||
@@ -163,9 +252,8 @@ class SnakeGame {
|
|||||||
while (true) {
|
while (true) {
|
||||||
// game running loop
|
// game running loop
|
||||||
while (~gameOver) {
|
while (~gameOver) {
|
||||||
do processInput();
|
|
||||||
do update();
|
do update();
|
||||||
do Sys.wait(speed);
|
do waitWithInput(getCurrentSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
// game over screen
|
// game over screen
|
||||||
@@ -173,18 +261,7 @@ class SnakeGame {
|
|||||||
let restart = waitForRestart();
|
let restart = waitForRestart();
|
||||||
|
|
||||||
if (restart) {
|
if (restart) {
|
||||||
// reset game state
|
do restart();
|
||||||
do Screen.clearScreen();
|
|
||||||
do snake.dispose();
|
|
||||||
do food.dispose();
|
|
||||||
let snake = Snake.new();
|
|
||||||
let food = Food.new();
|
|
||||||
do food.spawn();
|
|
||||||
let score = 0;
|
|
||||||
let gameOver = false;
|
|
||||||
let paused = false;
|
|
||||||
let speed = 150;
|
|
||||||
do drawUI();
|
|
||||||
} else {
|
} else {
|
||||||
return; // quit game
|
return; // quit game
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user