shawn42/gamebox

View on GitHub
lib/gamebox/behaviors/collidable/polygon_collidable.rb

Summary

Maintainability
A
40 mins
Test Coverage


class PolygonCollidable < CollidableShape
  attr_accessor :cw_local_points

  def setup
    @shape_type = opts[:shape]

    @cw_local_points = opts[:cw_local_points]
    @cw_local_points ||= opts[:points]

    @radius = opts[:radius]
    @radius ||= calculate_radius

    @old_x = actor_x
    @old_y = actor_y
  end

  def calculate_radius
    local_avg = cw_local_points.inject([0,0]) {|s, (x,y)| s[0] += x; s[1]+=y; s}.map {|x| x / cw_local_points.size}
    max_dist = 0
    cw_local_points.each do |lp|
      x_dist = local_avg[0]-lp[0]
      y_dist = local_avg[1]-lp[1]
      dist = Math.sqrt(x_dist*x_dist + y_dist*y_dist)
      max_dist = dist if dist > max_dist
    end 
    max_dist
  end

  def center_x
    poly_center[0]
  end

  def center_y
    poly_center[1]
  end

  def poly_center
    @cached_poly_center ||= cw_world_points.inject([0,0]) {|s, (x,y)| s[0] += x; s[1]+=y; s}.map {|x| x / cw_world_points.size}
  end

  def cw_world_points
    @cached_points ||= @cw_local_points.map{|lp| [lp[0]+actor_x,lp[1]+actor_y]}
  end

  def cw_world_lines
    return @cached_lines if @cached_lines
    lines = [] 

    cw_world_points.each_cons(2) do |a,b|
      lines << [a,b]
    end
    lines << [cw_world_points[-1],cw_world_points[0]]

    @cached_lines = lines
  end

  def cw_world_edge_normals
    return @cached_normals if @cached_normals

    @cached_normals = cw_world_lines.map do |edge|
      # vector subtraction
      v = edge[1][0]-edge[0][0], edge[1][1]-edge[0][1]
      [-v[1],v[0]]
    end

    @cached_normals
  end

  def recalculate_collidable_cache
    unless @old_x == actor_x && @old_y == actor_y
      clear_collidable_cache
      @old_x = actor_x
      @old_y = actor_y
    end
  end

  def clear_collidable_cache
    @cached_points = nil
    @cached_lines = nil
    @cached_poly_center = nil
  end

end