Commits

benbeltran committed aecbaeb

Preliminary parallax bg support

  • Participants
  • Parent commits 1cc50ed

Comments (0)

Files changed (16)

File actor_manager.lua

 end
 
 function ActorManager:update(dt)
-  for pos, actor in pairs(self.actors) do
+  for pos, actor in ipairs(self.actors) do
     actor:update(dt)
   end
 end
 
 function ActorManager:draw(dt)
-  for pos, actor in pairs(self.actors) do
-    actor:draw(dt)
+  for pos, actor in ipairs(self.actors) do
+    if not actor.dying then
+      actor:draw(dt)
+    end
   end
 end
 
 end
 
 function ActorManager:move_out(actor)
-  for pos, current_actor in pairs(self.actors) do
+  for pos, current_actor in ipairs(self.actors) do
     if current_actor == actor then
-      print("Removing actor: "..actor.name.." from "..pos)
-      print(table.inspect(self.actors))
+      game.collider.remove(actor)
       table.remove(self.actors, pos)
     end
   end
 end
 
 function ActorManager:unload()
-  for pos, actor in pairs(self.actors) do
-    if actor.name ~= "Player" then
-      actor:destroy()
+  for pos, actor in ripairs(self.actors) do
+    if not actor.survives_map then
+      actor:die()
+    else
+      actor:reset()
     end
   end
 end

File actors/actor.lua

 end
 
 function Actor:bind_events()
-  self:bind("collision", function(self, ev)
+end
+
+function Actor:do_collide(ev)
     if not ev.other.passable and not self.immutable and ev.other.is_actor 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.platform = nil
       end
     end
-  end)
+end
 
-  self:bind("endCollision", function(self, ev)
+function Actor:end_collide(ev)
     self.collider.bottom = false
     self.collider.top = false
     self.collider.left = false
     self.collider.right = false
     self.platform = nil
-  end)
 end
 
 function Actor:destroy()
 
 function Actor:draw_bounding_box()
   if game.show_hitbox then
+    local r,g,b,a = love.graphics.getColor()
     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)
+    love.graphics.setColor(r, g, b, a)
   end
 end
 
   return self.box.top+self.box.bottom
 end
 
+function Actor:reset()
+  self.platform = nil
+  self.collider = {
+    top = false,
+    right = false,
+    bottom = false,
+    left = false
+  }
+end
+
 function Actor:die()
   self.dying = true
 end

File actors/bovine_head.lua

   self.box.bottom = 16
   self.box.left = 4
   self.box.right = 4
+
+  self.survives_map = true
 end
 
 function BovineHeadActor:draw()
   self:draw_bounding_box()
 end
 
-function BovineHeadActor:bind_events()
-  Actor.bind_events(self)
-
-  self:bind('collision', function(self, ev)
-    if ev.other.name == "Grass" then
-      if love.keyboard.isDown("down") and not self.eat_lock then
-        self.eat_lock = true
-        self:dispatch('ate_grass', {grass = ev.other})
-        ev.other:dispatch('eaten')
-      end
+function BovineHeadActor:do_collide(ev)
+  if ev.other.name == "Grass" then
+    if love.keyboard.isDown("down") and not self.eat_lock then
+      self.eat_lock = true
+      self:dispatch('ate_grass', {grass = ev.other})
+      ev.other:dispatch('eaten')
     end
-  end)
+  end
 end
 
 function BovineHeadActor:update()

File actors/player.lua

     z = 0
   }
 
+  self.survives_map = true
+
   -- stomach
   self.stomach = {"", "", ""}
 end
   self.head:bind('ate_grass', function(self, ev)
     player:eat_grass(ev.grass.color)
   end)
+end
 
