class Core::Game::Map

Attributes

layers[R]
module[R]
objects[RW]
properties[R]
xoff[RW]
yoff[RW]

Public Class Methods

new(props, layers, objects, mod) click to toggle source
# File lib/game/map/map.rb, line 10
def initialize(props, layers, objects, mod)
  @properties = props
  @layers = layers
  @objects = objects
  @xoff = @yoff = 0
  @module = mod
  create_static_collision
end

Public Instance Methods

astar(node_start, node_goal) click to toggle source
# File lib/game/map/map.rb, line 171
def astar(node_start, node_goal)
  iterations = 0
  open = AStar::PriorityQueue.new()
  closed = AStar::PriorityQueue.new()
  node_start.calc_h(node_goal)
  open.push(node_start)
  costmap = generate_costmap
  while !open.empty? do
    iterations += 1 #keep track of how many times this itersates
    node_current = open.find_best
    if node_current == node_goal
      #puts("Iterations: #{iterations}")
      #show_path(node_current)
      return node_current 
    end       
    generate_successor_nodes(node_current, costmap) { |node_successor|
      #now doing for each successor node of node_current
      node_successor.calc_g(node_current)
      #skip to next node_successor if better one already on open or closed list
      if open_successor=open.find(node_successor) then 
        if open_successor<=node_successor then next end  #need to account for nil result
      end
      if closed_successor=closed.find(node_successor) then
        if closed_successor<=node_successor then next end 
      end
      #still here, then there's no better node yet, so remove any copies of this node on open/closed lists
      open.remove(node_successor)
      closed.remove(node_successor)
      # set the parent node of node_successor to node_current
      node_successor.parent=node_current
      # set h to be the estimated distance to node_goal using the heuristic
      node_successor.calc_h(node_goal)
      # so now we know this is the best copy of the node so far, so put it onto the open list
      open.push(node_successor)
    }
    #now we've gone through all the successors, so the current node can be closed
    closed.push(node_current)
  end
end
create_static_collision() click to toggle source
# File lib/game/map/map.rb, line 27
def create_static_collision
  return if @layers.empty?
  tiles = []
  @layers.each { |l|
    i = 0
    l.filled.each { |row|
      row.each { |tile|
        if !tile
          if tiles[i] == false
            i += 1
            next
          else
            tiles[i] = true
            i += 1
            next
          end
        end
        tiles[i] = tile.passable?
        i += 1
      }
    }
  }
  @collision = Core::CollisionLayer.new(@layers.first.filled.first.size, @layers.first.filled.size, tiles)
end
draw(xoff, yoff) click to toggle source

parameters are scrolling, instance variables are world positions

# File lib/game/map/map.rb, line 53
def draw(xoff, yoff)
  @layers.each { |l|
    l.filled.each { |ary|
      ary.each { |tile|
        tile.draw(xoff+@xoff, yoff+@yoff) if tile
      }
    }
  }
end
generate_costmap() click to toggle source
# File lib/game/map/map.rb, line 116
def generate_costmap
  map = []
  x = 0
  @collision.tiles.each { |ary|
    cary = []
    y = 0
    ary.each { |tile|
      if tile
        obj = Core.window.state.find_object(y*32, x*32)
        if obj and !obj.through
          cary.push(0)
          y += 1
          next
        end
        cary.push(1)
      else
        cary.push(0)
      end
      y += 1
    }
    map.push(cary)
    x += 1
  }
  return map
