Basic movement and firing
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Mar 2019 00:27:51 +0000 (18:27 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Mar 2019 00:27:51 +0000 (18:27 -0600)
conf.lua
main.lua
src/input.lua [new file with mode: 0644]
src/utils.lua [new file with mode: 0644]
src/world.lua [new file with mode: 0644]

index 28efd8bd69a4340e44480ddc7c27cd6527525ef6..d29aeaac06ac499e0b666b1fff13464d4e1bf04c 100644 (file)
--- a/conf.lua
+++ b/conf.lua
@@ -26,3 +26,28 @@ function love.conf(t)
     t.modules.video = false
     t.modules.window = true
 end
+
+local KEYMAP = {
+       MOVE_UP    = "w";
+       MOVE_DOWN  = "s";
+       MOVE_LEFT  = "a";
+       MOVE_RIGHT = "d";
+       FIRE_UP    = "up";
+       FIRE_DOWN  = "down";
+       FIRE_LEFT  = "left";
+       FIRE_RIGHT = "right";
+}
+
+local BACK_COLOR = { 0.8, 0.8, 0.8 }
+local PLAYER_COLOR = { 0.3, 0.3, 0.7 }
+local ENEMY_COLOR = { 1, 0, 0 }
+local BULLET_COLOR = { 0.6, 0.6, 1.0 }
+
+return {
+       KEYS = KEYMAP;
+
+       BACK_COLOR = BACK_COLOR;
+       PLAYER_COLOR = PLAYER_COLOR;
+       ENEMY_COLOR = ENEMY_COLOR;
+       BULLET_COLOR = BULLET_COLOR;
+}
index 6d9cf5d228ca358b78f1d0d6237fcd6048123241..156915decbb8b0c2dbe05c27885fc38dc3d3fb21 100644 (file)
--- a/main.lua
+++ b/main.lua
@@ -1,13 +1,36 @@
+local CONF = require "conf"
 
+local world_mod = require "src.world"
+local Input = require "src.input"
 
+local World = world_mod.World
+
+local world, player
+local input
 function love.load()
+       world, player = World:new()
+
+       input = Input:new()
+
+       love.graphics.setBackgroundColor(CONF.BACK_COLOR)
+end
 
+function love.keypressed(key)
+       input:keydown(key)      
 end
 
-function love.update()
+function love.keyreleased(key)
+       input:keyup(key)
+end
 
+function love.update(dt)
+       if love.keyboard.isDown "escape" then
+               love.event.quit()
+       end
+       
+       world:update(dt, input)
 end
 
 function love.draw()
-
+       world:draw()
 end
diff --git a/src/input.lua b/src/input.lua
new file mode 100644 (file)
index 0000000..9002297
--- /dev/null
@@ -0,0 +1,50 @@
+local CONF = require "conf"
+local KEYS = CONF.KEYS
+
+-- INPUT --
+
+local Input = {}
+function Input:new()
+       local o = {
+               move_up    = false;
+               move_down  = false;
+               move_left  = false;
+               move_right = false;
+               fire_up    = false;
+               fire_down  = false;
+               fire_left  = false;
+               fire_right = false;
+       }
+
+       local mt = { __index = Input }
+       setmetatable(o, mt)
+
+       return o
+end
+
+-- Ugly way of righting it but I don't care (right now at least... :P)
+function Input:keydown(key)
+       if     key == KEYS.MOVE_UP    then self.move_up    = true 
+       elseif key == KEYS.MOVE_DOWN  then self.move_down  = true
+       elseif key == KEYS.MOVE_LEFT  then self.move_left  = true
+       elseif key == KEYS.MOVE_RIGHT then self.move_right = true
+       elseif key == KEYS.FIRE_UP    then self.fire_up    = true
+       elseif key == KEYS.FIRE_DOWN  then self.fire_down  = true
+       elseif key == KEYS.FIRE_LEFT  then self.fire_left  = true
+       elseif key == KEYS.FIRE_RIGHT then self.fire_right = true
+       end
+end
+
+function Input:keyup(key)
+       if     key == KEYS.MOVE_UP    then self.move_up    = false 
+       elseif key == KEYS.MOVE_DOWN  then self.move_down  = false
+       elseif key == KEYS.MOVE_LEFT  then self.move_left  = false
+       elseif key == KEYS.MOVE_RIGHT then self.move_right = false
+       elseif key == KEYS.FIRE_UP    then self.fire_up    = false
+       elseif key == KEYS.FIRE_DOWN  then self.fire_down  = false
+       elseif key == KEYS.FIRE_LEFT  then self.fire_left  = false
+       elseif key == KEYS.FIRE_RIGHT then self.fire_right = false
+       end
+end
+
+return Input
diff --git a/src/utils.lua b/src/utils.lua
new file mode 100644 (file)
index 0000000..d98d304
--- /dev/null
@@ -0,0 +1,25 @@
+function math.lerp(a, b, t)
+       return a + (b - a) * t
+end
+
+function math.sqrDist(x1, y1, x2, y2)
+       return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)
+end
+
+function math.genuuid()
+       return ("xxxxxxxx-xxxx-4yxx-xxxxxxxx"):gsub('[xy]', function (c)
+        local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
+        return string.format('%x', v)
+    end)
+end
+
+local function ripairsiter(t, i)
+       i = i - 1
+       if i ~= 0 then
+               return i, t[i]
+       end
+end
+
+function reversedipairs(t)
+       return ripairsiter, t, #t + 1
+end
diff --git a/src/world.lua b/src/world.lua
new file mode 100644 (file)
index 0000000..811dbe5
--- /dev/null
@@ -0,0 +1,197 @@
+require "src.utils"
+
+local CONF = require "conf"
+
+-- BULLET --
+
+local Bullet = {}
+local Bullet_mt = { __index = Bullet }
+function Bullet:new(x, y, vx, vy)
+       local o = {
+               x = x;
+               y = y;
+               vx = vx;
+               vy = vy;
+               life = 100;
+               alive = true;
+       }
+       
+       setmetatable(o, Bullet_mt)
+       return o
+end
+
+function Bullet:update(dt)
+       self.x = self.x + self.vx * dt
+       self.y = self.y + self.vy * dt
+
+       self.life = self.life - 1
+       if self.life <= 0 then
+               self.alive = false
+       end
+end
+
+function Bullet:draw()
+       local R = 8
+       local cx = self.x
+       local cy = self.y
+       local vx = self.vx
+       local vy = self.vy
+
+       local a
+       if vx == 0 and vy == 0 then
+               a = 0
+       else
+               a = math.atan2(vy, vx)
+       end
+
+       local sin = math.sin
+       local cos = math.cos
+       local pi = math.pi
+
+       local pnts = {
+               cx + R * cos(a + 0 * pi / 3), cy + R * sin(a + 0 * pi / 3),
+               cx + R * cos(a + 2 * pi / 3), cy + R * sin(a + 2 * pi / 3),
+               cx + R * cos(a + 4 * pi / 3), cy + R * sin(a + 4 * pi / 3)
+       }
+
+       love.graphics.setColor(CONF.BULLET_COLOR)
+       love.graphics.polygon("fill", pnts)
+end
+
+-- PLAYER --
+
+local Player = {}
+local Player_mt = { __index = Player }
+function Player:new()
+       local o = {
+               x = 0;
+               y = 0;
+               r = 16;
+               fire_cooldown = 0;
+       }
+       
+       setmetatable(o, Player_mt)
+       return o
+end
+
+function Player:update(dt, world, input)
+       local dx = 0
+       local dy = 0
+
+       local SPEED = 150
+
+       if input.move_up    then dy = dy - SPEED end
+       if input.move_down  then dy = dy + SPEED end
+       if input.move_left  then dx = dx - SPEED end
+       if input.move_right then dx = dx + SPEED end
+
+       self.x = self.x + dx * dt
+       self.y = self.y + dy * dt
+
+       if self.fire_cooldown <= 0 then
+               self.fire_cooldown = 10
+               local firex = 0
+               local firey = 0
+
+               local FIRE_SPEED = 300
+               
+               if input.fire_up    then firey = firey - 1 end
+               if input.fire_down  then firey = firey + 1 end
+               if input.fire_left  then firex = firex - 1 end
+               if input.fire_right then firex = firex + 1 end
+
+               if firex ~= 0 or firey ~= 0 then
+                       local d = math.sqrt(math.sqrDist(0, 0, firex, firey))
+                       firex = FIRE_SPEED * firex / d
+                       firey = FIRE_SPEED * firey / d
+
+                       self:fire(firex, firey, world)
+               end
+       else
+               self.fire_cooldown = self.fire_cooldown - 1
+       end
+end
+
+function Player:fire(vx, vy, world)
+       local bullet = Bullet:new(self.x, self.y, vx, vy)
+       world:add_entity(bullet)        
+end
+
+function Player:draw()
+       love.graphics.setColor(CONF.PLAYER_COLOR)
+       love.graphics.circle("fill", self.x, self.y, self.r)
+end
+
+-- WORLD --
+
+local World = {}
+local World_mt = { __index = World }
+function World:new(player)
+       if player == nil then
+               player = Player:new()
+       end
+
+       local o = {
+               --[[
+               Entities are expected to have the following prototype:
+                       (string) id
+                       (boolean) alive
+                       (function(dt, world)) update
+                       (function) draw
+               --]]
+               entities = {};
+
+               player = player;
+       }
+
+       setmetatable(o, World_mt)
+
+       --Return both world and player in case we made the player in the constructor
+       return o, player
+end
+
+function World:update(dt, input)
+       for _, e in ipairs(self.entities) do
+               e:update(dt, self)
+       end
+
+       self.player:update(dt, self, input)
+end
+
+function World:add_entity(ent)
+       local id = math.genuuid()
+       ent.id = id
+
+       table.insert(self.entities, ent)
+end
+
+function World:remove_entity(ent_or_id)
+       local id = ent_or_id
+       if type(id) == "table" then
+               id = id.id
+       end
+
+       local pos = 0
+       for p, e in ipairs(self.entities) do
+               if e.id == id then
+                       pos = p
+                       break
+               end
+       end
+       
+       table.remove(self.entities, pos)
+end
+
+function World:draw()
+       for _, e in ipairs(self.entities) do
+               e:draw()
+       end
+
+       self.player:draw()
+end
+
+return {
+       World = World;
+       Player = Player;
+       Bullet = Bullet;
+}