Today I felt like making a game, so I learnt about Phaser and set myself the task/challenge of recreating a simple game from my childhood. Phaser is incredibly fun and easy to get started, I’d recommend giving it a go!
The game I chose was Tanx.
I started with the excellent Phaser tutorial and converted it to CoffeeScript. It’s perfectly fine to use CoffeeScript with Phaser, or I guess any other language that compiles to JavaScript.
It’s very rough and I only spent a few hours on it, but it gives you an idea of what you can make with this framework, even without any prior knowledge!
Instructions:
Try to shoot the other player by adjusting the angle and power. From the left, try an angle of about -30. From the right, try an angle of about 210.
Keys:
UP/DOWN: adjust angle A/Z: adjust power LEFT/RIGHT: pan screen SPACE: fire / start new game
Full source code:
GAME_WIDTH = 1200
currentAngle =
currentPower = 500
maxPower = 600
cursors = null
current_player = null
font = null
win_message = null
tanks = null
firing = false
game_over = false
toRad = (angle) ->
angle * Math.PI / 180
loadFonts = =>
@angle = game.add.retroFont ‘knightHawks’, 31, 25, Phaser.RetroFont.TEXT_SET6, 10, 1, 1
@power = game.add.retroFont ‘knightHawks’, 31, 25, Phaser.RetroFont.TEXT_SET6, 10, 1, 1
bulletHit = (body, shapeA, shapeB, equation) ->
firing = false
this.kill()
if body.sprite.parent == tanks
game_over = true
win = game.add.retroFont ‘knightHawks’, 31, 25, Phaser.RetroFont.TEXT_SET6, 10, 1, 1
win.text = current_player.name + ’ wins!’
win_message = game.add.image 60, 300, win
win_message.fixedToCamera = true
win_message.cameraOffset.x = 60
else
nextTurn()
changeAngle = (diff) ->
setAngle(currentAngle + diff)
setAngle = (angle) =>
currentAngle = angle
@angle.text = ‘angle: ‘ + currentAngle
changePower = (diff) ->
setPower(currentPower + diff)
setPower = (power) =>
currentPower = power
@power.text = ‘power: ‘ + currentPower
resetAngleAndPower = ->
setAngle
setPower 200
nextTurn = ->
resetAngleAndPower()
current_player = if current_player == @player
setAngle 180
@player2
else
setAngle
@player
resetCamera()
resetCamera = ->
game.camera.target = current_player
resetGame = ->
game_over = false
current_player = @player
resetCamera()
resetAngleAndPower()
win_message.destroy()
fireBullet = =>
unless firing
# create a bullet
angle = currentAngle
power = currentPower
# calculate velocity
x_velocity = Math.cos(toRad(angle)) power
y_velocity = Math.sin(toRad(angle)) power
cp = current_player
#offset to avoid shooting self
offset_x = if angle > 90 || angle < -90
-32
else
32
<span class="c1"># create the sprite and set it going</span>
<span class="nv">bullet = </span><span class="nx">game</span><span class="p">.</span><span class="nx">add</span><span class="p">.</span><span class="nx">sprite</span> <span class="nx">cp</span><span class="p">.</span><span class="nx">x</span> <span class="o">+</span> <span class="nx">offset_x</span><span class="p">,</span> <span class="nx">cp</span><span class="p">.</span><span class="nx">y</span><span class="p">,</span> <span class="s">'bullet'</span>
<span class="nx">game</span><span class="p">.</span><span class="nx">physics</span><span class="p">.</span><span class="nx">p2</span><span class="p">.</span><span class="nx">enable</span> <span class="nx">bullet</span>
<span class="nv">bullet.body.velocity.x = </span><span class="nx">x_velocity</span>
<span class="nv">bullet.body.velocity.y = </span><span class="nx">y_velocity</span>
<span class="nx">bullet</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">onBeginContact</span><span class="p">.</span><span class="nx">add</span> <span class="nx">bulletHit</span><span class="p">,</span> <span class="nx">bullet</span>
<span class="nx">game</span><span class="p">.</span><span class="nx">camera</span><span class="p">.</span><span class="nx">follow</span> <span class="nx">bullet</span>
<span class="nv">firing = </span><span class="kc">true</span>
@preload = ->
game.load.image ‘sky’, ’/games/assets/sky.png’
game.load.image ‘ground’, ’/games/assets/platform.png’
game.load.image ‘bullet’, ’/games/assets/ball.gif’
game.load.spritesheet ‘dude’, ’/games/assets/dude.png’, 32, 48
game.load.image ‘knightHawks’, ’/games/assets/fonts/KNIGHT3.png’
@create = =>
game.world.setBounds , , GAME_WIDTH, 600
game.physics.startSystem Phaser.Physics.P2JS
game.physics.p2.gravity.y = 100
game.physics.p2.defaultRestitution = 0.9
game.physics.p2.setImpactEvents true
sky = game.add.tileSprite , , 2000, 600, ‘sky’
# create the ground sprite and set to static
@ground = game.add.sprite , game.world.height - 48, ‘ground’
@ground.scale.setTo 6,3
game.physics.p2.enable @ground
@ground.body.static = true
# create the ’tanks’
tanks = game.add.group()
@player = tanks.create 32, game.world.height - 150, ‘dude’
@player.frame = 5
@player.name = ‘Player 1’
@player2 = tanks.create GAME_WIDTH - 120, game.world.height - 150, ‘dude’
@player2.name = ‘Player 2’
# angle / power text
loadFonts()
@ang = game.add.image 30, 30, @angle
ang.fixedToCamera = true
ang.cameraOffset.x = 30
pow = game.add.image 30, 60, @power
pow.fixedToCamera = true
pow.cameraOffset.x = 30
setPower currentPower
setAngle currentAngle
# enable physics!
tanks.forEach (thing) ->
game.physics.p2.enable(thing)
thing.body.gravity.y = 100
# set first player
current_player = @player
game.physics.p2.setImpactEvents true
cursors = game.input.keyboard.createCursorKeys()
game.input.keyboard.addKeyCapture Phaser.Keyboard.SPACEBAR
@update = ->
if game_over
if game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)
resetGame()
else
if cursors.right.isDown
game.camera.target = null
game.camera.x += 8
if cursors.left.isDown
game.camera.target = null
game.camera.x -= 8
if cursors.up.isDown
changeAngle -1
if cursors.down.isDown
changeAngle 1
if game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)
fireBullet()
if game.input.keyboard.isDown(Phaser.Keyboard.A)
changePower 1
if game.input.keyboard.isDown(Phaser.Keyboard.Z)
changePower -1
@game = game = new Phaser.Game(800, 600, Phaser.CANVAS, ‘tanks’, { preload: preload, create: create, update: update })