end
generate_successor_nodes(anode, costmap) { |newnode| ... } click to toggle source
# File lib/game/map/map.rb, line 142
def generate_successor_nodes(anode, costmap)
  height = costmap.size
  width = costmap.first.size
  # determine nodes bordering this one - only N,S,E,W for now
  # no boundary condition check, eg if anode.x==-4
  # considers a wall to be a 0 so therefore not allow that to be a neighbour
  north = costmap[anode.y-1][anode.x] unless (anode.y-1) < 0 #boundary check for -1
  south = costmap[anode.y+1][anode.x] unless (anode.y+1) > (height - 1)
  east  = costmap[anode.y][anode.x+1] unless (anode.x+1) > (width - 1)
  west  = costmap[anode.y][anode.x-1] unless (anode.x-1) < 0 #boundary check for -1
  
  if (west && west > 0) # not on left edge, so provide a left-bordering node
    newnode = AStar::Node.new((anode.x-1),anode.y,costmap[anode.y][(anode.x-1)])
    yield newnode
  end
  if (east && east > 0) # not on right edge, so provide a right-bordering node
    newnode = AStar::Node.new((anode.x+1),anode.y,costmap[anode.y][(anode.x+1)])
    yield newnode
  end
  if (north && north > 0) # not on left edge, so provide a left-bordering node
    newnode = AStar::Node.new(anode.x,(anode.y-1),costmap[(anode.y-1)][anode.x])
    yield newnode
  end
  if (south && south > 0) # not on right edge, so provide a right-bordering node
    newnode = AStar::Node.new(anode.x,(anode.y+1),costmap[(anode.y+1)][anode.x])
    yield newnode
  end    
end
height() click to toggle source
# File lib/game/map/map.rb, line 23
def height
  return @properties[:height]
end
left() click to toggle source
# File lib/game/map/map.rb, line 238
def left
  return @properties[:left]
end
lower() click to toggle source
# File lib/game/map/map.rb, line 234
def lower
  return @properties[:lower]
end
passable?(x, y, player=false) click to toggle source
# File lib/game/map/map.rb, line 63
def passable?(x, y, player=false)
  if !player && ((x/32) < 0 or (x/32) >= width or (y/32) < 0 or (y/32) >= height)
    return false
  elsif player
    if (x/32).to_i >= width
      if Core.window.state.map.right.passable?(0, y, true)
        Core.window.state.map.load(Core.window.state.map.right.properties[:file])
        Core.window.state.map.player.teleport(0, y / 32)
        return true
      else
        return false
      end
    elsif (x/32).to_i < 0
      if Core.window.state.map.left.passable?((Core.window.state.map.left.width - 1) * 32, y, true)
        Core.window.state.map.load(Core.window.state.map.left.properties[:file])
        Core.window.state.map.player.teleport(Core.window.state.map.current.width, y / 32)
        return true
      else
        return false
      end
    elsif (y/32).to_i >= height
      if Core.window.state.map.left.passable?(x, 0, true)
        Core.window.state.map.load(Core.window.state.map.lower.properties[:file])
        Core.window.state.map.player.teleport(x / 32, 0)
        return true
      else
        return false
      end
    elsif (y/32).to_i < 0
      if Core.window.state.map.left.passable?(x, (Core.window.state.map.upper.height - 1) * 32, true)
        Core.window.state.map.load(Core.window.state.map.upper.properties[:file])
        Core.window.state.map.player.teleport(x / 32, Core.window.state.map.current.height)
        return true
      else
        return false
      end
    end
  end
  begin
    p = @collision.tiles[y/32][x/32]
  rescue
    puts("Collision out of bounds: #{x/32}|#{y/32}")
  end
  if p
    obj = Core.window.state.find_object(x, y)
    if !obj
      return true
    end
    p = obj.through
  end
  return p
end
right() click to toggle source
# File lib/game/map/map.rb, line 242
def right
  return @properties[:right]
end
show_path(anode) click to toggle source
# File lib/game/map/map.rb, line 211
def show_path(anode)
  #shows the path back from node 'anode' by following the parent pointer
  curr = anode
  pathmap = generate_costmap
  while curr.parent do
    pathmap[curr.y][curr.x] = '*'
    curr = curr.parent
  end
  pathmap[curr.y][curr.x] = '*'
  pathstr=""
  pathmap.each_index do |row|
    pathmap[row].each_index do |col|
      pathstr<<"|#{pathmap[row][col]}"
    end
    pathstr<<"|\n"
  end
  puts(pathstr)
end
upper() click to toggle source
# File lib/game/map/map.rb, line 230
def upper
  return @properties[:upper]
end
width() click to toggle source
# File lib/game/map/map.rb, line 19
def width
  return @properties[:width]
end