Skip to content

Instantly share code, notes, and snippets.

@forestbelton
Created April 6, 2013 03:41
Show Gist options
  • Save forestbelton/5324654 to your computer and use it in GitHub Desktop.
Save forestbelton/5324654 to your computer and use it in GitHub Desktop.
A simple snake game
# Copyright (C) 2011 Forest Belton
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# Constants.
[DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT] = [0, 1, 2, 3]
[KEYCODE_SPACE, KEYCODE_LEFT, KEYCODE_RIGHT] = [32, 37, 39]
# Global variables.
ctx = null # Drawing context for the canvas.
id = null # ID for the update interval timer.
game = false # Whether the game has started or not.
dir = DIR_UP # Current direction of the snake.
[x, y] = [5, 5] # Current position of the snake.
body = [] # Coordinate list of the snake's body.
snack = [0, 0] # Location of the current snack on the screen.
# Configuration variables.
width = 0
height = 0
cellsize = 20
$(document).keydown (event) ->
if not game and event.keyCode is KEYCODE_SPACE
id = setInterval update, 100
game = true
switch event.keyCode
when KEYCODE_LEFT then dir = (dir + 3) % 4
when KEYCODE_RIGHT then dir = (dir + 1) % 4
$(document).ready ->
# Get the canvas drawing context.
canvas = document.getElementById 'canvas'
ctx = canvas.getContext '2d'
# Set the grid size based on the canvas' size.
width = canvas.width / cellsize
height = canvas.height / cellsize
# Draw the snake and make the first snack.
fillCell x, y, 'blue'
newSnack()
update = () ->
ateSnack = false
# Clear previous snake graphic on the canvas.
fillCell x, y, 'empty'
fillCell piece[0], piece[1], 'empty' for piece in body
# Update positions for the snake's body.
body = [[x, y]].concat(body)
# Update the snake's head position.
switch dir
when DIR_UP then [x, y] = [x, y - 1]
when DIR_RIGHT then [x, y] = [x + 1, y]
when DIR_DOWN then [x, y] = [x, y + 1]
when DIR_LEFT then [x, y] = [x - 1, y]
# Check for collision with the snack.
if x == snack[0] and y == snack[1]
ateSnack = true
newSnack()
if gameOver()
clearInterval id
return
# Keep the old body piece if we just ate a snack.
if not ateSnack
body.pop()
# Draw the snake.
fillCell x, y, 'blue'
fillCell piece[0], piece[1], 'blue' for piece in body
# Check for game over conditions.
# - Condition #1: The snake has hit the boundaries of the game board.
# - Condition #2: The snake has collided with itself.
gameOver = () ->
# Check for condition #1.
if x < 0 or x > (width - 1)
return true
if y < 0 or y > (height - 1)
return true
# Check for condition #2.
collided = false
for piece in body
do (piece) ->
if x == piece[0] and y == piece[1]
collided = true
return collided
newSnack = () ->
done = false
until done
collision = false
# Generate new coordinates.
snack[0] = Math.floor(Math.random() * width)
snack[1] = Math.floor(Math.random() * height)
# Check to see if the coordinates are already in use.
if snack[0] == x and snack[1] == y
collision = true
for piece in body
do (piece) ->
if snack[0] == piece[0] and snack[1] == piece[1]
collision = true
done = not collision
# Redraw snack at new coordinates.
fillCell snack[0], snack[1], 'red'
fillCell = (i, j, color) ->
if color is 'empty'
ctx.clearRect cellsize * i, cellsize * j, cellsize, cellsize
else
ctx.fillStyle = color
ctx.fillRect cellsize * i, cellsize * j, cellsize, cellsize
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/coffeescript" src="snake.coffee"></script>
<script type="text/javascript" src="coffee-script.js"></script>
<style>
#root {
width: 300;
height: 300;
margin-left: auto;
margin-right: auto;
}
#canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<div id="root">
Directions: Left/Right to turn left and right, respectively.
Press space to start.
<br><br>
<canvas id="canvas" width="300" height="300"></canvas>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment