1
0
dodge-bolt/src/systems/player.lua
2022-08-21 19:18:41 +00:00

262 lines
6.3 KiB
Lua

local Player = {}
local data = require("data")
local Vec = require("lib.brinevector")
local controls = data.controls
local AIMED_BOLT_DISTANCE = 15
local BOLT_AMOUNT = 1
local function getDirection(up_key, down_key, left_key, right_key)
local dx = (love.keyboard.isDown(right_key) and 1 or 0)
- (love.keyboard.isDown(left_key) and 1 or 0)
local dy = (love.keyboard.isDown(down_key) and 1 or 0)
- (love.keyboard.isDown(up_key) and 1 or 0)
return Vec(dx, dy).normalized
end
Player.required_groups = {"player", "controllable_player", "bolt"}
function Player:getMoveDirection()
return getDirection(
controls.move_up,
controls.move_down,
controls.move_left,
controls.move_right
)
end
function Player:getAimDirection(player)
if self.use_mouse_aim then
local ScreenScaler = self.pool:getSystem(require("systems.screen-scaler"))
local dir = Vec(ScreenScaler:getMousePosition()) - player.pos
return dir.normalized
-- local MAX_DIRECTIONS = 8
-- local angle_segment = math.pi*2/MAX_DIRECTIONS
-- local new_angle = math.floor(dir.angle/angle_segment+0.5)*angle_segment
-- return Vec(math.cos(new_angle), math.sin(new_angle))
else
return getDirection(
controls.aim_up,
controls.aim_down,
controls.aim_left,
controls.aim_right
)
end
end
function Player:addToGroup(group, e)
if group == "player" then
e.bolt_cooldown_timer = e.bolt_cooldown_timer or 0
e.aim_dir = e.aim_dir or Vec()
e.move_dir = e.move_dir or Vec()
end
end
function Player:update(dt)
if love.keyboard.isDown(controls.aim_up, controls.aim_down, controls.aim_left, controls.aim_right) then
self.use_mouse_aim = false
end
-- Update controls for "my" players
local move_direction = self:getMoveDirection()
for _, e in ipairs(self.pool.groups.controllable_player.entities) do
-- Update where they are aiming/looking
local aim_direction = self:getAimDirection(e)
if e.aim_dir ~= aim_direction then
e.aim_dir = aim_direction
self.pool:emit("playerAimed", e)
end
-- Update acceleration to make the player move
if e.move_dir ~= move_direction then
e.move_dir = move_direction
self.pool:emit("playerMoved", e)
end
-- Check if the player tried to shoot a bolt
if love.keyboard.isDown(controls.shoot) then
if self:tryShootingBolt(e) then
self.pool:emit("playerShot", e)
end
end
end
-- Update each player
for _, e in ipairs(self.pool.groups.player.entities) do
e.acc = e.move_dir * e.speed
-- Decrease bolt cooldown timer
if e.bolt_cooldown_timer > 0 then
e.bolt_cooldown_timer = math.max(0, e.bolt_cooldown_timer - dt)
end
-- If the player is nearby a non-moving bolt, pick it up
for _, bolt in ipairs(self.pool.groups.bolt.entities) do
if (e.pos-bolt.pos).length < 20 and bolt.vel.length < 3 then
self.pool:emit("storeBolt", e, bolt)
end
end
if e.acc.x ~= 0 or e.acc.y ~= 0 then
e.sprite.variant = "walk"
e.sprite.wobble = true
else
e.sprite.variant = "idle"
e.sprite.wobble = false
end
if e.acc.x < 0 then
e.sprite.flip = true
elseif e.acc.x > 0 then
e.sprite.flip = false
end
if #e.bolts > 0 then
local bolt = e.bolts[1]
if e.aim_dir.x ~= 0 or e.aim_dir.y ~= 0 then
bolt.hidden = nil
bolt.pos = e.pos + e.aim_dir * AIMED_BOLT_DISTANCE
else
bolt.hidden = true
end
end
end
end
function Player:mousemoved()
self.use_mouse_aim = true
end
function Player:tryShootingBolt(player)
if (player.aim_dir.x ~= 0 or player.aim_dir.y ~= 0) and
player.bolt_cooldown_timer == 0 and
#player.bolts > 0
then
player.bolt_cooldown_timer = player.bolt_cooldown
self.pool:emit("shootBolt", player)
return true
end
end
function Player:shootBolt(player)
local bolt = table.remove(player.bolts, 1)
if not bolt then return end
bolt.pos = player.pos + player.aim_dir * AIMED_BOLT_DISTANCE
bolt.vel = player.aim_dir * player.bolt_speed
bolt.owner = player
self.pool:emit("boltShot", player, bolt)
end
function Player:storeBolt(player, bolt)
bolt.owner = nil
table.insert(player.bolts, bolt)
end
function Player:hitPlayer(player, bolt)
self:resetMap()
end
local function createBolt()
return {
pos = Vec(),
vel = Vec(),
acc = Vec(),
sprite = {
name = "bolt",
variant = "idle",
},
friction = 0.98,
max_speed = 400,
}
end
function Player:resetMap()
local map = self.pool:getSystem(require("systems.map"))
local spawnpoints = map:listSpawnpoints()
for _, bolt in ipairs(self.pool.groups.bolt.entities) do
self.pool:removeEntity(bolt)
end
for i, player in ipairs(self.pool.groups.player.entities) do
for _, bolt in ipairs(player.bolts) do
self.pool:removeEntity(bolt)
end
local spawnpoint = spawnpoints[(i - 1) % #spawnpoints + 1]
player.pos = spawnpoint
player.bolts = {}
for _=1, BOLT_AMOUNT do
local bolt = self.pool:queue(createBolt())
self.pool:emit("storeBolt", player, bolt)
end
end
end
function Player:spawnPlayer(pos)
if not pos then
local map = self.pool:getSystem(require("systems.map"))
local spawnpoints = map:listSpawnpoints()
local players = self.pool.groups.player.entities
pos = spawnpoints[#players % #spawnpoints + 1]
end
local player = self.pool:queue{
pos = pos,
vel = Vec(0, 0),
acc = Vec(),
sprite = {
name = "player",
variant = "walk"
},
friction = 0.998,
speed = 800,
bolt_speed = 2000,
bolts = {},
bolt_cooldown = 0.1,
collider = {-5, -5, 4, 8}
}
for _=1, BOLT_AMOUNT do
local bolt = self.pool:queue(createBolt())
self.pool:emit("storeBolt", player, bolt)
end
return player
end
function Player:draw()
for _, e in ipairs(self.pool.groups.controllable_player.entities) do
if (e.aim_dir.x ~= 0 or e.aim_dir.y ~= 0) and #e.bolts > 0 then
local boltSystem = self.pool:getSystem(require("systems.bolt"))
local pos = e.pos + e.aim_dir * AIMED_BOLT_DISTANCE*0
local vel = (e.aim_dir * e.bolt_speed).normalized * AIMED_BOLT_DISTANCE*1
local point_amount = 8
local points = boltSystem:projectTrajectory(pos, vel, point_amount+3)
for i=3, point_amount+3-1 do
local ghost = data.sprites["bolt-ghost"]
local point = points[i]
local frame = ghost.variants.default[1]
love.graphics.setColor(1, 1, 1, (point_amount-(i-3))/point_amount)
love.graphics.draw(
frame.image,
point.x,
point.y,
nil,
nil,
nil,
ghost.width/2, ghost.height/2
)
end
end
end
end
return Player