Commits

benbeltran committed acf2d92

Add collision resolution + growing shadow

  • Participants
  • Parent commits 7afdddc

Comments (0)

Files changed (5)

File actors/actor.lua

   self.box.left = math.floor(box_width/2)
   self.box.right = math.floor(box_width/2)
 
+  -- colliders
+  self.collider = {
+    top = false,
+    bottom = false,
+    left = false,
+    right = false
+  }
+
   --horizontal physics variables
   self.max_x_vel = 2.5      -- Maximum Velocity
   self.x_acc = 3.0          -- Acceleration
 function Actor:bind_events()
   self:bind("collision", function(self, ev)
     if not ev.other.passable and not self.immutable then
-      if ev.other.immutable then
+      if ev.dx ~= 0 then
+        if (ev.dx > 0 and self:can_pass("right")) or (ev.dx < 0 and self:can_pass("left")) then
+          self.x = self.x + ev.dx - sign(ev.dx)
+        end
         self.x_vel = 0
+
+        if ev.dx > 0 then
+          self.collider.left = true
+          self.collider.right = false
+        else
+          self.collider.left = false
+          self.collider.right = true
+        end
       else
+        self.collider.left = false
+        self.collider.right = false
+      end
 
+      if ev.dy ~= 0 then
+        if (ev.dy > 0 and self:can_pass("down", self.x, self.y)) or (ev.dy < 0 and self:can_pass("up", self.x, self.y)) then
+          self.y = self.y + ev.dy - sign(ev.dy)
+        end
+        self.y_vel = sign(ev.dy)
+
+        if ev.dx > 0 then
+          self.collider.bottom = false
+          self.collider.top = true
+        else
+          self.collider.bottom = true
+          self.collider.top = false
+        end
+      else
+        self.collider.bottom = false
+        self.collider.top = false
       end
-      print(self.x, self.y, ev.other.x, ev.other.y, ev.dx, ev.dy)
     end
   end)
+
+  self:bind("endCollision", function(self, ev)
+    self.collider.bottom = false
+    self.collider.top = false
+    self.collider.left = false
+    self.collider.right = false
+  end)
 end
 
 function Actor:destroy()
 
 function Actor:draw()
   love.graphics.draw(self.image, self.x - self.image:getWidth() / 2, self.y - self.image:getHeight() / 2)
-  if game.show_hitbox then
-    self:draw_bounding_box()
-  end
+  self:draw_bounding_box()
   self:draw_shadow()
 end
 
 function Actor:draw_bounding_box()
-  love.graphics.setColor(255, 0, 0, 128)
-  love.graphics.rectangle("line", self.x-self:box_side("left"), self.y-self:box_side("top"), self:box_width(), self:box_height())
-  love.graphics.setColor(255,255,255,255)
+  if game.show_hitbox then
+    love.graphics.setColor(255, 0, 0, 128)
+    love.graphics.rectangle("line", self.x-self:box_side("left"), self.y-self:box_side("top"), self:box_width(), self:box_height())
+    love.graphics.setColor(255,255,255,255)
+  end
 end
 
 function Actor:draw_shadow()
   local r,g,b,a = love.graphics.getColor()
   local ps = love.graphics.getPointSize()
+  local counter = 0
 
   love.graphics.setColor(0,0,0,64)
   love.graphics.setPointSize(ps+4)
   love.graphics.setPointStyle("smooth")
 
   -- For every part of the box, let's look down to see where it lands
-  for i = self.x-self:box_side("left"), self.x+self:box_side("right") do
+  local left = self.x - self:box_side("left")
+  local right = self.x + self:box_side("right")
+  for i = left, right do
     local x = self:get_tile("x", i)
     local j = self.y+self:box_side("bottom")
     local y = self:get_tile("y", j)
     while self:check_point(x,y) do
       y = y+1
     end
-    love.graphics.point(i,y*16+1)
+    if self:should_draw_shadow(left, right, i, math.abs(self.y-y*16+1)) then
+      love.graphics.point(i,y*16+1)
+    end
   end
 
   love.graphics.setPointStyle("rough")
   love.graphics.setColor(r,g,b,a)
 end
 
+function Actor:should_draw_shadow(left_edge, right_edge, test_point, distance)
+  local lower_limit = 3
+  local ratio = 15
+  local center = round(left_edge + (right_edge - left_edge) / 2)
+
+  if test_point <= center + lower_limit and test_point >= center - lower_limit then
+    return true
+  end
+
+  local cutoff = 8 - math.floor ( distance / ratio )
+  local new_left_edge = left_edge + cutoff
+  local new_right_edge = right_edge - cutoff
+
+  if test_point > new_left_edge and test_point < new_right_edge then
+    return true
+  end
+
+  return false
+end
+
 function Actor:check_point(x, y)
   local tiles = game.map_manager.map("Collision")
   local tile = tiles:get(x,y)
 function Actor:unstick(context)
   if context == "y" then
     -- Half speed on bump
-    if not self:can_pass("up", self.x, self.y-1) then
+    if not self:can_pass("up", self.x, self.y-1, true) then
       self.y_vel = self.y_vel/2
     end
 
-    while not self:can_pass("down", self.x, self.y-1) do
+    while not self:can_pass("down", self.x, self.y-1, true) do
       self.y = self.y-1
     end
-    while not self:can_pass("up", self.x, self.y+1) do
+    while not self:can_pass("up", self.x, self.y+1, true) do
       self.y = self.y+1
     end
   end
 
   if context == "x" then
-    while not self:can_pass("right") do
+    while not self:can_pass("right", self.x, self.y, true) do
       if self.x_vel > 0 then
         self.x_vel = 0
       end
       self.x = self.x-1
     end
 
-    while not self:can_pass("left") do
+    while not self:can_pass("left", self.x, self.y, true) do
       if self.x_vel < 0 then
         self.x_vel = 0
       end
   end
 end
 
-function Actor:can_pass(direction, x, y)
+function Actor:can_pass(direction, x, y, skip_objects)
 
   local mapsys = game.map_manager
 
 
   if direction == "up" then
 
+    if self.collider.top and not skip_objects then
+      return false
+    end
+
     --get the tiles for this direction
     local tile_x1 = self:get_tile("x1", x+padding)
     local tile_x2 = self:get_tile("x2", x-padding)
 
   if direction == "down" then
 
+    if self.collider.bottom and not skip_objects then
+      return false
+    end
+
     --get the tiles for this direction
     local tile_x1 = self:get_tile("x1", x+padding)
     local tile_x2 = self:get_tile("x2", x-padding)
 
   if direction == "left" then
 
+    if self.collider.left and not skip_objects then
+      return false
+    end
+
     --get the tiles for this direction
     local tile_x1 = self:get_tile("x1", x)
     local tile_y1 = self:get_tile("y1", y+padding)
 
   if direction == "right" then
 
+    if self.collider.right and not skip_objects then
+      return false
+    end
+
     --get the tiles for this direction
     local tile_x2 = self:get_tile("x2", x)
     local tile_y1 = self:get_tile("y1", y+padding)

File actors/grass.lua

   self.name = "Grass"
   self.skip_same_collision = true
   self.immutable = true
-  -- self.passable = true
+  self.passable = true
 end
 
 return GrassActor
 
   function self.collider.collision(actor1, actor2, dx, dy)
     actor1:dispatch('collision', { other = actor2, dx = dx, dy = dy })
-    actor2:dispatch('collision', { other = actor1, dx = dx, dy = dy })
+    actor2:dispatch('collision', { other = actor1, dx = -dx, dy = -dy })
   end
 
   function self.collider.endCollision(actor1, actor2)

File lib/extra_math.lua

   end  -- if positive
 
   return math.ceil (x - 0.5)
-end
+end
+
+function sign (x)
+  if x >= 0 then
+    return 1
+  else
+    return -1
+  end
+end

File screens/game.lua

 function GameScreen:update(dt)
   beetle.update("Actors", table.getn(self.actor_manager.actors))
   self.map_manager:update(dt)
-  self.actor_manager:update(dt)
   self.collider.collide()
+  self.actor_manager:update(dt)
 end
 
 function GameScreen:exitedState()