Commits

benbeltran committed 3a3f8ba

Message system + triggers

  • Participants
  • Parent commits aecbaeb

Comments (0)

Files changed (14)

File actor_manager.lua

 function ActorManager:initialize()
   self.actors = {}
   self.main_actor = nil
+  game:move_in(self)
 end
 
 function ActorManager:update(dt)
 
 function ActorManager:draw(dt)
   for pos, actor in ipairs(self.actors) do
-    if not actor.dying then
+    if not actor.dying and actor ~= self.player then
       actor:draw(dt)
     end
   end
+
+  if self.player then
+    self.player:draw()
+  end
 end
 
 function ActorManager:move_in(actor)

File actors/bovine_head.lua

   self.box.right = 4
 
   self.survives_map = true
+
+  self.key_times = {
+    down = 0,
+    z = 0
+  }
+
+  self.interaction_helpers = {
+    down = love.graphics.newImage("assets/images/sprites/static/down_key_16x16.png"),
+    z = love.graphics.newImage("assets/images/sprites/static/z_key_16x16.png")
+  }
+  self.ended_collision = 0
 end
 
 function BovineHeadActor:draw()
+  if self.interaction_helper then
+    self:_draw_interaction_helper(self.interaction_helper)
+  end
   self:draw_bounding_box()
 end
 
 function BovineHeadActor:do_collide(ev)
   if ev.other.name == "Grass" then
-    if love.keyboard.isDown("down") and not self.eat_lock then
+    self.interaction_helper = "down"
+    if self.key_times["down"] > 0 and not self.eat_lock then
       self.eat_lock = true
       self:dispatch('ate_grass', {grass = ev.other})
       ev.other:dispatch('eaten')
     end
   end
+
+  if ev.other.triggerable then
+    self.interaction_helper = "z"
+    if self.key_times["z"] > 0 and not self.interact_lock and
+        love.timer.getMicroTime() - self.key_times["z"] <= 0.05
+      then
+      self.interact_lock = true
+      self:dispatch('interaction', other)
+      ev.other:trigger()
+    end
+  end
+end
+
+function BovineHeadActor:end_collide(ev)
+  Player.end_collide(self, ev)
+
+  if ev.other.triggerable or ev.other.name == "Grass" then
+    self.ended_collision = love.timer.getMicroTime()
+  end
 end
 
 function BovineHeadActor:update()
-  if not love.keyboard.isDown ("down") then
+  self:_update_keys()
+  if love.timer.getMicroTime() - self.ended_collision  < 0.1 then
+    self.interaction_helper = nil
+  end
+end
+
+function BovineHeadActor:_update_keys()
+  if love.keyboard.isDown ("z") then
+      self:update_time("z")
+  else
+    self.key_times["z"] = 0
+    self.interact_lock = false
+  end
+
+  if love.keyboard.isDown ("down") then
+    self:update_time("down")
+  else
+    self.key_times["down"] = 0
     self.eat_lock = false
   end
 end
 
+function BovineHeadActor:update_time(direction)
+  if self.key_times[direction] == 0 then
+    self.key_times[direction] = love.timer.getMicroTime()
+  end
+end
+
+function BovineHeadActor:_draw_interaction_helper(key)
+  if self.interaction_helpers[key] then
+    love.graphics.draw(self.interaction_helpers[key], self.x - 8, self.y - 32)
+  end
+end
+
 return BovineHeadActor

File actors/player.lua

 
   Actor.initialize(self, x, y, image)
 
+  self.jumplock = true
 
   self.box.top = -12
   self.box.left = 12
     down = 0,
     left = 0,
     right = 0,
-    z = 0
+    z = 0,
+    x = 0
   }
 
   self.survives_map = true
   self.head:bind('ate_grass', function(self, ev)
     player:eat_grass(ev.grass.color)
   end)
+
+  self.head:bind('interaction', function(self, ev)
+    player.z_lock = true
+  end)
 end
 
 function Player:do_collide(ev)
   --TODO: Move these "right, left, etc." to a config file. Much laters though.
   --NOTE: Joystick buttons mapped to xbox controller
 
-  if love.keyboard.isDown ("z") then
-    self:update_time("z")
-  else
-    self.key_times["z"] = 0
-  end
-
-  if love.keyboard.isDown ("up") then
-    self:update_time("up")
-  else
-    self.key_times["up"] = 0
-  end
-
-  if love.keyboard.isDown ("down") then
-    self:update_time("down")
-  else
-    self.key_times["down"] = 0
-  end
-
-  if love.keyboard.isDown ("left") then
-    self:update_time("left")
-  else
-    self.key_times["left"] = 0
-  end
-
-  if love.keyboard.isDown ("right") then
-    self:update_time("right")
-  else
-    self.key_times["right"] = 0
-  end
+  self:update_head()
+  self:_update_keys()
 
-  if self.key_times["z"] > 0 then
+  if self.key_times["x"] > 0 then
     self:jump(dt)
   else
     self:unjump(dt)
 
   self:physics(dt)
   self:centermap()
-  self:update_head()
 
   -- DEBUG
   beetle.update("Stomach", table.inspect(self.stomach))
 end
 
+function Player:_update_keys()
+  if love.keyboard.isDown ("x") then
+      self:update_time("x")
+  else
+    self.key_times["x"] = 0
+  end
+
+  if love.keyboard.isDown ("up") then
+    self:update_time("up")
+  else
+    self.key_times["up"] = 0
+  end
+
+  if love.keyboard.isDown ("down") then
+    self:update_time("down")
+  else
+    self.key_times["down"] = 0
+  end
+
+  if love.keyboard.isDown ("left") then
+    self:update_time("left")
+  else
+    self.key_times["left"] = 0
+  end
+
+  if love.keyboard.isDown ("right") then
+    self:update_time("right")
+  else
+    self.key_times["right"] = 0
+  end
+
+end
+
 function Player:update_head()
   if self.dir == "right" then
     self.head.x = self.x + self.x_head_offset

File actors/trigger.lua

+local TriggerActor = class('TriggerActor', Actor)
+
+function TriggerActor:initialize(x, y)
+  local image = "assets/images/sprites/static/sign_32x32.png"
+  self.name = "Trigger"
+  Actor.initialize(self, x, y, image)
+
+  self.skip_same_collision = true
+  self.immutable           = true
+  self.passable            = true
+  self.triggerable         = true
+end
+
+function TriggerActor:set_attribute(key, value)
+  Actor.set_attribute(self, key, value)
+
+  if key == "image" then
+    self.image = love.graphics.newImage(value)
+  end
+end
+
+function TriggerActor:trigger()
+  if self.trigger_type == "message" then
+    Message(self.trigger_value)
+  end
+  if self.trigger_type == "animation" then
+    print("Not yet implemented.")
+  end
+end
+
+return TriggerActor

File assets/fonts/mw_pithy_8point.ttf

Binary file added.

File assets/images/sprites/static/down_key_16x16.png

Added
New image

File assets/images/sprites/static/sign_32x32.png

Added
New image

File assets/images/sprites/static/z_key_16x16.png

Added
New image

File assets/maps/cowtest.tmx

 <?xml version="1.0" encoding="UTF-8"?>
 <map version="1.0" orientation="orthogonal" width="100" height="50" 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="52" terrain="0,0,,"/>
   <tile id="53" 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>
  </layer>
  <layer name="Collision" width="100" height="50">
   <data encoding="base64" compression="zlib">
-   eJzt10EOgzAQQ1EuC9z/Bt1mU9LJJGOT/id5WdXEikqPw8vVZBdXIG6cu42IbOH4zM7dRrCHl+gebnuxB3ustsse0R5nE3cr95i5XabH3cTdm+7LP+9R9b0V2EPn7MTd7D3Ue96dOFP/Hjx1GtG7G1X3JPPu47bHNzPf1Ve9p7j0iPbNfNZtE4cOCso9HOJGfR7quFGfhzpu1Oehjpve/4pMnqh3cN2MPX7bo2of9tDcF/Uz7JQMdfcdM0LdmRBCCCGkKqjD2QMAAAAAAAAAAACArw+pH2+H
+   eJzt10EOwjAQQ9Feu+3l2WZDw2SSsRv+k7xEuLEiynF4uZrs4grEjXO3EZEtHJ/ZudsI9vAS3cNtL/Zgj9V22SPa42zibuUeM7fL9LibuHvTffnnPaq+twJ76JyduJu9h3rPuxNn6t+Dp04jenej6p5k3n3c9vhm5rv6qvcUlx7RvpnPum3i0EFBuYdD3KjPQx036vNQx436PNRx0/tfkckT9Q6um7HHb3tU7cMemvuifoadkqHuvmNGqDsTQgghhFQFdTh7AAAAAAAAAAAAAPD1AeBc6bc=
   </data>
  </layer>
  <objectgroup name="Objects" width="100" height="50">
    </properties>
   </object>
   <object x="304" y="96"/>
+  <object name="Sign" type="SPAWN" x="176" y="304" width="16" height="16">
+   <properties>
+    <property name="image" value="assets/images/sprites/static/sign_32x32.png"/>
+    <property name="spawn" value="TriggerActor"/>
+    <property name="trigger_type" value="message"/>
+    <property name="trigger_value" value="This is a triggered message. \n\n What does this mean? \n\n Well. Two things: First, triggerable events are implemented. Second: The message system works generically now. Woo!"/>
+   </properties>
+  </object>
  </objectgroup>
 </map>
   self.current_player = self.min_players
 
   -- Set the font for the whole game. srsly
-  local font = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 16)
-  love.graphics.setFont(font)
+  self.fonts = {}
+  self.fonts.default = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 16)
+  self.fonts.big = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 24)
+  self.fonts.huge = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 36)
+  self.fonts.small = love.graphics.newFont("assets/fonts/QuattrocentoSans-Regular.ttf", 11)
+  self.fonts.message = love.graphics.newFont("assets/fonts/mw_pithy_8point.ttf", 16)
+  love.graphics.setFont(self.fonts.default)
 end
 
 function Game:initialize_collider()

File lib/message.lua

+local Message = class('Message')
+Message:include(CustomEventSupport)
+
+function Message:initialize(message, options)
+  self.message = self:_parse(message)
+
+  if not options then
+    options = {}
+  end
+
+  -- mark as passive
+  self.passive = true
+
+  -- display settings
+  self.padding = "10"
+  self.margin = "10"
+
+  -- animation and such
+  self.speed = self:_calculate_speed(options.speed or "fast") -- TODO: Play with this later
+  self.current_char = 0
+
+  self.autoclose = options.autoclose or false
+
+  self.opacity = 0.0
+  self.max_opacity = 128
+  self.current_index = 1
+
+  -- Smartish pausing (or triggered)
+  self.pause = 0
+  self.full_pause = 8
+
+  self.position = self:set_position(options.position)
+
+  -- DON'T draw inside camera
+  self.overlay = true
+
+  if love.keyboard.isDown("z") then
+    self.key_lock = true
+  end
+
+  game:move_in(self)
+  game:prioritize(self)
+end
+
+function Message:destroy()
+  game:deprioritize(self)
+  game:move_out(self)
+end
+
+function Message:_calculate_speed(speed)
+  return speed
+end
+
+function Message:set_position(position)
+  position = position or self:calculate_position()
+
+  if position == "top" then
+    self.y = 0
+  elseif position == "center" then
+    self.y = ( love.graphics.getHeight() / 2 - love.graphics.getHeight() / 6)
+  else
+    self.y = love.graphics.getHeight() - (love.graphics.getHeight() / 3) - (self.margin)
+  end
+
+  self.x = 0
+  self.w = love.graphics.getWidth() - (2 * self.margin)
+  self.h = (love.graphics.getHeight() / 3) - (2 * self.margin)
+
+  self.time = 0
+
+end
+
+function Message:calculate_position()
+  -- check player position. Set top or bottom. Never center.
+end
+
+function Message:draw()
+  self:_draw_background()
+  self:_draw_text()
+end
+
+function Message:_draw_background()
+  local r,g,b,a = love.graphics.getColor()
+  love.graphics.setColor(0,0,0,self.max_opacity)
+  love.graphics.rectangle("fill", self.x + self.margin, self.y + self.margin, self.w, self.h)
+  love.graphics.setColor(r,g,b,a)
+end
+
+function Message:_draw_text()
+  local font = love.graphics.getFont()
+  love.graphics.setFont(game.fonts.message)
+  love.graphics.printf(self.message:sub(1, self.current_index), self.margin + self.padding + self.x, self.margin + self.padding + self.y, self.w - self.padding - self.margin, "left")
+
+  if self.shown_text then
+    love.graphics.printf(">>>", self.margin + self.padding + self.x + self.w - 50, self.y + self.margin + self.padding + self.h - 50, 50, "left")
+  end
+
+  love.graphics.setFont(font)
+end
+
+function Message:update(dt)
+  self.time = self.time + dt
+  if self.current_index < self.message:len() then
+    if self.pause > 0 then
+      self.pause = self.pause - 1
+    else
+      self:_calculate_pause()
+      self.current_index = self.current_index + 1
+    end
+  else
+    self.shown_text = true
+  end
+
+  self:_handle_input()
+end
+
+function Message:_handle_input()
+  if love.keyboard.isDown ("z") then
+    if not self.key_lock then
+      self.key_lock = true
+      self:_advance_message()
+    end
+  else
+    self.key_lock = false
+  end
+end
+
+function Message:_advance_message()
+  if not self.shown_text then
+    self.current_index = self.message:len()
+    self.shown_text = true
+  else
+    self:destroy()
+  end
+end
+
+function Message:_calculate_pause()
+  local cur_char = self.message:sub(self.current_index, self.current_index)
+
+  if self.speed == "fast" then
+    self.pause = 0
+  elseif self.speed == "slow" then
+    self.pause = 2
+  else
+    self.pause = 1
+  end
+
+  if cur_char == "." then
+    -- don't pause for ellipsis until the end.
+    if self.message:sub(self.current_index+1,self.current_index+1) ~= "." then
+      self.pause = self.pause + self.full_pause
+    end
+  end
+
+  if cur_char == "," then
+    self.pause = self.pause + self.full_pause / 2
+  end
+
+  if cur_char == "\\" then
+    -- Calculate the special commands here :3
+  end
+end
+
+function Message:_parse(message)
+  return message:gsub("\\n", "\n")
+end
+
+function Message:finish()
+  self:dispatch("messageComplete")
+end
+
+return Message
 -- Lib
 require('lib/extra_math')
 
+-- Shaders
+
 -- Game Components
 
 Game = require('game')
 GrassActor = require('actors/grass')
 CatActor = require('actors/cat')
 MovingPlatformActor = require('actors/moving_platform')
+TriggerActor = require('actors/trigger')
+
+Message = require('lib/message')
 
 entities = {}
 

File map_manager.lua

   self.tx = 0
   self.ty = 0
   self.padding = 4
+  game:move_in(self)
 end
 
 function MapManager:map_name(map_path)
-  if string.find(map_path, self.loader.path) then
-    _, _, name = string.find(map_path, self.loader.path.."(.*).tmx")
+  if map_path:find(self.loader.path) then
+    _, _, name = map_path:find(self.loader.path.."(.*).tmx")
   return name
   else
     return map_path

File screens/game.lua

 
   love.graphics.setBackgroundColor(171,222,231)
 
-  self.actor_manager = ActorManager()
+  -- Components API
+  self.components = {}
 
+  -- initialize components
   self.map_manager = MapManager()
+  self.actor_manager = ActorManager()
+
   self.map_manager:load_map("cowtest")
 end
 
 function GameScreen:draw()
-  camera:draw(function(l,t,w,h)
-    self.map_manager:draw()
-    self.actor_manager:draw()
-    self.map_manager:draw_fg()
-  end)
+
+  for pos, component in ipairs(self.components) do
+    if not component.overlay then
+      camera:draw(function(l,t,w,h)
+        component:draw()
+      end)
+    else
+      component:draw()
+    end
+  end
 end
 
 function GameScreen:update(dt)
   beetle.update("Actors", table.getn(self.actor_manager.actors))
-  self.map_manager:update(dt)
-  self.actor_manager:update(dt)
+  -- TODO: These guys aren't components. We'll need to adapt them. maybe.
   self.collider.collide()
+
+    if self.priority_component then
+      self.priority_component:update(dt)
+    else
+      for pos, component in ipairs(self.components) do
+        component:update(dt)
+      end
+    end
 end
 
 function GameScreen:exitedState()
   camera:setPosition(destination.x, destination.y)
 end
 
+function GameScreen:move_in(component)
+  table.insert(self.components, component)
+end
+
+function GameScreen:move_out(component)
+  for pos, current_actor in ipairs(self.components) do
+    if current_actor == component then
+      table.remove(self.components, pos)
+    end
+  end
+end
+
+function GameScreen:prioritize(component)
+  self.priority_component = component
+end
+
+function GameScreen:deprioritize(component)
+  if self.component == self.priority then
+    self.priority_component = nil
+  end
+end
+
 return GameScreen