Browse Source

Projectiles; Fixes; Idk;

bjorn 10 years ago
parent
commit
3996d01e42
10 changed files with 236 additions and 130 deletions
  1. 2 2
      data/animation/pigeon.lua
  2. 43 0
      deps/manager.lua
  3. 15 25
      game.lua
  4. 14 0
      goal.lua
  5. 1 1
      map.lua
  6. 6 4
      person.lua
  7. 99 98
      pigeon.lua
  8. 13 0
      projectile.lua
  9. 4 0
      require.lua
  10. 39 0
      rock.lua

+ 2 - 2
data/animation/pigeon.lua

@@ -1,7 +1,7 @@
 local Pigeon = extend(Animation)
 
-Pigeon.scale = .15
-Pigeon.default = nil
+Pigeon.scale = .3
+Pigeon.default = 'idle'
 Pigeon.states = {}
 
 Pigeon.states.idle = {

+ 43 - 0
deps/manager.lua

@@ -0,0 +1,43 @@
+Manager = class()
+
+function Manager:init()
+  self.objects = {}
+end
+
+function Manager:update()
+  lume.each(self.objects, 'update')
+end
+
+function Manager:paused()
+  lume.each(self.objects, 'paused')
+end
+
+function Manager:add(object)
+  lume.call(object.activate, object)
+  self.objects[object] = object
+
+  return object
+end
+
+function Manager:remove(object)
+  if not object then return end
+  f.exe(object.deactivate, object)
+  self.objects[object] = nil
+end
+
+function Manager:get(id)
+  return self.objects[id]
+end
+
+function Manager:each(fn)
+  lume.each(self.objects, fn)
+end
+
+function Manager:filter(fn)
+  return lume.values(lume.filter(self.objects, fn))
+end
+
+function Manager:count()
+  if not next(self.objects) then return 0 end
+  return lume.count(self.objects)
+end

+ 15 - 25
game.lua

@@ -6,37 +6,26 @@ function Game:load()
   self.view = View()
   self.map = Map(ctx)
   self.pigeon = Pigeon()
-  self.people = {}
-  self.buildings = {}
+  self.people = Manager()
+  self.buildings = Manager()
+  self.projectiles = Manager()
   self.hud = Hud()
+  self.goal = Goal()
 
-  lume.push(self.buildings, Building(650, 60, 100), Building(800, 60, 200))
+  for i = 1, 5 do
+    self.buildings:add(Building(300 + lume.random(self.map.width - 300), lume.random(20, 100), lume.random(60, 300)))
+  end
+
+  for i = 1, 50 do
+    self.people:add(Person(500 + lume.random(self.map.width - 500), 400, -1))
+  end
 end
 
 function Game:update()
   self.pigeon:update()
-  lume.each(self.people, function(person)
-    person:update()
-  end)
-
-  --[[lume.each(self.buildings, function(building)
-    building:update()
-  end)]]
-
-  if love.math.random() < .7 * ls.tickrate then
-    local x, dir
-
-    if love.math.random() < .5 then
-      x = 0
-      dir = 1
-    else
-      x = 800
-      dir = -1
-    end
-
-    lume.push(self.people, Person(x, 400, dir))
-  end
-
+  self.people:update()
+  self.buildings:update()
+  self.projectiles:update()
   self.world:update(ls.tickrate)
   self.view:update()
 end
@@ -44,6 +33,7 @@ end
 function Game:draw()
   flux.update(ls.dt)
   self.view:draw()
+  self.goal:draw()
 end
 
 function Game:keypressed(key)

+ 14 - 0
goal.lua

@@ -0,0 +1,14 @@
+Goal = class()
+Goal.size = 25
+
+function Goal:init()
+  self.x = ctx.map.width - self.size
+  self.y = ctx.map.height - ctx.map.ground.height - self.size
+  ctx.event:emit('view.register', {object = self})
+end
+
+function Goal:draw()
+  local g = love.graphics
+  g.setColor(0, 255, 0)
+  g.rectangle('line', self.x - self.size / 2, self.y - self.size / 2, self.size, self.size)
+end

+ 1 - 1
map.lua

@@ -1,5 +1,5 @@
 Map = class()
-Map.width = 1600
+Map.width = 2400
 Map.height = 600
 
 function Map:init()

+ 6 - 4
person.lua

@@ -23,7 +23,7 @@ function Person:init(x, y, dir)
 
   self.dead = false
   self.walkTimer = 1
-  self.deathTimer = 0
+  self.throwTimer = 3
 
   ctx.event:emit('view.register', {object = self})
 end
@@ -34,9 +34,12 @@ function Person:update()
       self.body:applyLinearImpulse(self.direction * 50, -100)
       return .6 + love.math.random() * .2
     end)
-  end
 
-  if self.dead then
+    self.throwTimer = timer.rot(self.throwTimer, function()
+      local rock = Rock(self.body:getX(), self.body:getY())
+      return 3 + love.math.random()
+    end)
+  else
     local x, y = self.body:getLinearVelocity()
     if (math.abs(x) < 1 and math.abs(y) < 1) or (math.abs(x) > 5000 and math.abs(y) > 5000) then
       lume.remove(ctx.people, self)
@@ -62,6 +65,5 @@ function Person:die()
     self.body:applyLinearImpulse(-500 + love.math.random() * 1000, love.math.random() * -800)
     self.body:applyTorque(-200 * love.math.random() * 400)
     self.body:setFixedRotation(false)
-    self.deathTimer = 1
   end
 end

+ 99 - 98
pigeon.lua

@@ -5,13 +5,17 @@ function Pigeon:init()
   self.y = 500
   self.prevx = self.x
   self.prevy = self.y
-  self.w = 20
-  self.h = 40
+
+  self.scale = .3
   self.speed = 200
-  self.direction = {x = 1, y = 0}
-  self.targetDirection = {x = 1, y = 0}
-  self.laser = false
-  self.laserLength = 0
+
+  self.laser = {
+    active = false,
+    length = 0,
+    angle = 0,
+    speed = .2,
+    tween = nil
+  }
 
   self.lives = 3
   self.health = 100
@@ -26,6 +30,8 @@ function Pigeon:init()
     end
   end)
 
+  self.animation.spine.skeleton:setToSetupPose()
+
   ctx.view.target = self
 
   ctx.event:emit('view.register', {object = self})
@@ -36,65 +42,15 @@ function Pigeon:update()
   self.prevy = self.y
 
   -- Movement
-  if self.animation.state.name ~= 'peck' then
-    if love.keyboard.isDown('left') then
-      self.x = self.x - self.speed * ls.tickrate
-      self.targetDirection.x = -1
-      self.animation.flipped = true
-    elseif love.keyboard.isDown('right') then
-      self.x = self.x + self.speed * ls.tickrate
-      self.targetDirection.x = 1
-      self.animation.flipped = false
-    end
-
-    if love.keyboard.isDown('up') then
-      self.targetDirection.y = -1
-    elseif love.keyboard.isDown('down') then
-      self.targetDirection.y = 1
-    else
-      self.targetDirection.y = 0
-    end
-
-    flux.to(self.direction, .4, self.targetDirection):ease('expoout')
-  end
-
-  local kills = 0
+  self:move()
 
   -- Laser
-  do
-    self.laser = love.keyboard.isDown(' ')
-    self.laser = false
-
-    if self.laser then
-      self.laserTween = flux.to(self, 1, {laserLength = 1000}):ease('expoout')
-
-      if self.laserLength > 0 then
-        local x1, y1 = self.x, self.y - self.h / 2
-        local x2, y2 = self.x + self.direction.x * self.laserLength, self.y + self.direction.y * self.laserLength - self.h / 2
-
-        ctx.world:rayCast(x1, y1, x2, y2, function(fixture)
-          local person = fixture:getBody():getUserData()
-          if person and person.die then
-            person:die()
-            lume.remove(ctx.people, person)
-            kills = kills + 1
-            return 1
-          end
-          return -1
-        end)
-      end
-    else
-      if self.laserTween then
-        self.laserTween:stop()
-        self.laserLength = 0
-      end
-    end
-  end
+  self:updateLaser()
 
-  -- Increase size and health on kill
-  if kills > 0 then
-    flux.to(self, .6, {w = self.w + 5 * kills, h = self.h + 10 * kills}):ease('elasticout')
-    self.health = math.min(self.health + 15 * kills, self.maxHealth)
+  -- Pecking
+  if not self.laser.active and love.keyboard.isDown('down') then self.animation:set('peck') end
+  if self.animation.state.name == 'peck' then
+    self:killThingsOnBeak()
   end
 
   -- Death
@@ -107,17 +63,7 @@ function Pigeon:update()
 
     self.health = self.maxHealth
     self.lives = self.lives - 1
-    self.w = self.w / 2
-    self.h = self.h / 2
-  end
-
-  -- Health decay
-  self.health = self.health - 10 * ls.tickrate
-
-  if love.keyboard.isDown(' ') then self.animation:set('peck') end
-
-  if self.animation.state.name == 'peck' then
-    self:killThingsOnBeak()
+    flux.to(self.animation, .6, {scale = self.animation.scale / 2}):ease('elasticin')
   end
 end
 
@@ -125,21 +71,75 @@ function Pigeon:draw()
   local g = love.graphics
   local x = lume.lerp(self.prevx, self.x, ls.accum / ls.tickrate)
   local y = lume.lerp(self.prevy, self.y, ls.accum / ls.tickrate)
-  g.setColor(255, 255, 255)
-  g.rectangle('line', x - self.w / 2, y - self.h, self.w, self.h)
 
-  if self.laser then
-    local x2, y2 = x + self.direction.x * self.laserLength, y + self.direction.y * self.laserLength
+  if self.laser.active then
+    local x2, y2 = x + math.cos(self.laser.angle) * self.laser.length, y + math.sin(self.laser.angle) * self.laser.length
 
     g.setColor(255, 0, 0)
-    g.setLineWidth(self.w / 5)
-    g.line(x, y - self.h / 2, x2, y2 - self.h / 2)
-    g.setLineWidth(1)
+    g.line(x, y, x2, y2)
   end
 
   self.animation:draw(x, y)
 end
 
+function Pigeon:move()
+  if not self.laser.active then
+    if self.animation.state.name ~= 'peck' then
+      if love.keyboard.isDown('left') then
+        self.x = self.x - self.speed * ls.tickrate
+        self.animation.flipped = true
+      elseif love.keyboard.isDown('right') then
+        self.x = self.x + self.speed * ls.tickrate
+        self.animation.flipped = false
+      end
+    end
+  end
+end
+
+function Pigeon:updateLaser()
+  self.laser.active = love.keyboard.isDown(' ')
+
+  if self.laser.active then
+    self.laser.tween = flux.to(self.laser, 1, {length = 1000}):ease('expoout')
+
+    if self.laser.length == 0 then
+      self.laser.angle = self.animation.flipped and math.pi or 0
+    else
+      local x1, y1 = self.x, self.y
+      local x2, y2 = self.x + math.cos(self.laser.angle) * self.laser.length, self.y + math.sin(self.laser.angle) * self.laser.length
+
+      ctx.world:rayCast(x1, y1, x2, y2, function(fixture)
+        local person = fixture:getBody():getUserData()
+        if person and not person.dead and person.die then
+          self:kill(person)
+          return 1
+        end
+        return -1
+      end)
+    end
+
+    local diff = self.laser.speed * ls.tickrate * lume.sign(math.pi / 2 - self.laser.angle)
+    if love.keyboard.isDown('up') then
+      self.laser.angle = self.laser.angle - diff
+    elseif love.keyboard.isDown('down') then
+      self.laser.angle = self.laser.angle + diff
+    end
+  else
+    if self.laser.tween then
+      self.laser.tween:stop()
+      self.laser.length = 0
+    end
+  end
+end
+
+function Pigeon:kill(person)
+  if person and not person.dead then
+    person:die()
+    self.health = math.min(self.health + 15, self.maxHealth)
+    flux.to(self.animation, .6, {scale = self.animation.scale + .02}):ease('elasticout')
+  end
+end
+
 -- Kill everything near the beak. Uses very dumb AABB checking but can be improved.
 function Pigeon:killThingsOnBeak()
   local spine = self.animation.spine
@@ -152,25 +152,26 @@ function Pigeon:killThingsOnBeak()
   for _, slotName in pairs({'beakbottom', 'beaktop'}) do
     local beakSlot = spine.skeleton:findSlot(slotName)
     local beakAttachment = spine.skeleton:getAttachment(beakSlot.data.name, beakSlot.data.name .. '_bb')
-    local polygon = spine.skeletonBounds:getPolygon(beakAttachment)
-
-    if polygon then
-      local x1, y1, x2, y2
-      for i = 1, #polygon, 2 do
-        x1 = math.min(x1 or math.huge, polygon[i])
-        x2 = math.max(x2 or -math.huge, polygon[i])
-        y1 = math.min(y1 or math.huge, polygon[i + 1])
-        y2 = math.max(y2 or -math.huge, polygon[i + 1])
-      end
-
-      ctx.world:queryBoundingBox(x1, y1, x2, y2, function(fixture)
-        local person = fixture:getBody():getUserData()
-        if person and person.die then
-          person:die()
-
-          return true
+    if beakAttachment then
+      local polygon = spine.skeletonBounds:getPolygon(beakAttachment)
+
+      if polygon then
+        local x1, y1, x2, y2
+        for i = 1, #polygon, 2 do
+          x1 = math.min(x1 or math.huge, polygon[i])
+          x2 = math.max(x2 or -math.huge, polygon[i])
+          y1 = math.min(y1 or math.huge, polygon[i + 1])
+          y2 = math.max(y2 or -math.huge, polygon[i + 1])
         end
-      end)
+
+        ctx.world:queryBoundingBox(x1, y1, x2, y2, function(fixture)
+          local person = fixture:getBody():getUserData()
+          if person and person.die then
+            self:kill(person)
+            return true
+          end
+        end)
+      end
     end
   end
 end

+ 13 - 0
projectile.lua

@@ -0,0 +1,13 @@
+Projectile = class()
+
+function Projectile:init()
+
+end
+
+function Projectile:update()
+
+end
+
+function Projectile:draw()
+
+end

+ 4 - 0
require.lua

@@ -8,6 +8,7 @@ require 'deps/util'
 require 'deps/animation'
 require 'deps/event'
 require 'deps/view'
+require 'deps/manager'
 
 require 'context'
 require 'game'
@@ -15,6 +16,9 @@ require 'person'
 require 'building'
 require 'pigeon'
 require 'map'
+require 'goal'
+require 'projectile'
+require 'rock'
 
 require 'hud'
 

+ 39 - 0
rock.lua

@@ -0,0 +1,39 @@
+Rock = class()
+
+Rock.category = 5
+
+function Rock:init(x, y)
+  self.body = love.physics.newBody(ctx.world, x, y, 'dynamic')
+  self.shape = love.physics.newCircleShape(10)
+  self.fixture = love.physics.newFixture(self.body, self.shape)
+
+  self.body:setUserData(self)
+
+  self.fixture:setCategory(self.category)
+  self.fixture:setMask(self.category, Building.category, Person.category)
+  self.fixture:setGroupIndex(1)
+
+  self.body:setMass(10)
+  self.body:applyLinearImpulse(-2000, -5000)
+  self.body:setFixedRotation(true)
+  self.fixture:setFriction(.35)
+
+  lume.push(ctx.projectiles, self)
+
+  ctx.event:emit('view.register', {object = self})
+end
+
+function Rock:update()
+  local x, y = self.body:getLinearVelocity()
+  if (math.abs(x) < 1 and math.abs(y) < 1) or (math.abs(x) > 5000 and math.abs(y) > 5000) then
+    lume.remove(ctx.projectiles, self)
+    self.body:destroy()
+    ctx.event:emit('view.unregister', {object = self})
+  end
+end
+
+function Rock:draw()
+  local g = love.graphics
+  g.setColor(128, 128, 128)
+  g.circle('fill', self.body:getX(), self.body:getY(), 10)
+end