decompose bouncing into "mods"
This commit is contained in:
parent
e2134d76bd
commit
a709e4f1c4
@ -1,6 +1,6 @@
|
|||||||
local map = vim.api.nvim_set_keymap
|
local map = vim.api.nvim_set_keymap
|
||||||
|
|
||||||
map('n', '<leader>l', ":execute 'silent !kitty -d src love . &' | redraw!<cr>", {
|
map('n', '<leader><leader>l', ":execute 'silent !kitty -d src love . &' | redraw!<cr>", {
|
||||||
silent = true,
|
silent = true,
|
||||||
noremap = true
|
noremap = true
|
||||||
})
|
})
|
||||||
|
9
src/bolt-mods/bouncy.lua
Normal file
9
src/bolt-mods/bouncy.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
local BouncyMod = {}
|
||||||
|
|
||||||
|
BouncyMod.dont_die_on_touch_obstacle = true
|
||||||
|
|
||||||
|
function BouncyMod.on_shoot(bolt)
|
||||||
|
bolt.collider:setRestitution(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return BouncyMod
|
19
src/bolt-mods/init.lua
Normal file
19
src/bolt-mods/init.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
local mods = {
|
||||||
|
bouncy = require(... .. ".bouncy"),
|
||||||
|
speed_bounce = require(... .. ".speed-bounce"),
|
||||||
|
retain_speed = require(... .. ".retain-speed")
|
||||||
|
}
|
||||||
|
|
||||||
|
local order = {
|
||||||
|
mods.bouncy,
|
||||||
|
mods.speed_bounce,
|
||||||
|
mods.retain_speed
|
||||||
|
}
|
||||||
|
|
||||||
|
local priority = {}
|
||||||
|
for i, mod in ipairs(order) do
|
||||||
|
priority[mod] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
return { mods = mods, priority = priority }
|
26
src/bolt-mods/retain-speed.lua
Normal file
26
src/bolt-mods/retain-speed.lua
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
local RetainSpeedMod = {}
|
||||||
|
|
||||||
|
local MIN_LIFETIME = 0.1
|
||||||
|
|
||||||
|
function RetainSpeedMod.on_shoot(bolt, player)
|
||||||
|
local attr = bolt.attributes
|
||||||
|
if not attr.max_vel then return end
|
||||||
|
|
||||||
|
local velx, vely = bolt.collider:getLinearVelocity()
|
||||||
|
local old_velocity = (velx^2 + vely^2)^0.5
|
||||||
|
local new_velocity = attr.max_vel
|
||||||
|
bolt.max_lifetime = math.max(bolt.max_lifetime / (new_velocity / old_velocity)^2, MIN_LIFETIME)
|
||||||
|
|
||||||
|
local aim_dir = player:get_aim_dir()
|
||||||
|
bolt.collider:setLinearVelocity(aim_dir.x * new_velocity, aim_dir.y * new_velocity)
|
||||||
|
end
|
||||||
|
|
||||||
|
function RetainSpeedMod.on_update(bolt)
|
||||||
|
if bolt.dead then return end
|
||||||
|
local attr = bolt.attributes
|
||||||
|
|
||||||
|
local velx, vely = bolt.collider:getLinearVelocity()
|
||||||
|
attr.max_vel = math.max(attr.max_vel or 0, (velx^2 + vely^2)^0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
return RetainSpeedMod
|
10
src/bolt-mods/speed-bounce.lua
Normal file
10
src/bolt-mods/speed-bounce.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
local SpeedBounceMod = {}
|
||||||
|
|
||||||
|
local SPEEDUP_AMOUNT = 0.2
|
||||||
|
|
||||||
|
function SpeedBounceMod.on_shoot(bolt)
|
||||||
|
bolt.max_lifetime = bolt.max_lifetime / 2
|
||||||
|
bolt.collider:setRestitution(1 + SPEEDUP_AMOUNT)
|
||||||
|
end
|
||||||
|
|
||||||
|
return SpeedBounceMod
|
@ -3,7 +3,7 @@ local Vec = require("lib.brinevector")
|
|||||||
local Player = {}
|
local Player = {}
|
||||||
Player.__index = Player
|
Player.__index = Player
|
||||||
|
|
||||||
local SHOOT_COOLDOWN = 1
|
Player.MAX_HEALTH = 3
|
||||||
|
|
||||||
function Player:new(controls, collision_world, pos)
|
function Player:new(controls, collision_world, pos)
|
||||||
local player = setmetatable({}, Player)
|
local player = setmetatable({}, Player)
|
||||||
@ -11,13 +11,17 @@ function Player:new(controls, collision_world, pos)
|
|||||||
player.vel = Vec()
|
player.vel = Vec()
|
||||||
player.controls = controls
|
player.controls = controls
|
||||||
player.collider = collision_world:newCollider("Circle", { pos.x, pos.y, PLAYER_SIZE })
|
player.collider = collision_world:newCollider("Circle", { pos.x, pos.y, PLAYER_SIZE })
|
||||||
player.pickedup_bolt_speeds = {}
|
player.pickedup_bolt_speed = nil
|
||||||
player.shoot_cooldown = nil
|
player.shoot_cooldown = nil
|
||||||
player.health = 3
|
player.health = Player.MAX_HEALTH
|
||||||
|
player.has_bolt = true
|
||||||
|
player.bolt_mods = {}
|
||||||
|
|
||||||
if controls == "joystick" then
|
if controls == "joystick" then
|
||||||
local joysticks = love.joystick.getJoysticks()
|
local joysticks = love.joystick.getJoysticks()
|
||||||
assert(joysticks[1], "no joystick connected")
|
if not joysticks[1] then
|
||||||
|
print("no joystick connected")
|
||||||
|
end
|
||||||
player.joystick = joysticks[1]
|
player.joystick = joysticks[1]
|
||||||
end
|
end
|
||||||
return player
|
return player
|
||||||
@ -36,7 +40,7 @@ function Player:get_move_dir()
|
|||||||
local dirx = getDirectionKey("d", "a")
|
local dirx = getDirectionKey("d", "a")
|
||||||
local diry = getDirectionKey("s", "w")
|
local diry = getDirectionKey("s", "w")
|
||||||
return Vec(dirx, diry).normalized
|
return Vec(dirx, diry).normalized
|
||||||
elseif self.controls == "joystick" then
|
elseif self.controls == "joystick" and self.joystick then
|
||||||
local dirx = self.joystick:getGamepadAxis("leftx")
|
local dirx = self.joystick:getGamepadAxis("leftx")
|
||||||
local diry = self.joystick:getGamepadAxis("lefty")
|
local diry = self.joystick:getGamepadAxis("lefty")
|
||||||
local size = dirx^2 + diry^2
|
local size = dirx^2 + diry^2
|
||||||
@ -53,7 +57,7 @@ end
|
|||||||
function Player:get_aim_dir()
|
function Player:get_aim_dir()
|
||||||
if self.controls == "keyboard" then
|
if self.controls == "keyboard" then
|
||||||
return (Vec(love.mouse.getPosition()) - self.pos).normalized
|
return (Vec(love.mouse.getPosition()) - self.pos).normalized
|
||||||
elseif self.controls == "joystick" then
|
elseif self.controls == "joystick" and self.joystick then
|
||||||
local dirx = self.joystick:getGamepadAxis("rightx")
|
local dirx = self.joystick:getGamepadAxis("rightx")
|
||||||
local diry = self.joystick:getGamepadAxis("righty")
|
local diry = self.joystick:getGamepadAxis("righty")
|
||||||
local dir = Vec(dirx, diry).normalized
|
local dir = Vec(dirx, diry).normalized
|
||||||
@ -68,23 +72,11 @@ function Player:get_aim_dir()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Player:process_shoot()
|
function Player:pressed_shoot()
|
||||||
if not self.on_shoot then return end
|
|
||||||
local now = love.timer.getTime()
|
|
||||||
if self.last_shot_time then
|
|
||||||
if now - self.last_shot_time < SHOOT_COOLDOWN then return end
|
|
||||||
end
|
|
||||||
|
|
||||||
local shoot = false
|
|
||||||
if self.controls == "keyboard" then
|
if self.controls == "keyboard" then
|
||||||
shoot = love.keyboard.isDown("space")
|
return love.keyboard.isDown("space")
|
||||||
elseif self.controls == "joystick" then
|
elseif self.controls == "joystick" and self.joystick then
|
||||||
shoot = self.joystick:isGamepadDown("leftshoulder")
|
return self.joystick:isGamepadDown("leftshoulder")
|
||||||
end
|
|
||||||
|
|
||||||
if shoot then
|
|
||||||
self:on_shoot()
|
|
||||||
self.last_shot_time = now
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,36 +2,33 @@ local MainState = {}
|
|||||||
local Player = require("player")
|
local Player = require("player")
|
||||||
local Vec = require("lib.brinevector")
|
local Vec = require("lib.brinevector")
|
||||||
local bf = require("lib.breezefield")
|
local bf = require("lib.breezefield")
|
||||||
|
local rgb = require("helpers.rgb")
|
||||||
|
local lerp = require("lib.lume").lerp
|
||||||
|
local BoltMods = require("bolt-mods")
|
||||||
|
|
||||||
local BOLT_DIST_FROM_PLAYER = 40
|
local BOLT_DIST_FROM_PLAYER = 40
|
||||||
local BOLT_SIZE = 8
|
local BOLT_SIZE = 4
|
||||||
|
|
||||||
local DRAW_COLLIDERS = false
|
local DRAW_COLLIDERS = false
|
||||||
local BOLT_DURATION = 2.5
|
local BOLT_DURATION = 2.5
|
||||||
|
|
||||||
local PLAYER1_MASK = 2
|
local SHOOT_COOLDOWN = 1
|
||||||
local PLAYER2_MASK = 3
|
|
||||||
|
local FULL_HEALTH_COLOR = rgb(20, 200, 20)
|
||||||
|
local EMPTY_HEALTH_COLOR = rgb(180, 20, 20)
|
||||||
|
|
||||||
|
local ACTIVE_BOLT_COLOR = rgb(240, 20, 20)
|
||||||
|
local INACTIVE_BOLT_COLOR = rgb(200, 100, 100)
|
||||||
|
|
||||||
function MainState:enter()
|
function MainState:enter()
|
||||||
|
love.graphics.setNewFont(72)
|
||||||
love.mouse.setVisible(false)
|
love.mouse.setVisible(false)
|
||||||
|
|
||||||
self.world = bf.newWorld(0, 0, true)
|
self.world = bf.newWorld(0, 0, true)
|
||||||
self.world:setCallbacks(function(...) self:on_begin_contact(...) end)
|
self.world:setCallbacks(function(...) self:on_begin_contact(...) end)
|
||||||
|
|
||||||
local winw, winh = love.graphics.getDimensions()
|
self.players = {}
|
||||||
self.player_1 = Player:new("keyboard", self.world, Vec(50, 200))
|
self.bolts = {}
|
||||||
self.player_2 = Player:new("joystick", self.world, Vec(winw-50, 200))
|
|
||||||
|
|
||||||
self.player_1.collider.fixture:setCategory(PLAYER1_MASK)
|
|
||||||
self.player_2.collider.fixture:setCategory(PLAYER2_MASK)
|
|
||||||
|
|
||||||
self.players = { self.player_1, self.player_2 }
|
|
||||||
|
|
||||||
local on_shoot = function(...) self:on_player_shoot(...) end
|
|
||||||
for _, player in ipairs(self.players) do
|
|
||||||
player.on_shoot = on_shoot
|
|
||||||
player.collider.fixture:setUserData("player")
|
|
||||||
end
|
|
||||||
|
|
||||||
self.obstacles = {}
|
self.obstacles = {}
|
||||||
table.insert(self.obstacles, {{90, 90}, {100, 200}, {300, 300}, {200, 100}})
|
table.insert(self.obstacles, {{90, 90}, {100, 200}, {300, 300}, {200, 100}})
|
||||||
@ -52,23 +49,76 @@ function MainState:enter()
|
|||||||
end
|
end
|
||||||
local collider = self.world:newCollider("Polygon", points)
|
local collider = self.world:newCollider("Polygon", points)
|
||||||
collider:setType("static")
|
collider:setType("static")
|
||||||
|
collider.fixture:setUserData("obstacle")
|
||||||
table.insert(self.obstacle_colliders, collider)
|
table.insert(self.obstacle_colliders, collider)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
self.world:newCollider("Edge", { 0, 0, winw, 0 }):setType("static") -- top
|
local winw, winh = love.graphics.getDimensions()
|
||||||
self.world:newCollider("Edge", { 0, 0, 0, winh }):setType("static") -- left
|
local edges = {
|
||||||
self.world:newCollider("Edge", { winw, 0, winw, winh }):setType("static") -- right
|
{ 0, 0, winw, 0 }, -- top
|
||||||
self.world:newCollider("Edge", { 0, winh, winw, winh }):setType("static") -- bottom
|
{ 0, 0, 0, winh }, -- left
|
||||||
|
{ winw, 0, winw, winh }, -- right
|
||||||
|
{ 0, winh, winw, winh } -- bottom
|
||||||
|
}
|
||||||
|
for _, edge in ipairs(edges) do
|
||||||
|
local collider = self.world:newCollider("Edge", edge)
|
||||||
|
collider.fixture:setUserData("obstacle")
|
||||||
|
collider:setType("static")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.bolts = {}
|
self:start_match()
|
||||||
self.bolt_colliders = {}
|
end
|
||||||
|
|
||||||
|
function MainState:stop_match()
|
||||||
|
for _, bolt in ipairs(self.bolts) do
|
||||||
|
self:destroy_bolt(bolt)
|
||||||
|
end
|
||||||
|
for _, player in ipairs(self.players) do
|
||||||
|
self:destroy_player(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainState:start_match()
|
||||||
|
self:stop_match()
|
||||||
|
|
||||||
|
local winw, winh = love.graphics.getDimensions()
|
||||||
|
self:create_player("keyboard", Vec(50, 200))
|
||||||
|
-- self:create_player("joystick", Vec(winw-50, 200))
|
||||||
|
self:create_player("joystick", Vec(50, 300))
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:update(dt)
|
function MainState:update(dt)
|
||||||
|
local now = love.timer.getTime()
|
||||||
|
for _, bolt in ipairs(self.bolts) do
|
||||||
|
for _, mod in ipairs(bolt.shot_by.bolt_mods) do
|
||||||
|
if mod.on_update then
|
||||||
|
mod.on_update(bolt, dt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local lifetime = now - bolt.created_at
|
||||||
|
if lifetime > bolt.max_lifetime then
|
||||||
|
bolt.dead = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if bolt.dead then
|
||||||
|
local dampening = 0.75
|
||||||
|
local velx, vely = bolt.collider:getLinearVelocity()
|
||||||
|
bolt.collider:setLinearVelocity(velx * dampening, vely * dampening)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
for _, player in ipairs(self.players) do
|
for _, player in ipairs(self.players) do
|
||||||
player:process_shoot()
|
if player.has_bolt and player:pressed_shoot() then
|
||||||
|
player.last_shot_time = player.last_shot_time or 0
|
||||||
|
if now - player.last_shot_time > SHOOT_COOLDOWN then
|
||||||
|
self:on_player_shoot(player)
|
||||||
|
player.last_shot_time = now
|
||||||
|
player.has_bolt = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local move_dir = player:get_move_dir()
|
local move_dir = player:get_move_dir()
|
||||||
local acc = move_dir * 300
|
local acc = move_dir * 300
|
||||||
@ -76,52 +126,89 @@ function MainState:update(dt)
|
|||||||
player.vel = player.vel * 0.98
|
player.vel = player.vel * 0.98
|
||||||
player.collider:setLinearVelocity(player.vel.x, player.vel.y)
|
player.collider:setLinearVelocity(player.vel.x, player.vel.y)
|
||||||
|
|
||||||
local now = love.timer.getTime()
|
if not player.has_bolt then
|
||||||
for i, bolt in ipairs(self.bolts) do
|
for _, bolt in ipairs(self.bolts) do
|
||||||
local collider = self.bolt_colliders[i]
|
|
||||||
local lifetime = now - bolt.created_at
|
|
||||||
local velx, vely = collider:getLinearVelocity()
|
|
||||||
if not bolt.dead then
|
|
||||||
bolt.max_vel = math.max(bolt.max_vel, (velx^2 + vely^2)^0.5)
|
|
||||||
end
|
|
||||||
if lifetime > BOLT_DURATION then
|
|
||||||
bolt.dead = true
|
|
||||||
local dampening = 0.9
|
|
||||||
collider:setLinearVelocity(velx * dampening, vely * dampening)
|
|
||||||
end
|
|
||||||
|
|
||||||
if bolt.dead then
|
if bolt.dead then
|
||||||
local distance = (bolt.pos - player.pos).length
|
local distance = (bolt.pos - player.pos).length
|
||||||
if distance < BOLT_DIST_FROM_PLAYER then
|
if distance < BOLT_DIST_FROM_PLAYER then
|
||||||
table.insert(player.pickedup_bolt_speeds, bolt.max_vel)
|
player.pickup_bolt_attributes = bolt.attributes
|
||||||
self:destroy_bolt(i)
|
player.has_bolt = true
|
||||||
|
self:destroy_bolt(bolt)
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local was_dead = player.dead
|
||||||
|
if player.health <= 0 then
|
||||||
|
player.dead = true
|
||||||
|
end
|
||||||
|
if not was_dead and player.dead then
|
||||||
|
self:destroy_player(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #self.players > 1 then
|
||||||
self.world:update(dt)
|
self.world:update(dt)
|
||||||
|
|
||||||
for i, bolt in ipairs(self.bolts) do
|
for _, bolt in ipairs(self.bolts) do
|
||||||
local collider = self.bolt_colliders[i]
|
bolt.pos.x = bolt.collider:getX()
|
||||||
bolt.pos.x = collider:getX()
|
bolt.pos.y = bolt.collider:getY()
|
||||||
bolt.pos.y = collider:getY()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, player in ipairs(self.players) do
|
for _, player in ipairs(self.players) do
|
||||||
player.pos.x = player.collider:getX()
|
player.pos.x = player.collider:getX()
|
||||||
player.pos.y = player.collider:getY()
|
player.pos.y = player.collider:getY()
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
self.victory_timer = (self.victory_timer or 0) + dt
|
||||||
|
if self.victory_timer > 1 then
|
||||||
|
self.victory_timer = nil
|
||||||
|
self:start_match()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if love.keyboard.isDown("escape") then
|
if love.keyboard.isDown("escape") then
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:destroy_bolt(idx)
|
local function sort_bolt_mods(bolt_mods)
|
||||||
local collider = table.remove(self.bolt_colliders, idx)
|
table.sort(bolt_mods, function(a, b)
|
||||||
table.remove(self.bolts, idx)
|
return BoltMods.priority[a] < BoltMods.priority[b]
|
||||||
self.world:removeCollider(collider)
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainState:create_player(controls, pos)
|
||||||
|
local player = Player:new(controls, self.world, pos)
|
||||||
|
player.bolt_mods = {
|
||||||
|
BoltMods.mods.speed_bounce,
|
||||||
|
BoltMods.mods.bouncy,
|
||||||
|
BoltMods.mods.retain_speed,
|
||||||
|
}
|
||||||
|
sort_bolt_mods(player.bolt_mods)
|
||||||
|
player.collider.fixture:setUserData("player")
|
||||||
|
table.insert(self.players, player)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function remove_by_value(array, value)
|
||||||
|
for i, v in ipairs(array) do
|
||||||
|
if v == value then
|
||||||
|
table.remove(array, i)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainState:destroy_player(player)
|
||||||
|
remove_by_value(self.players, player)
|
||||||
|
self.world:removeCollider(player.collider)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainState:destroy_bolt(bolt)
|
||||||
|
remove_by_value(self.bolts, bolt)
|
||||||
|
self.world:removeCollider(bolt.collider)
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:on_player_shoot(player)
|
function MainState:on_player_shoot(player)
|
||||||
@ -129,111 +216,112 @@ function MainState:on_player_shoot(player)
|
|||||||
local bolt = {
|
local bolt = {
|
||||||
pos = player.pos + aim_dir * BOLT_DIST_FROM_PLAYER,
|
pos = player.pos + aim_dir * BOLT_DIST_FROM_PLAYER,
|
||||||
created_at = love.timer.getTime(),
|
created_at = love.timer.getTime(),
|
||||||
max_vel = 0
|
shot_by = player,
|
||||||
|
max_lifetime = BOLT_DURATION,
|
||||||
|
attributes = player.pickup_bolt_attributes or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
local velocity = 500
|
local DEFAULT_VELOCITY = 500
|
||||||
local pickup_idx = -1
|
bolt.collider = self.world:newCollider("Circle", { bolt.pos.x, bolt.pos.y, BOLT_SIZE })
|
||||||
for i, vel in ipairs(player.pickedup_bolt_speeds) do
|
bolt.collider:setLinearVelocity(aim_dir.x * DEFAULT_VELOCITY, aim_dir.y * DEFAULT_VELOCITY)
|
||||||
if vel > velocity then
|
bolt.collider:setRestitution(0.1)
|
||||||
velocity = vel
|
bolt.collider.fixture:setUserData("bolt")
|
||||||
pickup_idx = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if pickup_idx ~= -1 then
|
|
||||||
table.remove(player.pickedup_bolt_speeds, pickup_idx)
|
|
||||||
end
|
|
||||||
|
|
||||||
local collider = self.world:newCollider("Circle", { bolt.pos.x, bolt.pos.y, BOLT_SIZE })
|
for _, mod in ipairs(player.bolt_mods) do
|
||||||
collider:setLinearVelocity(aim_dir.x * velocity, aim_dir.y * velocity)
|
if mod.on_shoot then
|
||||||
-- collider:applyLinearImpulse(aim_dir.x * launch_force, aim_dir.y * launch_force)
|
mod.on_shoot(bolt, player)
|
||||||
collider.fixture:setUserData("bolt")
|
end
|
||||||
collider:setRestitution(1.2)
|
|
||||||
|
|
||||||
if player == self.player_1 then
|
|
||||||
collider:setMask(PLAYER1_MASK)
|
|
||||||
else
|
|
||||||
collider:setMask(PLAYER2_MASK)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(self.bolts, bolt)
|
table.insert(self.bolts, bolt)
|
||||||
table.insert(self.bolt_colliders, collider)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:get_bolt_by_collider(collider)
|
function MainState:get_bolt_by_collider(collider)
|
||||||
for i, other_collider in ipairs(self.bolt_colliders) do
|
for _, bolt in ipairs(self.bolts) do
|
||||||
if other_collider == collider then
|
if bolt.collider.fixture == collider then
|
||||||
return i
|
return bolt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:get_player_by_collider(collider)
|
function MainState:get_player_by_collider(collider)
|
||||||
if self.player_1.collider.fixture == collider then
|
for _, player in ipairs(self.players) do
|
||||||
return self.player_1
|
if player.collider.fixture == collider then
|
||||||
elseif self.player_2.collider.fixture == collider then
|
return player
|
||||||
return self.player_2
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:on_player_touch_bolt(player, bolt_idx)
|
function MainState:on_player_touch_bolt(player, bolt)
|
||||||
|
bolt.shot_by.has_bolt = true
|
||||||
|
|
||||||
player.health = player.health - 1
|
player.health = player.health - 1
|
||||||
self:destroy_bolt(bolt_idx)
|
self:destroy_bolt(bolt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MainState:on_bolt_touch_obstacle(bolt)
|
||||||
|
local should_die = true
|
||||||
|
local player = bolt.shot_by
|
||||||
|
for _, mod in ipairs(player.bolt_mods) do
|
||||||
|
if mod.on_touch_obstacle then
|
||||||
|
mod.on_touch_obstacle(bolt, player)
|
||||||
|
end
|
||||||
|
if mod.dont_die_on_touch_obstacle then
|
||||||
|
should_die = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if should_die then
|
||||||
|
bolt.dead = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:on_begin_contact(a, b)
|
function MainState:on_begin_contact(a, b)
|
||||||
local a_data = a:getUserData()
|
local a_data = a:getUserData()
|
||||||
local b_data = b:getUserData()
|
local b_data = b:getUserData()
|
||||||
|
|
||||||
if a_data == "player" and b_data == "bolt" then
|
if a_data == "player" and b_data == "bolt" then
|
||||||
self:on_player_touch_bolt(self:get_player_by_collider(a), self:get_bolt_by_collider(b))
|
self:on_player_touch_bolt(self:get_player_by_collider(a), self:get_bolt_by_collider(b))
|
||||||
elseif a_data == "bolt" and b_data == "player" then
|
elseif a_data == "bolt" and b_data == "player" then
|
||||||
self:on_player_touch_bolt(self:get_bolt_by_collider(a), self:get_player_by_collider(b))
|
self:on_player_touch_bolt(self:get_bolt_by_collider(a), self:get_player_by_collider(b))
|
||||||
|
|
||||||
|
elseif a_data == "bolt" and b_data == "obstacle" then
|
||||||
|
self:on_bolt_touch_obstacle(self:get_bolt_by_collider(a))
|
||||||
|
elseif a_data == "obstacle" and b_data == "bolt" then
|
||||||
|
self:on_bolt_touch_obstacle(self:get_bolt_by_collider(b))
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:draw_health(x, y, player, align)
|
local function lerp_color(a, b, t)
|
||||||
local max_health = 3
|
return lerp(a[1], b[1], t), lerp(a[2], b[2], t), lerp(a[3], b[3], t)
|
||||||
local rect_width = 20
|
|
||||||
local rect_height = 25
|
|
||||||
local gap = 10
|
|
||||||
local padding = 10
|
|
||||||
|
|
||||||
local health_bar_width = max_health * (rect_width + gap) - gap + 2*padding
|
|
||||||
if align == "right" then
|
|
||||||
x = x - health_bar_width
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setColor(0.1, 0.1, 0.1)
|
|
||||||
love.graphics.rectangle("fill",
|
|
||||||
x, y,
|
|
||||||
health_bar_width,
|
|
||||||
rect_height + 2*padding
|
|
||||||
)
|
|
||||||
|
|
||||||
for i=1, max_health do
|
|
||||||
local rect_x = x + (rect_width + gap) * (i-1) + padding
|
|
||||||
if player.health >= i then
|
|
||||||
love.graphics.setColor(0.7, 0.2, 0.2)
|
|
||||||
else
|
|
||||||
love.graphics.setColor(0.2, 0.2, 0.2)
|
|
||||||
end
|
|
||||||
love.graphics.rectangle("fill", rect_x, y+padding, rect_width, rect_height)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MainState:draw()
|
function MainState:draw()
|
||||||
for _, player in ipairs(self.players) do
|
for _, player in ipairs(self.players) do
|
||||||
love.graphics.setLineWidth(4)
|
love.graphics.setLineWidth(4)
|
||||||
|
local health_percent = player.health / Player.MAX_HEALTH
|
||||||
|
love.graphics.setColor(lerp_color(EMPTY_HEALTH_COLOR, FULL_HEALTH_COLOR, health_percent))
|
||||||
|
love.graphics.circle("fill", player.pos.x, player.pos.y, PLAYER_SIZE)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1)
|
love.graphics.setColor(1, 1, 1)
|
||||||
love.graphics.circle("line", player.pos.x, player.pos.y, PLAYER_SIZE)
|
love.graphics.circle("line", player.pos.x, player.pos.y, PLAYER_SIZE)
|
||||||
|
|
||||||
|
if player.has_bolt then
|
||||||
love.graphics.setLineWidth(3)
|
love.graphics.setLineWidth(3)
|
||||||
love.graphics.setColor(0.8, 0.1, 0.1)
|
love.graphics.setColor(ACTIVE_BOLT_COLOR)
|
||||||
local bolt_pos = player.pos + player:get_aim_dir() * BOLT_DIST_FROM_PLAYER
|
local bolt_pos = player.pos + player:get_aim_dir() * BOLT_DIST_FROM_PLAYER
|
||||||
love.graphics.circle("line", bolt_pos.x, bolt_pos.y, BOLT_SIZE)
|
love.graphics.circle("line", bolt_pos.x, bolt_pos.y, BOLT_SIZE)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setLineWidth(3)
|
||||||
for _, bolt in ipairs(self.bolts) do
|
for _, bolt in ipairs(self.bolts) do
|
||||||
|
if bolt.dead then
|
||||||
|
love.graphics.setColor(INACTIVE_BOLT_COLOR)
|
||||||
|
else
|
||||||
|
love.graphics.setColor(ACTIVE_BOLT_COLOR)
|
||||||
|
end
|
||||||
love.graphics.circle("line", bolt.pos.x, bolt.pos.y, BOLT_SIZE)
|
love.graphics.circle("line", bolt.pos.x, bolt.pos.y, BOLT_SIZE)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -260,9 +348,10 @@ function MainState:draw()
|
|||||||
self.world:draw()
|
self.world:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
local winw, winh = love.graphics.getDimensions()
|
if #self.players == 1 then
|
||||||
self:draw_health(10, 10, self.player_1, "left")
|
love.graphics.setColor(0.2, 1, 0.2)
|
||||||
self:draw_health(winw-10, 10, self.player_2, "right")
|
love.graphics.print("Victory!", 300, 200)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return MainState
|
return MainState
|
||||||
|
Loading…
Reference in New Issue
Block a user