body
  #wrapper
    #game
    .buttons
      h2 Switch Players 
        i(class='fa fa-caret-down')
      a(id='player1' class='player active') player 1
      a(id='player2' class='player') player 2
  
  #fi(style="display:none; text-align:center; position:absolute; bottom:15px; right:15px; width:280px; font-family:'Lato', arial, helvetica; background:rgba(255,255,255,0.3); padding:8px 15px;" )
    P <strong>Like Indie Games? Got $5?</strong><br><a href="https://www.fiverr.com/ebrewe/build-a-simple-game?display_share=true" target="_blank" style="display:block; padding:5px 8px; color:white; background:#00b22d; font-weight:bold; text-decoration:none!important; text-align:center; border-bottom:3px solid #00920d; margin:0.5em 0;">Find me on Fiverr.com</a> to see what those two things have in common! 
View Compiled
.clearfix {
  zoom: 1;
	&:before, &:after { content: ""; display: table; }
	&:after { clear: both; }
}
@mixin css-gradient($from: #dfdfdf, $to: #f8f8f8) {
	background-color: $to;
	background-image: -webkit-gradient(linear, left top, left bottom, from($from), to($to));
	background-image: -webkit-linear-gradient(top, $from, $to);
	background-image: -moz-linear-gradient(top, $from, $to);
	background-image: -o-linear-gradient(top, $from, $to);
	background-image: linear-gradient(to bottom, $from, $to);
}

//colours
$black: #312736;
$red: #d4838f;
$greyred: #d6abb1;
$green: #63b789;
$grey: #d9d9d9;
$blue: #c4ffeb;

 
* {box-sizing:border-box; }

body{
  display:block; 
  background:#999;
}

#wrapper {
  display:block;
  width:90%;
  height:auto;
  margin:0 auto; 
}

.buttons {
  display:block;
  font-family:arial, helvetica, sans-serif; 
  padding:20px; 
  border-radius:4px; 
  border:1px solid darken($grey, 40%);
  position:absolute;
  bottom:20px; 
  left:20px; 
  z-index:99; 
  
  h2 {
    font-weight:700;
    font-size:18px; 
    margin:0 0 10px; 
    color:#282828; 
  }
  
  a {
    display:block;
    float:left;
    border:1px solid darken($grey, 39%); 
    padding:10px 15px;
    border-radius:3px; 
    background:$grey;
    color:#3d3d3d; 
    margin-right:5px; 
    cursor:pointer; 
    &:hover {
      background:darken($grey, 13%);  
    }
    &:active{
      box-shadow:inset 0 2px 1px rgba(0,0,0,0.5);  
    }
    &.active {
      background:$green; 
      border-color:darken($green, 27%); 
      color: lighten($green, 40%); 
    }
  }
  
}
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~ Main game class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class Game

  constructor:(@container, @tileSize, {viewWidth, viewHeight, scale, iso} = {}) ->
    
    viewWidth ?= 600
    viewHeight ?= 400
    scale ?= 1
    iso ?= false
  
    @viewWidth = viewWidth
    @viewHeight = viewHeight 
    @scale = scale
    @iso = iso
    
  run: ->
    @setup()
    @then = Date.now()
    setInterval @tick, 30
    
    
  setup: ->
    @world = new World @container, @tileSize, @viewWidth, @viewHeight, @scale, @iso
    @inputHandler = new InputHandler( @world )
    
  update:(modifier) ->
    @inputHandler.update(modifier)
    @world.update()
  
  tick: =>
    now = Date.now()
    delta = now - @lastUpdate
    @lastUpdate = now
    @lastElapsed = delta
    @update(delta / 1000)
    @world.draw()

  
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The World Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class World
  
  constructor: (@container, tileSize, @viewWidth, @viewHeight, @scale, @iso) ->
    @debug = false
    
    @tileWidth = if @iso then tileSize * 2 * @scale else tileSize * @scale
    @tileHeight = tileSize * @scale
    
    @ctx = @createCanvas()
    @sprites = []
    @scrollX = 0
    @scrollY = 0
    @quickScroll = false
    @collisions = []
    @collisionIndex = {}
    @controls = []
    @inventory = []
    
  createCanvas: ->
    container = document.getElementById @container
    canvas = document.createElement('canvas')
    canvas.setAttribute('id', 'eNgine_canvas')
    canvas.width = @viewWidth
    canvas.height = @viewHeight
    container.appendChild canvas
    
    @canvas = canvas
    @canvas.getContext('2d')
    
  createWorld: (@map) ->
    ###
    create a collision map based on the map
    switch all unwalkable tiles to 1s on cmap
    for pathfinding
    ###
    
    @cMap = @map
    for row in @cMap
      for tile in row
        if row[tile] is not 0
          row[tile] = 1
          
    @createBackground( @map )
    @createPFGrid( @cMap )
    
  createBackground: (map) =>
    @background = new Background this, map
    
  createPFGrid: (cMap )->
    @grid = new PF.Grid( cMap[0].length, cMap.length, cMap)
	  #@finder = new PF.AStarFinder()
    @finder = new PF.BreadthFirstFinder()
    
  update: (modifier) ->
    if @background
      for tile in @background.tiles
        tile.update()
    @sortSprites @sprites
    sprite.update() for sprite in @sprites
    
    @collisionCheck(@sprites)
    
    
    if @player.rX < 200
      @scrollX -= if @quickScroll then @tileWidth else 3
    if @player.rX > @viewWidth - 200
      @scrollX += if @quickScroll then @tileWidth else 3
    if @player.rY < 50
      @scrollY -= if @quickScroll then @tileHeight else 3
    if @player.rY > @viewHeight - 50
      @scrollY += if @quickScroll then @tileHeight else 3
    
    if @player.rX > 200 and @player.rX <= (@viewWidth - 200) and @player.rY > 50 and @player.rY <= (@viewHeight - 50)
      @quickScroll = false
    
  sortSprites: (sprites) ->
    sprites = sprites.sort (a,b)->
      return if a.z > b.z then 1 else - 1
    
  collisionCheck: (sprites)->
    @collisions = []
    @collisionIndex = {}
    for spriteA in sprites
      if spriteA.collides
      
        #check this sprite against all other sprites
        for spriteB in sprites
             if spriteB != spriteA and spriteB.collides
               
               #check for collision between sprites
               ###
               if less than half a tile height above
               or less than half a tile height below
               and less than half a tile width beside
               ###
               colY = Math.abs spriteB.y - spriteA.y
               colX = Math.abs spriteB.x - spriteA.x
               if colY < @tileHeight / 2 and colX < @tileWidth/ 2
                 @collisions.push spriteA
                 @collisions.push spriteB
                 @collisionIndex[spriteA.name] = spriteB
    
  draw: ->
    @ctx.clearRect 0, 0, @viewWidth, @viewHeight
    if @background    
      for tile in @background.tiles
        tile.draw()
    sprite.draw() for sprite in @sprites


          
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Input Handler Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class InputHandler
  
  keysDown : {}
  clicked: false
  
  constructor: (@world) ->
    @bindMouse()  
  
  bindMouse: =>
    that = this
    @world.canvas.addEventListener('mousemove', (evt)->
      that.mousePos = that.getMousePos(evt)
    )
    
  getMousePos:(evt) ->
    rect = @world.canvas.getBoundingClientRect()
    { x: evt.clientX - rect.left, y: evt.clientY - rect.top }
    

  update: (modifier) ->
    
    ### 
    clear previous flags
    ###
    
    for i in [0 .. @world.background.tiles.length]
      if @world.background.tiles[i]
        @world.background.tiles[i].clearFlags 'hover'
    ###
    main input update
    ###
    if @world.background and @world.background.ready and @mousePos and @mousePos.x > 0 and @mousePos.x < @world.viewWidth and @mousePos.y > 0 and @mousePos.y < @world.viewHeight
      
      if @world.iso
        tileX = Math.floor ( (@mousePos.x + @world.scrollX)  / @world.tileWidth ) + ( (@mousePos.y + @world.scrollY)  / @world.tileHeight) - .5 
        tileY = Math.floor ( (@mousePos.y + @world.scrollY) / @world.tileHeight ) - ( (@mousePos.x + @world.scrollX) / @world.tileWidth) + .5
      else
        tileX = Math.floor (@mousePos.x + @world.scrollX) / @world.tileWidth
        tileY = Math.floor (@mousePos.y + @world.scrollY) / @world.tileHeight
      
     
           
      if @world.background.mapTiles[tileY] 
        if @world.background.mapTiles[tileY][tileX]
          theTile = @world.background.mapTiles[tileY][tileX]  
          if theTile.walkable
            theTile.setFlags('hover') 
            
            if @clicked
              onPlayer = false
                
              for tile in @world.background.tiles
                tile.clearFlags 'selected'
                tile.clearFlags 'path'
              #if @world.player.path
                #for tile in @world.player.path
                  #@world.background.mapTiles[tile[1]][tile[0]].clearFlags 'path'
              theTile.setFlags 'selected'
              
              ###
              Pathfinding
              ###
              pcoords = @world.player.getTile()
              goalX = theTile.rX
              goalY = theTile.rY
              
              
              for sprite in @world.sprites
                if sprite.entType and sprite.entType == 'player'
                    if sprite.myTile.rX == goalX and sprite.myTile.rY == goalY
                        #occupado
                        onPlayer = true
                        
              if onPlayer
                @clicked = false
                return false
                        
              gridClone = @clone @world.grid
              path = @world.finder.findPath pcoords.x, pcoords.y, tileX, tileY, gridClone
              for tile in path
                @world.background.mapTiles[tile[1]][tile[0]].setFlags 'path'
              if path and path[0]            
                @world.background.mapTiles[ path[0][1] ][path[0][0]].clearFlags 'path'
                @world.player.walkPath path
      
    ###
    clear click
    ###
    @clicked = false
    
  clone: (obj) ->
    if not obj? or typeof obj isnt 'object'
      return obj
	
    if obj instanceof Date
      return new Date(obj.getTime()) 
	
    if obj instanceof RegExp
      flags = ''
      flags += 'g' if obj.global?
      flags += 'i' if obj.ignoreCase?
      flags += 'm' if obj.multiline?
      flags += 'y' if obj.sticky?
      return new RegExp(obj.source, flags) 
	
    newInstance = new obj.constructor()
	
    for key of obj
      newInstance[key] = @clone obj[key]
	
    newInstance
	  
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Sprite Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###
class SpriteImage

  ready: false
  
  constructor:(@url = 'images/spritesheet.png', world, sprite) ->
    image = new Image
    #image = document.createElement('img')
    image.src = @url
    @image = image
    @image.onload= => 
      @ready = true
      #if world.debug
        #console.log 'created a ' + sprite

class Sprite

  x: 0 #world-relative x
  y: 0 #world-relative y
  w: 0
  h: 0
  z: 0
  zIndex: 0
  name: 'sprite'
  collides: false
  ready: false
  image: false
  frame:0
  animationFrames: 0
  
  constructor: (@world, url) ->
    if url
      @image = new SpriteImage url, @world, @name
    console.log @name, @world if @world.debug
    @rX = @x
    @rY = @y
    @z = @rY
    @world.sprites.push this unless @name is 'tile' 
    
  setAnimationFrames: (frames) ->
    @animationFrames = frames
    
  update: (modifier) ->
    @rX = @x - @world.scrollX
    @rY = @y - @world.scrollY
    
    @z = @rY + @zIndex
    
  draw: ->
    if @image.image and @image.ready 
       sx = ( @w * @frame )
       w = @w 
       h =  @h 
       sy = 0
       try
         @world.ctx.drawImage( @image.image, sx, sy, w, h, @rX , @rY, @w * @world.scale, @h * @world.scale )
       catch error
         console.log  @image.image, 0,0, 0, 0, @rX , @rY, @w, @h
         console.log 'effin ' + error
         
  drawFrame: (frame) ->
    sx = 0 
    sy = 0
    @world.ctx.drawImage( @image, sx, sy, @rX, @rY, @w, @h )
    
      
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Background Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class Background 

  constructor: (@world, map) ->
    @x = 0
    @y = 0
    @w = 0
    @h= 0
    @rX = @x
    @rY = @y
    @tiles = []
    @mapTiles =[]
    @map = map
    
    for rIndex, row of @map
      @mapTiles[rIndex] = []
      #TODO go backwards to render in sequence
      for i in [row.length-1..0] by -1
        cIndex = i
        column = row[cIndex]       
        w= @world.tileWidth
        h= @world.tileHeight
        x = cIndex
        y = rIndex
        tileNo = [cIndex, rIndex] 
        walkable = true
        if column != 0 then walkable = false
        
        if @world.iso
          isoCoords = @twoDToIso x, y, w, h 
          tile = new DrawnTile @world, isoCoords.x, isoCoords.y, @world.tileWidth, @world.tileHeight, column, tileNo, walkable
        else
          x = cIndex * w
          y = rIndex * h
          tile = new Tile @world, x, y, @world.tileWidth, @world.tileHeight, 'tile', tileNo, walkable
          
        @tiles.push tile
        @mapTiles[rIndex][cIndex] = tile 
        
        
    @ready = true
    console.log @tiles if @world.debug
        
  twoDToIso: (x, y, w, h)->
    isoX = (x * w / 2) - (y * w / 2)
    isoY = (y * h / 2) + (x * h / 2)
    {x: isoX, y: isoY}
    
  backgroundSize: ->
    
        
  update: (modifier) ->
    super()  
  
 
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Tile Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class Tile extends Sprite
  
  constructor: (@world, @x, @y, @w, @h, @type = 0, @tileNo = [0, 0], @walkable=true)->
    # super @world, 'images/gameTile.png'
    super()
    @name = 'tile'
    # image = @getType()
    @color = 'rgba(0,0,255,' + (parseInt(@tileNo[0]) / 10) + ')'
    @flags = {}
    @tileFrame = @getTileFrame()
    
  update: (modifier)->
    @rX = @x - @world.scrollX
    @rY = @y - @world.scrollY
    
    
      
    ###
    different tiles
    ###
    @frame = @tileFrame
    
    if @flags.hover
      @frame = 1
    if @flags.selected
      @frame = 2
    if @flags.path
      @frame = 3
    
  draw: (frame = 0)->
    #@world.ctx.fillStyle = '#d6abb1'
    #@world.ctx.fillRect @x, @y, @w, @h
    if @world.debug
      @world.ctx.strokeStyle = @color
      @world.ctx.strokeRect @rX, @rY, @w, @h
      
    
    if @image.ready
    
       sx = ( @w * @frame ) 
       sy = 0
       @world.ctx.drawImage( @image.image, sx / @world.scale, sy, @w / @world.scale, @h / @world.scale, @rX , @rY, @w, @h )
      
    
  setFlags: (flag)->
    @flags[flag] = true
  
  clearFlags: (flag)->
    @flags[flag] = false
  
  
     
  getTileFrame: ->
    tileFrames=
      0: 0,
      1: 0,
      2: 4,
      3: 5,
      4: 6,
      5: 7
      
    tileFrames[@type]
      
  getType: ->
    tileTypes= 
      'tile': 'images/gameTile.png',
      'isoTile': 'images/gameTileIso.png',
      
     type = if @world.iso then 'isoTile' else 'tile'
     tileTypes[type]
     
class DrawnTile extends Tile
  colour: ''
  
  constructor: (@world, @x, @y, @w, @h, @type = 0, @tileNo = [0, 0], @walkable=true) ->
    super()
    @defaultColour = '#d6abb1'
    if @type is 1 then @defaultColour = 'rgba(0,0,0,0)'
    
    
  update: (modifier)->
  
    @rX = @x - @world.scrollX
    @rY = @y - @world.scrollY
    
    @colour = @defaultColour
    if @flags.path
      @colour = @getColour 'path'
    if @flags.hover
      @colour = @getColour 'hover'
    if @flags.selected
      @colour = @getColour 'selected'
    if @flags.occupied
      @colour = @getColour 'occupied'

  draw: ->
    @world.ctx.fillStyle = @colour
    @world.ctx.beginPath()
    @world.ctx.moveTo @rX + (@world.tileWidth / 2), @rY
    @world.ctx.lineTo @rX + @world.tileWidth, @rY + (@world.tileHeight / 2)
    @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
    @world.ctx.lineTo @rX, @rY + (@world.tileHeight / 2)
    @world.ctx.closePath()
    @world.ctx.fill()
    
    
  getColour: (flag) ->
    colours=
      hover: '#cd8791',
      selected: 'white',
      path:  '#f1d2d6',
      occupied: '#0000ff'
      
    colours[flag]
      
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The platform Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###
class Platform extends Sprite

  name: 'platform'
  vx: 0
  vy: 0
  collides: true
  active: false
  
  constructor: (@world, @x, @y, @w, @h, @moving= false, @startPos = [], @endPos = [], @startGrid=[], @endGrid=[], speed = 1.5)->
    super()
    image = false
    @defaultColour = 'blue'
    @activeColour = 'yellow'
    @inMotion = false
    @speedY = speed
    @speedX = if @world.iso then speed * 2 else speed
    @direction = 1
    @waiting = false
    @startX = @startPos[0]
    @startY = @startPos[1]
    @endX = @endPos[0]
    @endY = @endPos[1]
    @zIndex = 0
    # super @world, image
    
  update: (modifier)=>
    if !@waiting and @active
      if @inMotion
        @move()
    
    
    @vx = 0 unless @x != @targetX
    @vy = 0 unless @y != @targetY
    
    @x += @vx
    @y += @vy
    
    
    @rX = @x - @world.scrollX
    @rY = @y - @world.scrollY
    
    
    
    @colour =  if @active then @activeColour else @defaultColour 
    @z = @rY + @zIndex
    
  startMoving: ->
    @inMotion = true
    
  stopMoving: -> 
    @inMotion = false
    
  changeDirection: (direction) =>
    that = this
    if @world.debug then console.log 'platform changing direction to ' + direction
    @stopMoving()
    @waiting = true
    setTimeout ()->
      that.waiting = false
      that.startMoving()
    , 2000
    @direction = direction
    
      
  move:  ->
  
    if @direction == false
      @targetX = @endX
      @targetY = @endY
      @targetGrid = @endGrid
    else
      @targetX = @startX
      @targetY = @startY
      @targetGrid = @startGrid
      
    
    
    deltaX = @x - @targetX
    deltaY = @y - @targetY    
    
    @world.grid.setWalkableAt(@startGrid[0], @startGrid[1], false)
    @world.grid.setWalkableAt(@endGrid[0], @endGrid[1], false)
    @world.background.mapTiles[@startGrid[1]][@startGrid[0]].walkable= false
    @world.background.mapTiles[@endGrid[1]][@endGrid[0]].walkable= false
    
    if deltaY == 0 and deltaX == 0
      @world.grid.setWalkableAt(@targetGrid[0], @targetGrid[1], true)
      @world.background.mapTiles[@targetGrid[1]][@targetGrid[0]].walkable= true
      return @changeDirection !@direction   
      
    
    if deltaY != 0
      @vy = if deltaY > 0 then -@speedY else @speedY
      
    if deltaX != 0
      @vx = if deltaX > 0 then -@speedX else @speedX
      
    
    
      
    
  draw: ->
    @world.ctx.fillStyle = @colour
    @world.ctx.beginPath()
    @world.ctx.moveTo @rX + (@world.tileWidth / 2), @rY
    @world.ctx.lineTo @rX + @world.tileWidth, @rY + (@world.tileHeight / 2)
    @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
    @world.ctx.lineTo @rX, @rY + (@world.tileHeight / 2)
    @world.ctx.closePath()
    @world.ctx.fill()
    
    if @world.debug
      @world.ctx.strokeStyle = 'black'
      @world.ctx.strokeRect @rX, @rY, @w, @h
  
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Entity Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class Entity extends Sprite
  speed:0
  vx: 0
  vy:0
  collides: true
  

  constructor: (@world, x, y, @w, @h, image, @speed = 0) ->
    super()
    @frame = 0
    @w *= @world.scale
    @h *= @world.scale
    @flip = false
    @speedX *= @world.scale
    @speedY *= @world.scale
    @defaultX = x
    @defaultY = y
    @x = x
    @y = y
    @path = false
 
    @zIndex = @world.tileHeight - 0.1
    # super  @world, image
  
  update: (modifier) =>
  
    @z = @rY + @zIndex
  
    @vx = 0 unless @nextX != @x
    @vy = 0 unless @nextY != @y
    
    
    
    if @vx == 0 and @vy == 0
      if @path and @path[2] and @world.background.mapTiles[@path[2][1]][@path[2][0]].walkable
        @path.shift()
        @walkPath @path
      else
        @path = []
        myTile = @getTile()
        @myTile =@world.background.mapTiles[myTile.y][myTile.x] 
        
    setVx = @vx
    setVy = @vy
        
    if @onPlatform 
      if @onPlatform.inMotion
        @x = @onPlatform.x
        @y = @onPlatform.y
        this.vx = 0
        this.vy = 0
           
    @x += @vx
    @y += @vy
    
      
    @rX = @x - @world.scrollX
    @rY = @y - @world.scrollY
    
    
    if @world.collisionIndex[this.name]
      collidesWith = @world.collisionIndex[this.name]
      if collidesWith.name == 'platform'
        @onPlatform = collidesWith
      else
        @onPlatform = false
    else
      @onPlatform = false
      
        
  animate: (frame, animation) ->
    frameIn = frame in animation
    frameIndex = animation.indexOf frame
    if frameIn
      @frame = frame 
    else
      @frame = animation[0]
      
  draw: ->  
    if @image.ready
      sx = ( @w * @frame ) 
      sy = 0
      @world.ctx.drawImage( @image.image, sx, sy, @w, @h, @rX - (@w - @world.tileWidth), @rY - (@h - @world.tileHeight), @w * @world.scale, @h*@world.scale )
      
      
  
  kill: (modifier) =>
    that = this
    @world.sprites[t..t] = [] if ( t = @world.sprites.indexOf(that))
    

  reset: ->
    @nextStep=[]
    @vx = 0
    @vy = 0
    @path = [[],[]] 
    @x = @defaultX
    @y = @defaultY
    
      
  twoDToIso: (ex, wy, w, h)->
    tileX = Math.floor ( (@rX + @world.scrollX)  / @world.tileWidth ) + ( (@rY + @world.scrollY)  / @world.tileHeight)  
    tileY = Math.floor ( (@rY + @world.scrollY) / @world.tileHeight ) - ( (@rX + @world.scrollX) / @world.tileWidth) 
    {x: tileX, y:tileY}
    
  
  getTile:(x = @rX, y=@rY) =>
    if @world.iso
      matrix = @twoDToIso x, y, @world.tileWidth, @world.tileHeight 
    else
      px = Math.floor @rX / @world.tileWidth
      py = Math.floor @rY / @world.tileHeight 
      matrix = {x: Math.floor(@x / @world.tileWidth), y: Math.floor (@y / @world.tileHeight)}
    matrix
    
  walkPath: (path) ->
    @path = path
    if @path[1]
      @nextStep = @path[1] 
      @nextX = @world.background.mapTiles[@nextStep[1]][@nextStep[0]].x
      @nextY = @world.background.mapTiles[@nextStep[1]][@nextStep[0]].y
      
      deltaX = @nextX - @x
      deltaY = @nextY - @y
      
      #clear path as you go
      @world.background.mapTiles[@path[0][1]][@path[0][0]].clearFlags 'path'
      
      if deltaX != 0
        if deltaX > 0
          #move right
          @vx = @speedX
        if deltaX < 0
          #move left
          @vx = -@speedX
       
      if deltaY != 0
        if deltaY > 0
          #move down
          @vy = @speedY
        if deltaY < 0
          #move up
          @vy = -@speedY
      
    else
      false


###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Player Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###

class Player extends Entity
  name: 'Player'
  
  
  constructor: ->
    super()
    @speedX = 3
    @speedY = 3
    if @world.iso
      @speedX *= 2
    @entType = 'player'
    @animations = {}
    @animations.standing = [0]
    @animations.walkDownLeft = [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6]
    @animations.walkDownRight = [7,7,7,8,8,8,9,9,9,10,10,10,11,11,11]
  
  update:(modifier) ->
    if @vx < 0 and @vy > 0
      @animate(@frame + 1, @animations.walkDownLeft)
      
    if @vx > 0 and @vy > 0
      @animate(@frame + 1, @animations.walkDownRight)
    
    if @vx is 0 and @vy is 0
      @animate( 0, @animations.standing)
     
          
    super()
    
  draw: ->
    super() 
    if @world.debug
      @world.ctx.strokeStyle = 'black'
      @world.ctx.strokeRect @rX , @rY , @w, @h
    
  setActive: ->
    @world.player = this
    @world.quickScroll = true
    
class DrawnPlayer extends Player
  constructor: ->
    super()
    @colourTop = '#c4ffeb'
    @colourRight = '#9be1c9'
    @colourLeft = '#80b9a6'
    
  draw: =>  
     that = this
     @world.ctx.fillStyle = @colourLeft
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX, @rY + @world.tileHeight / 2
     @world.ctx.lineTo @rX, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
     @world.ctx.closePath()
     @world.ctx.fill()
     
     
     @world.ctx.fillStyle = @colourRight
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX + @w, @rY + @world.tileHeight / 2
     @world.ctx.lineTo @rX + @w, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
     @world.ctx.closePath()
     @world.ctx.fill()
     
     @world.ctx.fillStyle = @colourTop
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX + @w, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY
     @world.ctx.closePath()
     @world.ctx.fill()
     
     if @world.player == that
       @world.ctx.strokeStyle = 'yellow'
       @world.ctx.beginPath()
       @world.ctx.moveTo @rX, @rY + (@h / 2)
       @world.ctx.lineTo @rX + (@w / 2), @rY + @h
       @world.ctx.lineTo @rX + @w, @rY + (@h / 2)
       @world.lineWidth = 2
       @world.ctx.stroke()
     
     if @world.debug
        @strokeStyle = 'black'
        @world.ctx.strokeRect(@rX, @rY, @w, @h)
        @strokeStyle = 'blue'
        @world.ctx.strokeRect @rX, @rY, 4, 4
     
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Control Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###  
class Control extends Sprite
   
   collides: true
   switchedOn: true
   
   frame: 0
   
   constructor: (world, @x, @y, @w, @h, image, @linkedTo, @name = 'control') ->
     super world, image
     @world.controls.push this
     if @world.debug then console.log 'created a control linked to ' + @linkedTo.name
     
   update: (modifier) =>
     that = this
     if @world.collisionIndex[@name]
       for control in @world.controls
         if control != that
           if control.linkedTo == @linkedTo
             control.switchedOn = false if control.switchedOn
      
       @switchedOn = true
       
       collides = @world.collisionIndex[@name]
       if !@linkedTo.active
         @linkedTo.active = true
         @linkedTo.startMoving()
     else
       if @switchedOn
         @switchedOn = false
         @linkedTo.active = false
         
     @frame = if @switchedOn then 1 else 0
         
     super modifier
     
   draw: ->
     if !@image
       @world.ctx.strokeStyle = 'blue'
       @world.ctx.strokeRect @rX, @rY, @w, @h / 2
       
     else
       @rY = @rY - (5 * @world.scale)
       super()
   
     
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The Item Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###  
class Item extends Sprite

  collides:true
  
  constructor: (world, @x, @y, @w, @h, image, @name='item')->
    super world, image
    
  update: (modifier) =>
     that = this
     if @world.collisionIndex[@name]
       collides = @world.collisionIndex[@name]
       if collides.entType == 'player'
         @world.inventory.push this
         @kill()
         
     super()
       
  draw: ->
    if !@image
      @world.ctx.beginPath()
      @world.ctx.arc(@rX + (@w / 2), @rY, @w / 2, 0, 2 * Math.PI, false)
      @world.ctx.fillStyle = 'rgb(234,204,112)'
      @world.ctx.fill()
    else
      super()
      
  
  kill: (modifier) =>
    that = this
    @world.sprites[t..t] = [] if ( t = @world.sprites.indexOf(that))
    
  
  
  
###
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
~The NPC Class
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~
###
class NPC extends Entity
  
  name: 'Smith'
    
    
  constructor: ->
    super()
    @speedX = 1.5
    @speedY = 1.5
    @entType = 'npc'
    if @world.iso
      @speedX *= 2
        
  update: (modifier) ->
    super modifier
    if @loopPath and @path.length < 3
      @clearPath()
      @setPath @initialPath, true

  setPath: (path, @loopPath = false) ->
     @initialPath = []
     for item in path
       @initialPath.push item
     @path = path
     
  clearPath: ->
     @path = []
 
class DrawnNPC extends NPC
  constructor: ->
    super()
    @colourTop = '#dbdbdb'
    @colourRight = '#bdbdbd'
    @colourLeft = '#aeaeae'
    
    
  draw: ->  
  
     @world.ctx.fillStyle = @colourLeft
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX, @rY + @world.tileHeight / 2
     @world.ctx.lineTo @rX, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
     @world.ctx.closePath()
     @world.ctx.fill()
     
     
     @world.ctx.fillStyle = @colourRight
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX + @w, @rY + @world.tileHeight / 2
     @world.ctx.lineTo @rX + @w, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight
     @world.ctx.closePath()
     @world.ctx.fill()
     
     @world.ctx.fillStyle = @colourTop
     @world.ctx.beginPath()
     @world.ctx.moveTo @rX + @w, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight)
     @world.ctx.lineTo @rX, @rY - @world.tileHeight / 2
     @world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY
     @world.ctx.closePath()
     @world.ctx.fill()
     
     if @world.debug
      @strokeStyle = 'black'
      @world.ctx.strokeRect(@rX, @rY, @w, @h)
      @strokeStyle = 'blue'
      @world.ctx.strokeRect @rX, @rY, 4, 4
     
        


###
START THE GAME!
###

  
map = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1], 
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1], 
    [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1], 
    [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1], 
    [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1], 
    [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1], 
    [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1], 
    [1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1], 
    [1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1], 
    [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  ]


window.onload = ->

  game = new Game 'game', 30, scale:.5
  game.iso = true
  game.run()
  game.world.createWorld map
  game.world.scrollX = -250
  #game.world.debug = true
  
  ###
  bind mousey
  ###
  
  $('canvas').on('click', ()->
    game.inputHandler.clicked = true  
  )
	
  pX = game.world.background.mapTiles[2][17].x
  pY = game.world.background.mapTiles[2][17].y
  player = new DrawnPlayer game.world,pX, pY, 60, 30, 'images/eric.png', 10
  
  p2X = game.world.background.mapTiles[1][17].x
  p2Y = game.world.background.mapTiles[1][17].y
  player2 = new DrawnPlayer game.world,p2X, p2Y, 60, 30, 'images/eric.png', 10
  
  player.name = 'Ebrewe'
  player2.name = 'client'
  
  player2.colourTop = '#a4efeb'
  player2.colourRight = '#8bd1c9'
  player2.colourLeft = '#70a9a6'
  
  
  npcX = game.world.background.mapTiles[9][5].x
  npcY = game.world.background.mapTiles[9][5].y
  #Badguy
  badRobot = new DrawnNPC game.world, npcX, npcY, 60, 60
  npcPath = [
    [5,9],[5,10],[5,11],[5,12],
    [11,12],
    [11,5],
    [5,5],
    [5,9]
  ]
  badRobot.setPath npcPath, yes
  
  
  pfX = game.world.background.mapTiles[9][18].x
  pfY = game.world.background.mapTiles[9][18].y
  
  pfX2 = game.world.background.mapTiles[7][16].x
  pfY2 = game.world.background.mapTiles[7][16].y
  
  platform = new Platform game.world, pfX, pfY, game.world.tileWidth, game.world.tileHeight, true, [pfX, pfY], [pfX2, pfY2], [18, 9], [16, 7]
    

  prX = game.world.background.mapTiles[11][4].x
  prY = game.world.background.mapTiles[11][4].y
  
  prX2 = game.world.background.mapTiles[11][3].x
  prY2 = game.world.background.mapTiles[11][3].y
  
  platform2 = new Platform game.world, prX, prY, game.world.tileWidth, game.world.tileHeight, true, [prX, prY], [prX2, prY2], [4, 11], [3, 11]
 
  cX = game.world.background.mapTiles[1][13].x
  cY = game.world.background.mapTiles[1][13].y
  control = new Control game.world, cX, cY, 60, 35, 'http://games.ericbrewer.ca/cdn/images/buttonTileIso.png', platform
  
  c2X = game.world.background.mapTiles[11][16].x
  c2Y = game.world.background.mapTiles[11][16].y
  control2 = new Control game.world, c2X, c2Y, 60, 35, 'http://games.ericbrewer.ca/cdn/images/buttonTileIso.png', platform
  
  c3X = game.world.background.mapTiles[3][4].x
  c3Y = game.world.background.mapTiles[3][4].y
  control3 = new Control game.world, c3X, c3Y, 60, 35, 'http://games.ericbrewer.ca/cdn/images/buttonTileIso.png', platform2
  
  control.name = 'elControl'
  control2.name = 'elTwoControl'
  control3.name ='platformControl'
  
  iX = game.world.background.mapTiles[11][1].x
  iY = game.world.background.mapTiles[11][1].y
  goal = new Item game.world, iX, iY, 30, 30, false, 'goal'
  
  player.setActive()
  
  ###
  bind players
  ###
  $('.buttons').on('click', '.player', (e)->
      bId = $(this).attr('id')
      e = e ? e : window.event
      e.preventDefault()
      e.stopPropagation()
      
      $('.active').removeClass('active')
      $(this).addClass('active')
      
      
      switch bId
        when 'player1' then player.setActive()
        when 'player2' then player2.setActive()
        else player.setActive()
    )
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. https://ebrewe-games.s3.amazonaws.com/pathfinding/pathfinding.min.js