From: Brendan Hansen Date: Sun, 10 Mar 2019 00:27:51 +0000 (-0600) Subject: Basic movement and firing X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=9f262321a0dfb2ac230554245634f40c87515458;p=genetic-shooter.git Basic movement and firing --- diff --git a/conf.lua b/conf.lua index 28efd8b..d29aeaa 100644 --- 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; +} diff --git a/main.lua b/main.lua index 6d9cf5d..156915d 100644 --- 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 index 0000000..9002297 --- /dev/null +++ b/src/input.lua @@ -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 index 0000000..d98d304 --- /dev/null +++ b/src/utils.lua @@ -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 index 0000000..811dbe5 --- /dev/null +++ b/src/world.lua @@ -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; +}