Skip to content

Instantly share code, notes, and snippets.

@shakkurcwb
Last active June 2, 2023 02:26
Show Gist options
  • Save shakkurcwb/d30610f490b6b90bb8a5f7f9f55fa7c9 to your computer and use it in GitHub Desktop.
Save shakkurcwb/d30610f490b6b90bb8a5f7f9f55fa7c9 to your computer and use it in GitHub Desktop.
Definitely not a Snake Game (JavaScript)
body {
text-align: center;
}
#game-screen {
border: 1px solid #000000;
}
.title {
font-size: 20px;
font-weight: bold;
}
.sub-title {
font-size: 16px;
font-weight: bold;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="game.css">
</head>
<body>
<div>
<p class="title">Current Score: <strong id="score">0</strong></p>
<p class="sub-title">Max Score: <strong id="max-score">0</strong></p>
</div>
<canvas id="game-screen" width="400" height="300"></canvas>
<script src="game.js"></script>
</body>
</html>
var ctx = document.getElementById('game-screen').getContext('2d');
var minWidth = 0;
var minHeight = 0;
var maxWidth = 400;
var maxHeight = 300;
var boxWidth = 20;
var boxHeight = 20;
var config = {
defaultFoodSpawn: false,
defaultPlayerSpawn: false,
selfCollisionCausesGameOver: false,
outOfBoundsCausesGameOver: false,
};
var styles = {
grid: {
primaryColor: 'red',
secondaryColor: 'black',
},
player: {
headColor: 'purple',
bodyColor: 'blue',
},
food: {
color: 'green',
},
};
// Score
var score = 0;
var scoreElement = document.getElementById('score');
var scoreConstants = {
movement: 10,
food: 100,
selfCollision: -100,
outOfBounds: -100,
};
function updateScoreElement() {
scoreElement.innerHTML = score;
}
var maxScore = 0;
var maxScoreElement = document.getElementById('max-score');
function updateMaxScoreElement() {
maxScoreElement.innerHTML = maxScore;
}
if (localStorage.getItem('maxScore')) {
maxScore = parseInt(localStorage.getItem('maxScore'));
}
function persistMaxScore() {
localStorage.setItem('maxScore', maxScore);
}
// Player Position
var movementDirection = "right";
var safePlayerPosition = {
x: 0,
y: 0,
};
var playerPosition = safePlayerPosition;
if (!config.defaultPlayerSpawn) {
playerPosition = randomPlayerPosition();
}
var playerPath = [];
playerPath.push(playerPosition);
// Food Position
var safeFoodPosition = {
x: maxWidth - boxWidth,
y: maxHeight - boxHeight,
};
var foodPosition = safeFoodPosition;
if (!config.defaultFoodSpawn) {
foodPosition = randomFoodPosition();
}
function initGame() {
console.log('initGame');
drawGrid();
drawPlayer();
drawFood();
renderScores();
document.addEventListener("keydown", movePlayer);
}
function drawGrid() {
console.log('drawGrid');
count = 0;
for (var x = minWidth; x < maxWidth; x += boxWidth) {
for (var y = minHeight; y < maxHeight; y += boxHeight) {
if (count % 2 == 0) {
ctx.fillStyle = styles.grid.primaryColor;
} else {
ctx.fillStyle = styles.grid.secondaryColor;
}
ctx.fillRect(x, y, boxWidth, boxHeight);
count += 1;
}
}
}
function drawPlayer() {
console.log('drawPlayer');
playerPath.forEach(function (body, idx) {
if (idx === 0) {
ctx.fillStyle = styles.player.headColor;
console.log('@head at ' + body.x + ', ' + body.y);
} else {
ctx.fillStyle = styles.player.bodyColor;
}
ctx.fillRect(body.x, body.y, boxWidth, boxHeight);
});
}
function drawFood() {
console.log('drawFood');
ctx.fillStyle = styles.food.color;
ctx.fillRect(foodPosition.x, foodPosition.y, boxWidth, boxHeight);
}
function randomWidth() {
var possibleWidths = [];
for (var x = minWidth; x < maxWidth; x += boxWidth) {
possibleWidths.push(x);
}
return possibleWidths[Math.floor(Math.random() * possibleWidths.length)];
}
function randomHeight() {
var possibleHeights = [];
for (var x = minHeight; x < maxHeight; x += boxWidth) {
possibleHeights.push(x);
}
return possibleHeights[Math.floor(Math.random() * possibleHeights.length)];
}
function randomPosition() {
var x = randomWidth();
var y = randomHeight();
return { x, y };
}
function randomPlayerPosition() {
console.log('randomPlayerPosition');
var position = randomPosition();
console.log('@player at: ' + position.x + ', ' + position.y);
return position;
}
function randomFoodPosition() {
console.log('randomFoodPosition');
var position = randomPosition();
// confirm x, y does not conflict with player's path
playerPath.forEach(function (body) {
if (position.x === body.x && position.y === body.y) {
console.log('@food conflict: ' + position.x + ', ' + position.y);
position = randomPosition();
}
});
console.log('@food at: ' + position.x + ', ' + position.y);
// @todo: still possible that we have a conflicting position
return { x: position.x, y: position.y };
}
function isValidMovement(event) {
console.log('isValidMovement');
var validKeyCodes = [
37, 38, 39, 40
];
return validKeyCodes.includes(event.keyCode);
}
function movePlayer(event) {
console.log('movePlayer');
if (!isValidMovement(event)) {
return;
}
console.log('@from: ' + movementDirection);
guessMovementDirection(event);
console.log('@to: ' + movementDirection);
var newHead = guessPlayerMovement();
var stopGame = false;
if (!stopGame) {
stopGame = handleOutOfBoundsCollision(newHead);
console.log('@stopGame: handleOutOfBoundsCollision', stopGame);
}
if (!stopGame) {
stopGame = handleSelfCollision(newHead);
console.log('@stopGame: handleSelfCollision', stopGame);
}
if (!stopGame) {
stopGame = handleFoodCollision(newHead);
console.log('@stopGame: handleFoodCollision', stopGame);
}
if (!stopGame) {
// in case nothing interrupt the movement, we can move the player
playerPath.unshift(newHead);
// bonus for movement
score += scoreConstants.movement;
// re-draw player
drawPlayer();
// re-draw food
drawFood();
// display scores on UI
renderScores();
}
if (stopGame) {
resetGame();
}
}
function guessMovementDirection(event) {
console.log('guessMovementDirection');
// some logic to avoid moving backwards
if (event.keyCode === 37 && movementDirection !== "right") {
movementDirection = "left";
} else if (event.keyCode === 38 && movementDirection !== "down") {
movementDirection = "up";
} else if (event.keyCode === 39 && movementDirection !== "left") {
movementDirection = "right";
} else if (event.keyCode === 40 && movementDirection !== "up") {
movementDirection = "down";
}
return movementDirection;
}
function guessPlayerMovement() {
// initialize as current head
var newHead = {
x: playerPath[0].x,
y: playerPath[0].y,
}
// then move player's head according to direction
if (movementDirection === "left") {
newHead.x -= boxWidth;
}
if (movementDirection === "up") {
newHead.y -= boxHeight;
}
if (movementDirection === "right") {
newHead.x += boxWidth;
}
if (movementDirection === "down") {
newHead.y += boxHeight;
}
return newHead;
}
function isFoodCollision(position) {
if (position.x === foodPosition.x && position.y === foodPosition.y) {
return true;
}
return false;
}
function handleFoodCollision(position) {
console.log('handleFoodCollision');
if (isFoodCollision(position)) {
score += scoreConstants.food;
foodPosition = randomFoodPosition();
}
return false;
}
function handleOutOfBoundsCollision(position) {
console.log('handleOutOfBoundsCollision');
// make a copy of position (new player's head)
var originalPosition = Object.assign({}, position);
// check if player is out of bounds then adjust position accordingly
if (position.x < minWidth) {
position.x = maxWidth - boxWidth;
}
if (position.x > maxWidth - boxWidth) {
position.x = minWidth;
}
if (position.y < minHeight) {
position.y = maxHeight - boxHeight;
}
if (position.y > maxHeight - boxHeight) {
position.y = minHeight;
}
// if position is different than original, then player is out of bounds
if (originalPosition.x !== position.x || originalPosition.y !== position.y) {
if (config.outOfBoundsCausesGameOver) {
alert('out of bounds - game over!');
return true;
}
if (!config.outOfBoundsCausesGameOver) {
// punish player for going out of bounds
score += scoreConstants.outOfBounds;
}
}
return false;
}
function handleSelfCollision(position) {
console.log('handleSelfCollision');
var stopGame = false;
// check if player is colliding with itself
playerPath.forEach(function (body, idx) {
if (position.x === body.x && position.y === body.y) {
if (config.selfCollisionCausesGameOver) {
alert('self collision - game over!');
stopGame = true;
}
if (!config.selfCollisionCausesGameOver) {
// punish player for self collision
score += scoreConstants.selfCollision;
}
}
});
return stopGame;
}
function resetGame() {
console.log('resetGame');
movementDirection = "right";
playerPosition = safePlayerPosition;
if (!config.defaultPlayerSpawn) {
playerPosition = randomPlayerPosition();
}
playerPath = [];
playerPath.push(playerPosition);
foodPosition = safeFoodPosition;
if (!config.defaultFoodSpawn) {
foodPosition = randomFoodPosition();
}
drawGrid();
drawPlayer();
drawFood();
score = 0;
renderScores();
}
function renderScores() {
console.log('renderScores');
updateScoreElement();
if (score > maxScore) {
maxScore = score;
persistMaxScore();
}
updateMaxScoreElement();
}
initGame();
@shakkurcwb
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment