Created
March 29, 2013 00:44
-
-
Save zspecza/df23db9dbc546f5b11d8 to your computer and use it in GitHub Desktop.
See demo at http://solopong.declandewet.mixture.io/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
# Solo Pong - Declan de Wet | |
# TODO: Prevent paddle from going out of the viewport | |
# TODO: Implement collision animations | |
# TODO: Music and sound | |
# TODO: Keyboard controls | |
### | |
# Create a self-instantiating shim/polyfill for the requestAnimationFrame API, if it does not exist, | |
# then fall back to setTimeOut set to 60fps (average) | |
do -> | |
lastTime = 0 | |
vendors = ["webkit", "moz"] | |
x = 0 | |
while x < vendors.length and not window.requestAnimationFrame | |
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"] | |
window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] or window[vendors[x] + "CancelRequestAnimationFrame"] | |
++x | |
unless window.requestAnimationFrame | |
window.requestAnimationFrame = (callback, element) -> | |
currTime = new Date().getTime() | |
timeToCall = Math.max(0, 16 - (currTime - lastTime)) | |
id = window.setTimeout(-> | |
callback currTime + timeToCall | |
, timeToCall) | |
lastTime = currTime + timeToCall | |
id | |
unless window.cancelAnimationFrame | |
window.cancelAnimationFrame = (id) -> | |
clearTimeout id | |
# We'll need to set this to some arbitrary value for now - it changes later, but we need it to keep | |
# track of the requestAnimationFrame if we ever need to stop the animation | |
animID = 0 | |
jQuery -> | |
# Get the canvas 2D context | |
canvas = $('#canvas') | |
can = canvas[0] | |
ctx = can.getContext '2d' if can.getContext | |
# Initialize some movement parameters | |
dirX = 6 | |
dirY = 8 | |
# Set the width and height of the canvas to the full window's width and height | |
can.width = $(window).width() | |
can.height = $(window).height() | |
# Find out the canvas' relaive Y position | |
can.minY = $("#canvas").offset().top; | |
can.maxY = can.minY + can.height; | |
# Move the paddle with the mouse | |
onMouseMove = (e) -> | |
if e.pageY > can.minY and e.pageY < can.maxY | |
paddle.posY = (e.pageY - can.minY) - paddle.height / 2 | |
# Initialize the player's score and number of lives so we can keep track | |
score = 0 | |
lives = 0 | |
# Instantiate the ball object and set it's size and position | |
ball = {} | |
ball.size = 10 | |
ball.posX = can.width / 2 - ball.size / 2 | |
ball.posY = Math.round(Math.random() * can.height) # We don't always want it to start in the same place | |
# Instantiate the paddle object | |
paddle = {} | |
paddle.width = 10 | |
paddle.height = can.height / 2 | |
paddle.posX = can.width - paddle.width | |
paddle.posY = can.height / 2 - paddle.height / 2 | |
# Create some drop-in functions for clearing and creating shapes, keeping it DRY | |
clear = -> | |
ctx.clearRect 0, 0, can.width, can.height | |
circle = (x, y, r, color) -> | |
ctx.fillStyle = color | |
ctx.beginPath() | |
ctx.arc(x, y, r, 0, Math.PI*2, true) | |
ctx.closePath() | |
ctx.fill() | |
rect = (x, y, w, h, color) -> | |
ctx.fillStyle = color | |
ctx.beginPath() | |
ctx.rect(x, y, w, h) | |
ctx.fill() | |
# Set up a draw function that will be called at each animation frame | |
draw = -> | |
# clear the canvas before we re-draw | |
do clear | |
# Display player's current score and remaining lives | |
ctx.font = '15pt Calibri' | |
ctx.fillStyle = 'white' | |
ctx.fillText "Score: #{score} Lives: #{lives}", 20, 30 | |
# Instantiate the ball | |
circle(ball.posX, ball.posY, ball.size, 'red') | |
# Make the ball bounce | |
if ball.posX + dirX < ball.size | |
dirX = -dirX | |
# ...except if it passes the paddle | |
else if ball.posX + dirX > can.width - ball.size | |
# The paddle hit the ball! hooray! | |
if ball.posY > paddle.posY and ball.posY < paddle.posY + paddle.height | |
# Counter momentum | |
dirX = -dirX | |
# Let's reward the player :) | |
if score <= 50 | |
score += 5 | |
lives = 1 | |
else if score <= 250 | |
score += 10 | |
lives = 2 | |
# This time we make the paddle smaller so it's more of a challenge | |
paddle.height = can.height / 3 | |
else if score <= 500 | |
score += 50 | |
lives = 3 | |
paddle.height = can.height / 5 | |
else if score <= 1000 | |
score += 100 | |
lives = 5 | |
paddle.height = can.height / 7 | |
else if score <= 5000 | |
score += 1000 | |
lives = 10 | |
paddle.height = can.height / 10 | |
else | |
score += 1500 | |
# uh oh :( the player missed the ball. Better penalize them | |
else | |
# stop the animation so we don't decrement by 1 for every frame | |
window.cancelAnimationFrame animID | |
lives-- | |
# clear the canvas, reset the ball and... | |
clear() | |
ball.posX = can.width / 2 - ball.size / 2 | |
ball.posY = Math.round(Math.random() * can.height) | |
# ...restart the animation | |
window.requestAnimationFrame animloop | |
# Move the ball! | |
dirY = -dirY if ball.posY + dirY > can.height - ball.size or ball.posY + dirY < ball.size | |
ball.posX += dirX | |
ball.posY += dirY | |
# create the paddle | |
rect(paddle.posX, paddle.posY, paddle.width, paddle.height, 'yellow') | |
# update the canvas if the window ever gets resized | |
resize = -> | |
can.width = $(window).width() | |
can.height = $(window).height() | |
do draw | |
# A nice function representing our animation loop | |
animloop = -> | |
# Here's where we change that necessary identifier in earlier comments | |
animID = requestAnimationFrame(animloop) | |
# Has the player lost all of their lives? | |
if lives < 0 | |
# Oh no, they have! Better stop the game and tell them their score. | |
clear() | |
ctx.font = '30pt Calibri' | |
ctx.textAlign = 'center' | |
ctx.fillStyle = 'white' | |
ctx.fillText "SCORE: #{score}", can.width / 2, can.height / 2 | |
ctx.font = '15pt Calibri' | |
ctx.fillText "Created by Declan de Wet (declandewet@me.com)", can.width / 2, (can.height / 2) + 40 | |
# No, they haven't - DRAW! | |
else draw() | |
return animID | |
init = -> | |
do animloop | |
$(window).on 'resize', resize | |
$(document).on 'mousemove', onMouseMove | |
do init |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment