   [ null,null,null,null, null,null,null,null, null,null,null,null, null,null,null,null ]
   [ null,null,null,null, null,null,null,null, null,null,null,null, null,null,null,null ]
 ]
+
+tileSearchVertical = (grid, x, topY, bottomY) ->
+  hits = []
+  c = Math.floor(x/16)
+  for r in [Math.floor(topY/16)..Math.floor(bottomY/16)]
+    row = grid[r]
+    if row?
+      hit = grid[r][c]
+      if hit?
+        hits.push [r,c,hit]
+    # else
+    #   console.log "vsearch NO row? #{r}",grid
+  hits
+
+tileSearchHorizontal = (grid, y, leftX, rightX) ->
+  hits = []
+  r = Math.floor(y/16)
+  row = grid[r]
+  if row?
+    for c in [Math.floor(leftX/16)..Math.floor(rightX/16)]
+      hit = grid[r][c]
+      if hit?
+        # hits.push hit
+        hits.push [r,c,hit]
+  hits

    @handleAdminControls()

    p1in = @p1Controller.update()
    console.log p1in if p1in
    @input.controllers.player1 = p1in
    # @input.controllers.player2 = @p2Controller.update()


        when 'fall'
          velocity.y = 0


      # TODO: Gravity system?
      # TODO: always apply? or just when airborn?
      # velocity.y += 100/1000 * dt
      # if samus.action != 'run' and samus.action != 'stand'
      max = 200/1000
      velocity.y += max/10
      velocity.y = max if velocity.y > max
        # console.log "v #{velocity.x} #{velocity.y}"
      samus.action = null
    

tileWidth = 16
samusWidth = 12
halfSamusWidth = samusWidth/2
samusHeight = 32

Systems.register 'velocity_position', class GestureAction
  run: (estore,dt,input) ->
    for velocity in estore.getComponentsOfType('velocity')
      if position = estore.getComponent(velocity.eid, 'position')
        # Current pos and velocity:
        velX = velocity.x
        velY = velocity.y

        # Proposed movement:
        dx = velX * dt
        dy = velY * dt

        # Proposed resulting position:
        newX = position.x + dx
        newY = position.y + dy

        # Samus box:
        left = position.x - halfSamusWidth
        right = left + samusWidth
        bottom = position.y
        top = bottom - samusHeight

        newLeft = newX - samusWidth/2
        newRight = left + samusWidth
        newBottom = newY
        newTop = bottom - samusHeight

        # Collisions:
        leftHits = tileSearchVertical(roomData, newLeft, top+1,bottom-1)
        rightHits = tileSearchVertical(roomData, newRight, top+1,bottom-1)
        topHits = tileSearchHorizontal(roomData, newTop, left+1,right-1)
        bottomHits = tileSearchHorizontal(roomData, newBottom, left+1,right-1)


        if leftHits.length > 0
          newX = (Math.floor(newLeft/tileWidth) + 1) * tileWidth + halfSamusWidth
          velX = 0 if velX < 0

        if rightHits.length > 0
          newX = Math.floor(newRight/tileWidth) * tileWidth - halfSamusWidth
          velX = 0 if velX > 0

        if bottomHits.length > 0
          newY = Math.floor(newBottom/tileWidth) * tileWidth
          velY = 0 if velY > 0

        if topHits.length > 0
          newY = (Math.floor(newBottom/tileWidth) + 1) * tileWidth
          velY = 0 if velY < 0


        # Floor safety check:
        screenBottom = 240
        if newY > screenBottom
          newY = screenBottom
          velY = 0

        velocity.x = velX
        velocity.y = velY

        position.x = newX
        position.y = newY