-  self:bind("collision", function(self, ev)
-    if ev.other.type == "CHECKPOINT" then
-      game.player_respawn = {map = game.map_manager.map.name, x = ev.other.x + self:box_side("left"), y = ev.other.y - self:box_side("bottom")}
-      beetle.update("Checkpoint", "Map: "..game.player_respawn.map.." x: "..game.player_respawn.x.." y: "..game.player_respawn.y)
-    end
+function Player:do_collide(ev)
+  Actor.do_collide(self, ev)
+  if ev.other.type == "CHECKPOINT" then
+    game.player_respawn = {map = game.map_manager.map.name, x = ev.other.x + self:box_side("left"), y = ev.other.y - self:box_side("bottom")}
+    beetle.update("Checkpoint", "Map: "..game.player_respawn.map.." x: "..game.player_respawn.x.." y: "..game.player_respawn.y)
+  end
 
-    if ev.other.type == "TELEPORT" then
-      teleport_object = {
-        map = ev.other.properties.map,
-        x = ev.other.properties.x,
-        y = ev.other.properties.y
-      }
-      game:teleport(teleport_object)
-    end
+  if ev.other.type == "TELEPORT" then
+    teleport_object = {
+      map = ev.other.properties.map,
+      x = ev.other.properties.x,
+      y = ev.other.properties.y
+    }
+    game:teleport(teleport_object)
+  end
 
-    if ev.other.friendly == false then
-      game:teleport(game.player_respawn)
-    end
-  end)
+  if ev.other.friendly == false then
+    game:teleport(game.player_respawn)
+  end
 end
 
 function Player:eat_grass(color)
   end
 end
 
-function Player:die()
-  game.lives = game.lives - 1
-  if game.lives < 0 then
-    -- go to game over
-  else
-    Player:respawn()
-  end
-end
-
 return Player

File assets/images/bg1/sky.jpg

Added
New image

File assets/images/bg2/clouds.png

Added
New image

File assets/images/bg3/clouds.png

Added
New image

File assets/images/bg3/crappymountains.png

Added
New image

File assets/images/tiles/test-tiles-16-16.png

Old
Old image
New
New image

File assets/maps/cowtest.tmx

    <properties>
     <property name="collides" value="1"/>
     <property name="map" value="teleporttest"/>
-    <property name="x" value="200"/>
-    <property name="y" value="200"/>
+    <property name="x" value="32"/>
+    <property name="y" value="224"/>
    </properties>
   </object>
   <object x="304" y="96"/>

File assets/maps/teleporttest.tmx

 <?xml version="1.0" encoding="UTF-8"?>
-<map version="1.0" orientation="orthogonal" width="100" height="50" tilewidth="16" tileheight="16" backgroundcolor="#b0e2f3">
+<map version="1.0" orientation="orthogonal" width="50" height="20" tilewidth="16" tileheight="16" backgroundcolor="#b0e2f3">
  <tileset firstgid="1" name="IHCTiles" tilewidth="16" tileheight="16">
-  <image source="../images/tiles/test-tiles-16-16.png" width="160" height="160"/>
+  <image source="../images/tiles/test-tiles-16-16.png" width="160" height="192"/>
   <terraintypes>
    <terrain name="Grass" tile="-1"/>
    <terrain name="Ice" tile="-1"/>
   <tile id="51" terrain=",0,,"/>
   <tile id="52" terrain="0,0,,"/>
   <tile id="53" terrain="0,,,"/>
+  <tile id="60" terrain=",,,0"/>
+  <tile id="61" terrain=",,0,0"/>
+  <tile id="62" terrain=",,0,"/>
+  <tile id="70" terrain=",0,,0"/>
+  <tile id="71" terrain="0,0,0,0"/>
+  <tile id="72" terrain="0,,0,"/>
+  <tile id="80" terrain=",0,,"/>
+  <tile id="81" terrain="0,0,,"/>
+  <tile id="82" terrain="0,,,"/>
  </tileset>
- <tileset firstgid="101" name="Collision Tiles" tilewidth="16" tileheight="16">
+ <tileset firstgid="121" name="Collision Tiles" tilewidth="16" tileheight="16">
   <image source="../images/tiles/collision-tiles.png" width="48" height="16"/>
   <tile id="0">
    <properties>
    </properties>
   </tile>
  </tileset>
- <layer name="BG" width="100" height="50">
+ <layer name="BG" width="50" height="20">
   <data encoding="base64" compression="zlib">
-   eJzt07EKwjAQgOFQXTuqdWrVSZzt+z+aF0zHDk4n5PvgJzceHCkFAH43RIedjol79WqOxugcXaKpza/omrhXr07le4N7e29tXop7ZKj3qH+h3mH7H7UleuSt1a1n9N5pTdwLAAAAAAAAAAAAAAAAAAAA4F98ACFhBE8=
+   eJztwTEBAAAAwqD1T20MH6AAAACAtwEPoAAB
   </data>
  </layer>
- <layer name="MG" width="100" height="50">
+ <layer name="MG" width="50" height="20">
   <data encoding="base64" compression="zlib">
-   eJztmk+PmzAQxUdtD1V3sz01SU9r0lM37bHf/6uVUfjJDxcSkkBwV/OkkQkxYM+bfzaY1YVvraRWvq88jjnxoZWPA/Jsp7luW9lYnXN2Pvat/Fh7IDPBuXC9N63s7KR3b/dd6+cPrRytzjk7H7Xayi14tZP9Jzvp3Y/3XXuU8z7nWvlwu6lxbLfA5+O633XtoTt2LpyX1J3ztkYb9PH7+N4LHz9bebOsc49PxCx42li9c36P+dw5+VOIc0QeJ47VOGfi1YvlOuTTxGupY6b2XxOeV5L18/tc/vG5lS8z3Qv/Juddk0u8jvH5vcw0liXhfPhYmaP7SI3+4Sj9+/fE68idtc5LQV2f7JTbH1Xvzuk7l0AMqDEvlvCxUmOxBvkf7GgMY2tel68rjmsq3D/gYY714CPtfgjEJvKhz4favnb/eLK8V8K4nZs1/eMePs/5hsrSdZaOY+qz4IK1occrtynno0Y7wu6n6HsuuTa+PVneD9xYrummPKvcy/Lj1M15KT7usX3dX3iUuF4ucQIH6FSvZx9qK2NvuvPkCF2LNyIH6Vezfzyaj0v2jV1732SZg73lmLO1Pg9+/iB92DMhh7PuoM6qlY9HcqGclHvg7MFi00dp2ZNl71bXdawr2KNq5P601Lk8L/zjX0mWY05juX7z89RA2Dg6p76DB9035L66t66cJMu81bzfvhQf5Z6eCvFF447/LnNAssxNspzPj5b1Tl/4bOT3sThWfmrkYy3w3qjMC4ifgxf4Re/oEx6TZV/T9Tf32Fo/x++6fr7+0LphjRq+FrC/t7P+GlN9hXP0IUbBYbKsX9U7/kM8O8h91ZfcP3g/qvlGhTUjvL1XfpyPodhe5nbNK+hb612uwU+4p9YFmsfL9x/wob6p/FAHPnf3nGtNf+6bi6Xy9bk4oLpJlnWL/dOiV30PvpdjrXV1fZGKvppz6AMfWn9pf84x1jm+M4AHYsIade2QEIuIL+oTmte19tWcwG/67eReSLIc9zTX0A7xoZxoHuOaW2uAa3nQNewSvKiN8TtZ346pgYlRet1RrtXai+vhTXWInSfrrwc5Dx+NDc9fazm4nrpPU8otPAyNaez/Mf7O8Tp2ra6z1c61j9aqmruJW+hc14fH4t6I7ku/XpjPmH9fK/dw8ShBX5orsH3WHBrHk/VtXvkp97TwryTPSzJv8rnyoXpZI7bXwI/GavjBH8qaVX0D28U3dpZjnu5b0Wqe4Xlj/jFV7tHZmM7X5EP3ojjeSIvO9R2Sfneh9bB+A9dYv86CF63XeD849G1QyDLyJpz9Gvh/6ncbgXmgth+6DwQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgbrwFzFIlsM=
+   eJztU0EKwzAMM9tx7TXxbU2Py47b/782ByyqhRU6KKWBCETaxEtlSxPp6Ojo6OhYx8V4/cHWMBjHH2wBax605seaB2f3Y8v8W/Bjy/zP6MdN/p//GfyodZf5z0Y1Tr6WGQdjNiZf1evwrH52lB913pEb6Ct6I+kOdDa69iBLryP1Enw9Sjd/FzOcSF/w90T9IPuR+lN6zn5W9vbIZs3B7wcnWXISqYfoPUC/Uq3Sil6RsbnqrdTdvRZ3Jlkymuh3gfYizU3le86J9qCp1oW9RDWZ3tkvZClX/fJ/qPBlfO/Ah38TeX7udO9WfgDvFhsc
   </data>
  </layer>
- <layer name="FG" width="100" height="50">
+ <layer name="FG" width="50" height="20">
   <data encoding="base64" compression="zlib">
-   eJzt2LsKwkAQBdBBS0UrH52vylen/v+nuctqr2AcMefAJe2Ey+6QRACvGpQMH5kmz9J3o5JxybpkUzIJvWSaRethUXKM1su15JY4U5+tovWxjNbHMXec3qt91LOxjdbJPHec3ruUHKL1UPvY5I5DtB1S76nt43kK+yNT7aOej9qDXZ5vH62Hc/YgAAAAHavfo4uOwvue/5g/nd03X+KP6OO36AMAAAAAAAAAAAAA+JY7m/YQpA==
+   eJztwTEBAAAAwqD1T20MH6AAAACAtwEPoAAB
   </data>
  </layer>
- <layer name="Collision" width="100" height="50">
+ <layer name="Collision" width="50" height="20">
   <data encoding="base64" compression="zlib">
-   eJzt10EOgzAQQ1EuC9z/Bt1mU9LJJGOT/id5WdXEikqPw8vVZBdXIG6cu42IbOH4zM7dRrCHl+gebnuxB3ustsse0R5nE3cr95i5XabH3cTdm+7LP+9R9b0V2EPn7MTd7D3Ue96dOFP/Hjx1GtG7G1X3JPPu47bHNzPf1Ve9p7j0iPbNfNZtE4cOCso9HOJGfR7quFGfhzpu1Oehjpve/4pMnqh3cN2MPX7bo2of9tDcF/Uz7JQMdfcdM0LdmRBCCCGkKqjD2QMAAAAAAAAAAACArw+pH2+H
+   eJztkUEKADAIw/btbZ/fCwoenFpIIPdq1gIAANBsoRtX6IBq4NZDNZjeI/J/hx6R/0/scRLsIGN3xx0/dlfcUbEbscIHmRuOBQ==
   </data>
  </layer>
- <objectgroup name="Objects" width="100" height="50">
-  <object name="Cat" type="SPAWN" x="304" y="368" width="16" height="16">
+ <objectgroup name="Objects" width="50" height="20">
+  <object name="Checkpoint" type="CHECKPOINT" x="16" y="224" width="64" height="48">
    <properties>
-    <property name="spawn" value="CatActor"/>
-   </properties>
-  </object>
-  <object name="Player" type="SPAWN" x="64" y="256" width="16" height="16">
-   <properties>
-    <property name="spawn" value="Player"/>
-   </properties>
-  </object>
-  <object name="Blue Grass" type="SPAWN" x="1008" y="336" width="16" height="16">
-   <properties>
-    <property name="color" value="blue"/>
-    <property name="spawn" value="GrassActor"/>
+    <property name="collides" value="1"/>
    </properties>
   </object>
-  <object name="Green Grass" type="SPAWN" x="768" y="144" width="16" height="16">
+  <object name="Teleport to new Map" type="TELEPORT" x="784" y="0" width="16" height="208">
    <properties>
-    <property name="color" value="green"/>
-    <property name="spawn" value="GrassActor"/>
+    <property name="collides" value="1"/>
+    <property name="map" value="cowtest"/>
+    <property name="x" value="64"/>
+    <property name="y" value="288"/>
    </properties>
   </object>
-  <object name="Red Grass" type="SPAWN" x="0" y="304" width="16" height="16">
+  <object name="Red Grass" type="SPAWN" x="352" y="240" width="16" height="16">
    <properties>
     <property name="color" value="red"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Red Grass" type="SPAWN" x="16" y="304" width="16" height="16">
+  <object name="Red Grass" type="SPAWN" x="416" y="224" width="16" height="16">
    <properties>
     <property name="color" value="red"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Red Grass" type="SPAWN" x="32" y="304" width="16" height="16">
+  <object name="Red Grass" type="SPAWN" x="480" y="208" width="16" height="16">
    <properties>
     <property name="color" value="red"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Green Grass" type="SPAWN" x="784" y="144" width="16" height="16">
+  <object name="Blue Grass" type="SPAWN" x="368" y="240" width="16" height="16">
    <properties>
-    <property name="color" value="green"/>
-    <property name="spawn" value="GrassActor"/>
-   </properties>
-  </object>
-  <object name="Green Grass" type="SPAWN" x="800" y="144" width="16" height="16">
-   <properties>
-    <property name="color" value="green"/>
+    <property name="color" value="blue"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Blue Grass" type="SPAWN" x="1024" y="336" width="16" height="16">
+  <object name="Blue Grass" type="SPAWN" x="432" y="224" width="16" height="16">
    <properties>
     <property name="color" value="blue"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Blue Grass" type="SPAWN" x="1040" y="336" width="16" height="16">
+  <object name="Blue Grass" type="SPAWN" x="496" y="208" width="16" height="16">
    <properties>
     <property name="color" value="blue"/>
     <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Moving Platform" type="SPAWN" x="272" y="272" width="16" height="16">
+  <object name="Green Grass" type="SPAWN" x="384" y="240" width="16" height="16">
    <properties>
-    <property name="spawn" value="MovingPlatformActor"/>
+    <property name="color" value="green"/>
+    <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Checkpoint" type="CHECKPOINT" x="576" y="192" width="32" height="16">
+  <object name="Green Grass" type="SPAWN" x="448" y="224" width="16" height="16">
    <properties>
-    <property name="collides" value="1"/>
+    <property name="color" value="green"/>
+    <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object name="Teleport to new Map" type="TELEPORT" x="0" y="0" width="16" height="64">
+  <object name="Green Grass" type="SPAWN" x="512" y="208" width="16" height="16">
    <properties>
-    <property name="collides" value="1"/>
-    <property name="map" value="teleporttest"/>
-    <property name="x" value="200"/>
-    <property name="y" value="200"/>
+    <property name="color" value="green"/>
+    <property name="spawn" value="GrassActor"/>
    </properties>
   </object>
-  <object x="304" y="96"/>
  </objectgroup>
 </map>
   -- Set the font for the whole game. srsly
   local font = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 16)
   love.graphics.setFont(font)
-  love.graphics.setColor(255,255,255,200)
 end
 
 function Game:initialize_collider()
   self.collider.initialize(16)
 
   function self.collider.collision(actor1, actor2, dx, dy)
-    if actor1.dispatch then
-      actor1:dispatch('collision', { other = actor2, dx = dx, dy = dy })
+    if actor1.do_collide then
+      actor1:do_collide({ other = actor2, dx = dx, dy = dy })
     end
-    if actor2.dispatch then
-      actor2:dispatch('collision', { other = actor1, dx = -dx, dy = -dy })
+    if actor2.do_collide then
+      actor2:do_collide({ other = actor1, dx = -dx, dy = -dy })
     end
   end
 
   function self.collider.endCollision(actor1, actor2)
-    if actor1.dispatch then
-      actor1:dispatch('endCollision', { other = actor2})
+    if actor1.end_collide then
+      actor1:end_collide({ other = actor2})
     end
-    if actor2.dispatch then
-      actor2:dispatch('endCollision', { other = actor1})
+    if actor2.end_collide then
+      actor2:end_collide({ other = actor1})
     end
   end
 
 end
 
 function Game:draw_text(message, y)
+  local colorMode = love.graphics.getColorMode()
   love.graphics.setColorMode("modulate")
   love.graphics.printf(message, 0, y, love.graphics.getWidth(), "center")
-  love.graphics.setColorMode("replace")
+  love.graphics.setColorMode(colorMode)
 end
 
 return Game

File lib/vendor/AdvancedTiledLoader/Object.lua

     obj.properties = prop or {} -- Properties set by tiled.
     obj.polygon = nil           -- Polygon points. Set by the Loader if defined in Tiled.
     obj.polyline = nil          -- Polyline points. Set by the Loader if defined in Tiled.
-    
+
     -- drawInfo stores values needed to actually draw the object. You can either set these yourself
     -- or use updateDrawInfo to do it automatically.
     obj.drawInfo = {
-    
+
         -- x and y are the drawing location of the object. This is different than the object's x and
         -- y value which is the object's placement on the map.
         x = 0,      -- The x draw location
         y = 0,      -- The y draw location
-        
+
         -- These limit the drawing of the object. If the object falls out of the bounds of
-        -- the map's drawRange then the object will not be drawn. 
+        -- the map's drawRange then the object will not be drawn.
         left = 0,   -- The leftmost point on the object
         right = 0,  -- The rightmost point on the object
         top = 0,    -- The highest point on the object
         bottom = 0, -- The lowest point on the object
-        
+
         -- The order to draw the object in relation to other objects. Usually equal to bottom.
         order = 0,
-        
-        -- In addition to this, other drawing information can be stored in the numerical 
+
+        -- In addition to this, other drawing information can be stored in the numerical
         -- indicies which is context sensitive to the map's orientation, if the object has a gid, or
         -- of the object is a polygon or polyline object.
-    } 
-    
+    }
+
     -- Update the draw info
     Object.updateDrawInfo(obj)
-    
+
     -- Return our object
     return obj
 end
 function Object:updateDrawInfo()
     local di = self.drawInfo
     local map = self.layer.map
-        
+
     if self.polygon or self.polyline then
         -- Reset the draw info
         self.drawInfo = {}
         -- Create the draw information for each vertex
         for k,v in ipairs(vertexes) do
             if k%2 == 1 then
-                if map.orientation == "isometric" then 
+                if map.orientation == "isometric" then
                     di[k], di[k+1] = map:fromIso(self.x+vertexes[k], self.y+vertexes[k+1])
                 else
                     di[k], di[k+1] = self.x+vertexes[k], self.y+vertexes[k+1]
             end
         end
         di.order = di.bottom
-    
+
     -- Isometric map
     elseif map.orientation == "isometric" then
         -- Is a tile object
             di.left, di.right, di.top, di.bottom = di[7], di[3], di[2], di[6]
             di.order = 1
         end
-        
+
     -- Orthogonal map
     else
         -- Is a tile object
 function Object:draw(x, y, r, g, b, a)
 
     if not self.visible then return end
-    
+
     local di = self.drawInfo
-    love.graphics.setLineWidth(2)
+    love.graphics.setLineWidth(1)
 
     -- The object is a polyline.
     if self.polyline then
         love.graphics.pop()
         love.graphics.setColor(r, g, b, a)
         love.graphics.line( unpack(di) )
-        
+
     -- The object is a polygon.
     elseif self.polygon then
         love.graphics.push()
         love.graphics.polygon( "line", unpack(di) )
         love.graphics.pop()
         love.graphics.setColor(r,g,b,a)
-        love.graphics.polygon( "line", unpack(di) ) 
-        
+        love.graphics.polygon( "line", unpack(di) )
+
     -- The object is a tile object. Draw the tile.
     elseif self.gid then
         local tile = self.layer.map.tiles[self.gid]
         tile:draw(di.x, di.y - tile.height)
-        
+
     -- Map is isometric. Draw a parallelogram.
     elseif self.layer.map.orientation == "isometric" then
         love.graphics.setColor(r, g, b, a/5)
         love.graphics.polygon("fill", unpack(di))
-        
+
         love.graphics.push()
         love.graphics.translate(0,1)
         love.graphics.setColor(0, 0, 0, a)
         love.graphics.polygon("line", unpack(di))
         love.graphics.pop()
-            
+
         love.graphics.setColor(r,g,b,a)
         love.graphics.polygon("line", unpack(di))
 
     else
         love.graphics.setColor(r, g, b, a/5)
         love.graphics.rectangle("fill", unpack(di))
-            
+
         love.graphics.setColor(0, 0, 0, a)
         love.graphics.push()
         love.graphics.translate(1,1)
         love.graphics.rectangle("line", unpack(di))
-        love.graphics.print(self.name, di.x, di.y-20)
         love.graphics.pop()
-            
-        love.graphics.setColor(r,g,b,a)
-        love.graphics.rectangle("line", unpack(di))
-        love.graphics.print(self.name, di.x, di.y-20)
+
+        love.graphics.push()
+        love.graphics.scale(0.5)
+        love.graphics.print(self.name, di.x*2, di.y*2-20)
+        love.graphics.pop()
     end
 end
 
 CustomEvent = require('lib/vendor/custom_event')
 CustomEventSupport = require('lib/vendor/custom_event_support')
 
-
 -- Lib
 require('lib/extra_math')
 
   --configuration (this should probably be its own file, um, TODO)
   next_time = love.timer.getMicroTime()
 
-  --set scale mode
+  --set graphics options
   love.graphics.setDefaultImageFilter( 'nearest', 'nearest' )
 
   -- Load the cam
 
 function debug_message(message, x, y)
   local r,g,b,a = love.graphics.getColor()
+  local colorMode = love.graphics.getColorMode()
   love.graphics.setColorMode("modulate")
   love.graphics.setColor(0,0,0,255)
   love.graphics.print(message, x, y)
-  love.graphics.setColorMode("replace")
+  love.graphics.setColorMode(colorMode)
   love.graphics.setColor(r,g,b,a)
 end
 
+function ripairs(t)
+  local max = 1
+  while t[max] ~= nil do
+    max = max + 1
+  end
+  local function ripairs_it(t, i)
+    i = i-1
+    local v = t[i]
+    if v ~= nil then
+      return i,v
+    else
+      return nil
+    end
+  end
+  return ripairs_it, t, max
+end
+
 function love.quit()
   print("Goodbye!")
 end

File map_manager.lua

 function MapManager:load_map(map)
   self:unload_map()
   self.map = self.loader.load(map)
+  self.map("Objects").visible = false
   beetle.update("Map", self.map.name)
   self.map.useSpriteBatch = true
   self.map("Collision").visible = false
   camera:setWorld(0,0,self.map.width*self.map.tileWidth, self.map.height*self.map.tileHeight)
   camera:setPosition(0,0)
+  self:load_backgrounds()
   self:initialize_objects()
 end
 
+function MapManager:load_backgrounds()
+  -- PARALLAX TESTING. DO NOT KEEP THIS CODE.
+  self.bg1 = love.graphics.newImage("assets/images/bg1/sky.jpg")
+  self.bg2 = love.graphics.newImage("assets/images/bg2/clouds.png")
+  self.bg3 = love.graphics.newImage("assets/images/bg3/crappymountains.png")
+end
+
 function MapManager:initialize_objects()
   for i, v in ipairs(self.map("Objects").objects) do
     if v.properties.collides == 1 then
       end
     end
   end
+  self:unload_backgrounds()
+end
+
+function MapManager:unload_backgrounds()
+  self.bg1 = nil
+  self.bg2 = nil
+  self.bg3 = nil
 end
 
 -- TODO: Have a way to decide when to draw which layer.
 function MapManager:draw()
+  self:draw_backgrounds()
   if self.map then
     self.map:draw()
   end
 end
 
+function MapManager:draw_backgrounds()
+  if self.bg1 then
+    self:draw_background(self.bg1)
+  end
+
+  if self.bg2 then
+    self:draw_background(self.bg2, true)
+  end
+
+  if self.bg3 then
+    self:draw_background(self.bg3, true)
+  end
+end
+
+function MapManager:draw_background(image)
+    local tx, ty = camera:toWorld(0,0)
+    local image_w = image:getWidth()
+    local image_h = image:getHeight()
+    local viewport_w = love.graphics.getWidth()
+    local viewport_h = love.graphics.getHeight()
+    local map_w = game.map_manager.map.width * game.map_manager.map.tileWidth
+    local map_h = game.map_manager.map.height * game.map_manager.map.tileHeight
+
+    -- maximum value of offset
+    local max_x = (map_w - viewport_w / camera.scale)
+    local max_y = (map_h - viewport_h / camera.scale)
+    -- ratio between current offset and max offset
+    -- Check offset to avoid 0/0 when map is same size as viewport
+    local cx, cy = 0, 0
+    if max_x > 0 then
+      cx = tx / max_x
+    end
+    if max_y > 0 then
+      cy = ty / max_y
+    end
+    -- difference between image and viewport
+    local dx = (viewport_w - image_w) / camera.scale
+    local dy = (viewport_h - image_h) / camera.scale
+
+    local px = tx + dx * cx
+    local py = ty + dy * cy
+
+    love.graphics.draw(image, px, py, 0, 0.5, 0.5)
+end
+
 function MapManager:draw_fg()
   if self.map then
     self.map("FG"):draw()

File screens/game.lua

 end
 
 function GameScreen:teleport(destination)
-  if self.map_manager.map.name ~= destination.map then
+  local old_map = self.map_manager:map_name(self.map_manager.map.name)
+  local new_map = self.map_manager:map_name(destination.map)
+  if old_map ~= new_map then
+    game.unloading = true
     self.actor_manager:unload()
-    self.map_manager:load_map(self.map_manager:map_name(destination.map))
+    self.map_manager:load_map(new_map)
+    game.unloading = false
   end
   self.actor_manager.player.x = destination.x
   self.actor_manager.player.y = destination.y