262 lines
6.3 KiB
Lua
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
|