Compare commits

...
25 Commits
Author SHA1 Message Date
Simon Kellet 8d756beb1b removed 2024-08-06 18:16:45 +01:00
Simon Kellet 86d33a7fc5 nearly there 2024-08-06 18:16:14 +01:00
Simon Kellet 65f4ee3473 wip 2024-08-06 17:39:14 +01:00
Simon Kellet e13114a736 power up colliders for both players 2024-08-06 17:39:09 +01:00
Simon Kellet 451d710326 escape key on pause 2024-08-02 17:27:23 +01:00
Simon Kellet 585fccf59a flips 2024-08-02 17:27:13 +01:00
Simon Kellet 3290d704e3 less prints 2024-08-02 17:27:09 +01:00
Simon Kellet 7b553d9758 formatting 2024-08-02 17:26:50 +01:00
Simon Kellet e9e3731a0b new window size 2024-08-02 17:26:43 +01:00
Simon Kellet ed9265939c scale conts 2024-08-02 17:26:35 +01:00
Simon Kellet 826ef98f19 no longer needed 2024-08-02 17:26:29 +01:00
Simon Kellet db3559b8c6 player scaling 2024-08-02 17:26:22 +01:00
Simon Kellet 88faf2538b scaling 2024-08-02 17:26:14 +01:00
Simon Kellet 7252c3cd2c scaling now works? yay? 2024-08-02 17:01:21 +01:00
Simon Kellet 7da12d3035 added mute 2024-07-31 20:37:25 +01:00
Simon Kellet ebf9369ba5 fixed game logix 2024-07-31 20:37:17 +01:00
Simon Kellet f6be8b2a16 removed btton func 2024-07-31 20:36:53 +01:00
Simon Kellet beb4c28a70 removed button func 2024-07-31 20:36:47 +01:00
Simon Kellet 2d22a50447 added mute 2024-07-31 20:36:29 +01:00
Simon Kellet d059017989 fix win 2024-07-31 20:36:20 +01:00
Simon Kellet 49a57a6e5d better bouncing finally 2024-07-31 20:36:10 +01:00
Simon Kellet f5770cd4e0 ops 2024-07-31 20:35:55 +01:00
Simon Kellet 49633072ac reset wind 2024-07-31 20:35:49 +01:00
Simon Kellet 7af90632fd added truncate method 2024-07-31 20:35:42 +01:00
Simon Kellet e47799650a added start of gui lib 2024-07-31 15:20:12 +01:00
22 changed files with 435 additions and 339 deletions
+17 -4
View File
@@ -6,15 +6,18 @@ end
local function drawHealth() local function drawHealth()
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
love.graphics.print("P1:" .. UserPlayer1.health, 5, 5) love.graphics.print("P1:" .. UserPlayer1.health, 5, 5)
love.graphics.print("P2:" .. UserPlayer2.health, width - 200, height - 95) love.graphics.print("P2:" .. UserPlayer2.health, width - 200, height - 95)
end end
function DrawGame() function DrawGame()
--STI local curWidth, curHeight = love.graphics.getDimensions()
GameMap:draw() love.graphics.scale(_G.X_SCALE, _G.Y_SCALE)
GameMap:draw(0, 0, _G.X_SCALE, _G.Y_SCALE)
GameMap:resize(curWidth / _G.X_SCALE, curHeight / _G.Y_SCALE)
-- WindField -- WindField
if DebugFlag then if DebugFlag then
@@ -22,6 +25,7 @@ function DrawGame()
drawFPS() drawFPS()
end end
-- Bullets
for _, v in ipairs(Bullets1) do for _, v in ipairs(Bullets1) do
v:draw() v:draw()
end end
@@ -29,9 +33,18 @@ function DrawGame()
v:draw() v:draw()
end end
-- PowerUps
for _, v in ipairs(PowerUps) do
v:draw()
end
UserPlayer1:draw() UserPlayer1:draw()
UserPlayer2:draw() UserPlayer2:draw()
--Draw Health --Draw Health
--TODO: make this nicer looking
drawHealth() drawHealth()
--TODO: draw running score
--drawScore()
end end
+25 -9
View File
@@ -1,10 +1,15 @@
function GameKeyPressed(key) function GameKeyPressed(key)
if key == "escape" then if key == "escape" then
if not MUTED then
musicBattle:setVolume(0) musicBattle:setVolume(0)
musicPause:setVolume(0.6) musicPause:setVolume(0.6)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
_G.GAMESTATE = "PAUSE" _G.GAMESTATE = "PAUSE"
print("STATE CHANEGD: PAUSED!") --print("STATE CHANEGD: PAUSED!")
_G.PAUSED = true _G.PAUSED = true
end end
@@ -12,20 +17,27 @@ function GameKeyPressed(key)
DebugFlag = not DebugFlag DebugFlag = not DebugFlag
end end
--TODO: Better restart
if key == "r" and not _G.PAUSED then if key == "r" and not _G.PAUSED then
RestartGame() RestartGame()
_G.GAMESTATE = "GAME" _G.GAMESTATE = "GAME"
love.load() love.load()
end end
-- debug map changes! if key == "m" then
--[[ _G.MUTED = not _G.MUTED
if DebugFlag and key == "1" then -- Need to set the battle music to mute
_G.CUR_LEVEL = 1 if _G.MUTED then
RestartGame() musicBattle:setVolume(0)
love.load() else
musicBattle:setVolume(0.5)
end end
end
if DebugFlag and key == "1" then
--UserPlayer1.speed = 50000
--print("player1 speed increased!")
end
if DebugFlag and key == "2" then if DebugFlag and key == "2" then
_G.CUR_LEVEL = 2 _G.CUR_LEVEL = 2
RestartGame() RestartGame()
@@ -36,5 +48,9 @@ function GameKeyPressed(key)
RestartGame() RestartGame()
love.load() love.load()
end end
--]]
if key == "p" then
testP = PowerUp("speed", 300, 300, "assets/powerup.jpeg", 10)
table.insert(PowerUps, testP)
end
end end
+42 -11
View File
@@ -21,7 +21,7 @@ local max = math.max -- optimisations
function UpdateGame(dt) function UpdateGame(dt)
--Check if anyone has won --Check if anyone has won
if checkLossState() == true then if checkLossState() == true then
print("STATE CHNAGED: WIN!") --print("STATE CHNAGED: WIN!")
_G.GAMESTATE = "WIN" _G.GAMESTATE = "WIN"
end end
--WindField --WindField
@@ -37,6 +37,7 @@ function UpdateGame(dt)
EnableKeyPress2 = true EnableKeyPress2 = true
end end
-- Update Bullets1
for i, v in ipairs(Bullets1) do for i, v in ipairs(Bullets1) do
v:update(dt) v:update(dt)
@@ -57,17 +58,17 @@ function UpdateGame(dt)
-- Hit player2 -- Hit player2
if v.collider:enter("Player2") then if v.collider:enter("Player2") then
print("Player1 hit Player2!") --print("Player1 hit Player2!")
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer1.health > 0 then if UserPlayer2.health > 0 then
UserPlayer1.health = UserPlayer1.health - 1 UserPlayer2.health = UserPlayer2.health - 1
end end
end end
-- Hit player1 -- Hit player1
if v.collider:enter("Player1") then if v.collider:enter("Player1") then
print("Player 1 hit themselves!") --print("Player 1 hit themselves!")
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer1.health > 0 then if UserPlayer1.health > 0 then
@@ -82,6 +83,7 @@ function UpdateGame(dt)
end end
end end
-- Update Bullets2
for i, v in ipairs(Bullets2) do for i, v in ipairs(Bullets2) do
v:update(dt) v:update(dt)
@@ -100,19 +102,19 @@ function UpdateGame(dt)
v.collider:destroy() v.collider:destroy()
end end
-- Hit player2 -- Hit player1
if v.collider:enter("Player1") then if v.collider:enter("Player1") then
print("Player2 hit Player1!") --print("Player2 hit Player1!")
table.remove(Bullets2, i) table.remove(Bullets2, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer2.health > 0 then if UserPlayer1.health > 0 then
UserPlayer2.health = UserPlayer2.health - 1 UserPlayer1.health = UserPlayer1.health - 1
end end
end end
-- Hit player1 -- Hit player2
if v.collider:enter("Player2") then if v.collider:enter("Player2") then
print("Player 2 hit themselves!") --print("Player 2 hit themselves!")
table.remove(Bullets2, i) table.remove(Bullets2, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer2.health > 0 then if UserPlayer2.health > 0 then
@@ -127,6 +129,35 @@ function UpdateGame(dt)
end end
end end
-- PowerUp updates
for i, v in ipairs(PowerUps) do
v:update(dt)
if v.collider:enter("Player1") then
UserPlayer1:getPowerUp(v)
UserPlayer1:powerup()
table.remove(PowerUps, i)
v.collider:destroy()
end
if v.collider:enter("Player2") then
UserPlayer2:getPowerUp(v)
UserPlayer2:powerup()
table.remove(PowerUps, i)
v.collider:destroy()
end
end
--PowerUp timer to place
PUTimeToPlace = PUTimeToPlace - dt
--print(PUTimeToPlace)
if PUTimeToPlace <= 0 then
local w, h = love.graphics.getDimensions()
local ranx = love.math.random(30, w)
local rany = love.math.random(100, h)
local newPU = PowerUp("speed", ranx, rany, "assets/powerup.jpeg", 10)
table.insert(PowerUps, newPU)
PUTimeToPlace = _G.PU_TIMER --reset
end
UserPlayer1:handleKeys("w", "s", "a", "d", dt) UserPlayer1:handleKeys("w", "s", "a", "d", dt)
UserPlayer2:handleKeys("up", "down", "left", "right", dt) UserPlayer2:handleKeys("up", "down", "left", "right", dt)
UserPlayer1:updateCol() UserPlayer1:updateCol()
+8 -31
View File
@@ -1,43 +1,20 @@
local function button(x, y, w, h, text, selected)
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
end
-- Draw rectangle
love.graphics.rectangle("line", x, y, w, h, rounding, rounding)
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
-- Calculate position to center the text
local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setFont(MenuFont)
love.graphics.print(text, textX, textY)
end
local function title() local function title()
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
love.graphics.setColor(0.5, 1, 1) love.graphics.setColor(0.5, 1, 1)
love.graphics.rectangle("fill", 0, 0, width, height) love.graphics.rectangle("fill", 0, 0, width, height)
love.graphics.setColor(0, 0, 0) love.graphics.setColor(0, 0, 0)
love.graphics.print("MENU", 100, 100) love.graphics.print("Tanks-A-Lot", 100, 100)
end end
function DrawMenu() function DrawMenu()
local bwidth, bheight = 300, 140 local bwidth, bheight = 300 * _G.X_SCALE, 140 * _G.Y_SCALE
title() title()
button(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false) GUI:newButton(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false) GUI:newButton(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false)
button(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false) GUI:newButton(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false)
button(100, 650, bwidth, bheight, "Quit", MENU_POS == 3 and true or false) GUI:newButton(100, 650, bwidth, bheight, "Quit", MENU_POS == 3 and true or false)
love.graphics.setColor(255, 255, 255) -- reset colours love.graphics.setColor(255, 255, 255) -- reset colours
end end
+13 -3
View File
@@ -7,12 +7,12 @@ function MenuKeyPressed(key)
if MENU_POS == 0 then if MENU_POS == 0 then
--Change state to GAME! --Change state to GAME!
_G.GAMESTATE = "GAME" _G.GAMESTATE = "GAME"
print("STATE CHANEGD: GAME!") --print("STATE CHANEGD: GAME!")
musicMenu:stop() musicMenu:stop()
elseif MENU_POS == 1 then elseif MENU_POS == 1 then
print("STATE CHANEGD: DUNNO!") --print("STATE CHANEGD: DUNNO!")
elseif MENU_POS == 2 then elseif MENU_POS == 2 then
print("STATE CHANEGD: DUNNO!") --print("STATE CHANEGD: DUNNO!")
elseif MENU_POS == 3 then elseif MENU_POS == 3 then
love.event.quit() love.event.quit()
end end
@@ -41,4 +41,14 @@ function MenuKeyPressed(key)
_G.GAMESTATE = "MENU" _G.GAMESTATE = "MENU"
love.load() love.load()
end end
if key == "m" then
MUTED = not MUTED
if MUTED then
musicMenu:setVolume(0)
else
musicMenu:setVolume(0.5)
end
end
end end
+7 -30
View File
@@ -1,32 +1,8 @@
local function button(x, y, w, h, text, selected)
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
end
-- Draw rectangle
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding)
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
-- Calculate position to center the text
local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setFont(MenuFont)
love.graphics.setColor(1, 1, 1) -- reset colours
love.graphics.print(text, textX, textY)
end
function DrawPause() function DrawPause()
local opacity = 0.3 local opacity = 0.3
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
local bwidth, bheight = 300, 140 local bwidth, bheight = 300 * _G.X_SCALE, 140 * _G.Y_SCALE
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
DrawGame() --Draw a single frame of the game DrawGame() --Draw a single frame of the game
@@ -37,8 +13,9 @@ function DrawPause()
love.graphics.print("PAUSED", 100, 100) love.graphics.print("PAUSED", 100, 100)
--love.graphics.print("" .. PAUSE_POS, 200,200) --love.graphics.print("" .. PAUSE_POS, 200,200)
button(100, 200, bwidth, bheight, "Return", PAUSE_POS == 0 and true or false) GUI:newButton(100, 200, bwidth, bheight, "Back", PAUSE_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "Menu", PAUSE_POS == 1 and true or false) GUI:newButton(100, 350, bwidth, bheight, "Menu", PAUSE_POS == 1 and true or false)
button(100, 500, bwidth, bheight, "Quit", PAUSE_POS == 2 and true or false) GUI:newButton(100, 500, bwidth, bheight, "Quit", PAUSE_POS == 2 and true or false)
love.graphics.setColor(255, 255, 255) -- reset colours love.graphics.setColor(255, 255, 255) -- reset colours
end end
+25 -3
View File
@@ -1,20 +1,42 @@
function PauseKeyPressed(key) function PauseKeyPressed(key)
if key == "return" then if key == "escape" then
-- quickly return to the game -- quickly return to the game
if not _G.MUTED then
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
_G.GAMESTATE = "GAME"
end
if key == "return" then
-- quickly return to the game
if not _G.MUTED then
musicBattle:setVolume(0.5)
musicPause:setVolume(0)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
-- 0 Return to game -- 0 Return to game
-- 1 Quit -- 1 Quit
if PAUSE_POS == 0 then if PAUSE_POS == 0 then
-- unpause the game -- unpause the game
_G.GAMESTATE = "GAME" _G.GAMESTATE = "GAME"
print("STATE CHANEGD: GAME!") --print("STATE CHANEGD: GAME!")
_G.PAUSED = false _G.PAUSED = false
if not MUTED then
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
elseif PAUSE_POS == 1 then elseif PAUSE_POS == 1 then
_G.GAMESTATE = "MENU" _G.GAMESTATE = "MENU"
print("STATE CHANEGD: MENU!") --print("STATE CHANEGD: MENU!")
_G.PAUSED = false _G.PAUSED = false
musicPause:stop() musicPause:stop()
musicBattle:stop() musicBattle:stop()
+5 -4
View File
@@ -1,12 +1,13 @@
local function winner() local function winner()
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local opacity = 0.3 local opacity = 0.3
local s = "" local s = ""
if not _G.P1_WIN then if _G.P1_WIN then
s = "P1 Win! R - Restart" s = "P1 Win! R - Restart"
elseif not _G.P2_WIN then end
if _G.P2_WIN then
s = "P2 Win! R - Restart" s = "P2 Win! R - Restart"
end end
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+60 -19
View File
@@ -1,7 +1,9 @@
Bullet = Object:extend() Bullet = Object:extend()
cos = math.cos local pi = math.pi
sin = math.sin --optimisation local cos = math.cos
pi = math.pi local sin = math.sin
local atan = math.atan
local deg = math.deg
function Bullet:new(x, y, p, speed, rotation) function Bullet:new(x, y, p, speed, rotation)
self.image = love.graphics.newImage("assets/bullet.png") self.image = love.graphics.newImage("assets/bullet.png")
@@ -20,9 +22,13 @@ function Bullet:new(x, y, p, speed, rotation)
self.originY = self.height / 2 self.originY = self.height / 2
self.collider = World:newCircleCollider(x, y, 10) self.collider = World:newCircleCollider(x, y, 10)
--self.collider = World:newRectangleCollider(x, y, 10, 10)
--self.collider:setType("")
self.collider:setFixedRotation(true) self.collider:setFixedRotation(true)
self.collider:setPosition(self.x, self.y) self.collider:setPosition(self.x, self.y)
self.bounce = 0 -- how many times this bullet has bounced
if self.p == 1 then if self.p == 1 then
self.collider:setCollisionClass("Bullet1") self.collider:setCollisionClass("Bullet1")
elseif self.p == 2 then elseif self.p == 2 then
@@ -31,34 +37,69 @@ function Bullet:new(x, y, p, speed, rotation)
end end
function Bullet:update(dt) function Bullet:update(dt)
--If a bullet hits a wall, make it bounce off the wall and change its rotation -- Calculate the velocity
if self.p == 1 then local dx = math.cos(self.rotation) * self.speed * dt
local dy = math.sin(self.rotation) * self.speed * dt
-- Check for collisions
if self.collider:enter("Wall") then if self.collider:enter("Wall") then
--calculate normal of the wall self.bounce = self.bounce + 1
--calculate the angle of reflection
local angle = (math.atan2(dx, dy))
--get normal of the wall without using getNormal()
----TODO: fix this -- Get the collision normal
local collision_data = self.collider:getEnterCollisionData("Wall")
local contact = collision_data.contact
local normal_x, normal_y = contact:getNormal()
--set the new angle -- Debug print to verify normal values
self.rotation = angle --print("---------------------------------")
self.collider:setAngle(self.rotation) --print("Collision detected!")
--print("Normal X:", normal_x, "Normal Y:", normal_y)
--print("Initial Velocity X:", dx, "Initial Velocity Y:", dy)
--print("Initial Angle: ", self.rotation)
-- Reflect the velocity using the normal
local dot_product = dx * normal_x + dy * normal_y
dx = dx - 2 * dot_product * normal_x
dy = dy - 2 * dot_product * normal_y
--print("################################")
-- Debug print to verify reflected velocity
--print("Reflected Velocity X:", dx, "Reflected Velocity Y:", dy)
self.rotation = deg(atan(dy, dx))
-- Update the rotation based on the new velocity direction
--self.rotation = deg(atan(dy, dx))
--print("Reflected Angle (radians):", self.rotation)
--print("Reflected Angle (degrees):", self.rotation)
--print("---------------------------------")
end end
-- Set the linear velocity of the collider
self.collider:setLinearVelocity(dx, dy)
-- Update position
self.x = self.collider:getX()
self.y = self.collider:getY()
end
--[[
function Bullet:update(dt)
local normal_x, normal_y = 0, 0
local dx, dy = 0, 0
if self.p == 1 or self.p == 2 then
if self.collider:enter("Wall") then
self.collider:setLinearVelocity(dx, dy)
else
dx = cos(self.rotation) * self.speed * dt dx = cos(self.rotation) * self.speed * dt
dy = sin(self.rotation) * self.speed * dt dy = sin(self.rotation) * self.speed * dt
self.collider:setLinearVelocity(dx, dy) self.collider:setLinearVelocity(dx, dy)
end end
if self.p == 2 then
local dx = cos(self.rotation) * self.speed * dt
local dy = sin(self.rotation) * self.speed * dt
self.collider:setLinearVelocity(dx, dy)
end end
-- Update position
self.x = self.collider:getX() self.x = self.collider:getX()
self.y = self.collider:getY() self.y = self.collider:getY()
end end
]]
function Bullet:draw() function Bullet:draw()
for _, _ in ipairs(Bullets1) do for _, _ in ipairs(Bullets1) do
View File
+5
View File
@@ -1,7 +1,12 @@
--Config file for the game --Config file for the game
function love.conf(t) function love.conf(t)
--t.window.width = 1366
--t.window.height = 768
t.window.width = 1600 t.window.width = 1600
t.window.height = 960 t.window.height = 960
t.window.title = "Tanks-A-Lot" t.window.title = "Tanks-A-Lot"
t.window.resizable = true
t.version = "11.5" t.version = "11.5"
end end
+22 -2
View File
@@ -1,3 +1,16 @@
-- WINDOW SCALE
-- Used to scale the game up or down
-- (scales STI world map and Walls in the game! )
-- (see debug for more)
X_SCALE = 1
Y_SCALE = 1
-- TILE SCALE
-- Since this game is put together rather badly
-- the game world is 1600x960
GAME_WORLD_DIM_WIDTH = 1600
GAME_WORLD_DIM_HEIGHT = 960
--[[ --[[
* Game states: * Game states:
* - MENU * - MENU
@@ -19,13 +32,20 @@ PAUSE_POS = 0
PAUSE_MAX = 2 -- 0 resume, 1 menu, 2 quit PAUSE_MAX = 2 -- 0 resume, 1 menu, 2 quit
BULLETS_MAX = 10 -- MAX amount of bullets a player can shoot BULLETS_MAX = 10 -- MAX amount of bullets a player can shoot
BULLETS_BOUNCE_MAX = 7 -- MAX amount of bounces before exploding! BULLETS_BOUNCE_MAX = 10 -- MAX amount of bounces before exploding!
BULLETS_LIFETIME = 50 BULLETS_LIFETIME = 50 --TODO: impl. lifetime for a bullet!
-- Power up timer
PU_TIMER = 10
-- WIN flags for P1 and P2 -- WIN flags for P1 and P2
P1_WIN = false P1_WIN = false
P2_WIN = false P2_WIN = false
-- Default speeds for bullets and player
DEFAULT_P_SPEED = 12000
DEFAULT_B_SPEED = 22000
-- WIN counts! -- WIN counts!
P1_COUNT = 0 P1_COUNT = 0
P2_COUNT = 0 P2_COUNT = 0
BIN
View File
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
GUI = Object:extend()
function GUI:new() end
function GUI:newButton(x, y, w, h, text, selected)
love.graphics.setColor(255, 255, 255) -- reset colours
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
local xoff = x + 10
local yoff = y - 10
local textX, textY = 0, 0
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
love.graphics.setFont(MenuFont)
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding)
-- Calculate position to center the text
textX = x + (w - tw) / 2
textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setColor(0, 0, 0)
love.graphics.print(text, textX, textY)
elseif selected then
-- If selected, raise the button and draw a shadow
love.graphics.setColor(love.math.colorFromBytes(0, 0, 0))
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding) -- shadow
love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
love.graphics.rectangle("fill", xoff, yoff, w, h, rounding, rounding) -- button offset
-- Calculate position to center the text
textX = xoff + (w - tw) / 2
textY = yoff + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setColor(1, 1, 1)
love.graphics.print(text, textX, textY)
end
end
-195
View File
@@ -1,195 +0,0 @@
local clock = os.clock
--- Simple profiler written in Lua.
-- @module profile
-- @alias profile
local profile = {}
-- function labels
local _labeled = {}
-- function definitions
local _defined = {}
-- time of last call
local _tcalled = {}
-- total execution time
local _telapsed = {}
-- number of calls
local _ncalls = {}
-- list of internal profiler functions
local _internal = {}
--- This is an internal function.
-- @tparam string event Event type
-- @tparam number line Line number
-- @tparam[opt] table info Debug info table
function profile.hooker(event, line, info)
info = info or debug.getinfo(2, "fnS")
local f = info.func
-- ignore the profiler itself
if _internal[f] or info.what ~= "Lua" then
return
end
-- get the function name if available
if info.name then
_labeled[f] = info.name
end
-- find the line definition
if not _defined[f] then
_defined[f] = info.short_src .. ":" .. info.linedefined
_ncalls[f] = 0
_telapsed[f] = 0
end
if _tcalled[f] then
local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil
end
if event == "tail call" then
local prev = debug.getinfo(3, "fnS")
profile.hooker("return", line, prev)
profile.hooker("call", line, info)
elseif event == "call" then
_tcalled[f] = clock()
else
_ncalls[f] = _ncalls[f] + 1
end
end
--- Sets a clock function to be used by the profiler.
-- @tparam function func Clock function that returns a number
function profile.setclock(f)
assert(type(f) == "function", "clock must be a function")
clock = f
end
--- Starts collecting data.
function profile.start()
if rawget(_G, "jit") then
jit.off()
jit.flush()
end
debug.sethook(profile.hooker, "cr")
end
--- Stops collecting data.
function profile.stop()
debug.sethook()
for f in pairs(_tcalled) do
local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil
end
-- merge closures
local lookup = {}
for f, d in pairs(_defined) do
local id = (_labeled[f] or "?") .. d
local f2 = lookup[id]
if f2 then
_ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0)
_telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0)
_defined[f], _labeled[f] = nil, nil
_ncalls[f], _telapsed[f] = nil, nil
else
lookup[id] = f
end
end
collectgarbage("collect")
end
--- Resets all collected data.
function profile.reset()
for f in pairs(_ncalls) do
_ncalls[f] = 0
end
for f in pairs(_telapsed) do
_telapsed[f] = 0
end
for f in pairs(_tcalled) do
_tcalled[f] = nil
end
collectgarbage("collect")
end
--- This is an internal function.
-- @tparam function a First function
-- @tparam function b Second function
-- @treturn boolean True if "a" should rank higher than "b"
function profile.comp(a, b)
local dt = _telapsed[b] - _telapsed[a]
if dt == 0 then
return _ncalls[b] < _ncalls[a]
end
return dt < 0
end
--- Generates a report of functions that have been called since the profile was started.
-- Returns the report as a numeric table of rows containing the rank, function label, number of calls, total execution time and source code line number.
-- @tparam[opt] number limit Maximum number of rows
-- @treturn table Table of rows
function profile.query(limit)
local t = {}
for f, n in pairs(_ncalls) do
if n > 0 then
t[#t + 1] = f
end
end
table.sort(t, profile.comp)
if limit then
while #t > limit do
table.remove(t)
end
end
for i, f in ipairs(t) do
local dt = 0
if _tcalled[f] then
dt = clock() - _tcalled[f]
end
t[i] = { i, _labeled[f] or "?", _ncalls[f], _telapsed[f] + dt, _defined[f] }
end
return t
end
local cols = { 3, 29, 11, 24, 32 }
--- Generates a text report of functions that have been called since the profile was started.
-- Returns the report as a string that can be printed to the console.
-- @tparam[opt] number limit Maximum number of rows
-- @treturn string Text-based profiling report
function profile.report(n)
local out = {}
local report = profile.query(n)
for i, row in ipairs(report) do
for j = 1, 5 do
local s = row[j]
local l2 = cols[j]
s = tostring(s)
local l1 = s:len()
if l1 < l2 then
s = s .. (" "):rep(l2 - l1)
elseif l1 > l2 then
s = s:sub(l1 - l2 + 1, l1)
end
row[j] = s
end
out[i] = table.concat(row, " | ")
end
local row =
" +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n"
local col =
" | # | Function | Calls | Time | Code | \n"
local sz = row .. col .. row
if #out > 0 then
sz = sz .. " | " .. table.concat(out, " | \n | ") .. " | \n"
end
return "\n" .. sz .. row
end
-- store all internal profiler functions
for _, v in pairs(profile) do
if type(v) == "function" then
_internal[v] = true
end
end
return profile
+24 -12
View File
@@ -11,8 +11,13 @@ World:addCollisionClass("Bullet1")
World:addCollisionClass("Player2") World:addCollisionClass("Player2")
World:addCollisionClass("Bullet2") World:addCollisionClass("Bullet2")
World:addCollisionClass("Wall") World:addCollisionClass("Wall")
World:addCollisionClass("PowerUp")
require("gui")
require("powerups/powerup")
require("powerups/speed")
require("restart") require("restart")
require("truncate")
require("player") require("player")
require("bullet") require("bullet")
require("mapsloader") require("mapsloader")
@@ -104,9 +109,17 @@ function love.run()
end end
end end
function love.load(args) function love.resized()
--TOD0: fix scaling!
end
function love.load()
-- Set a random seed -- Set a random seed
love.math.setRandomSeed(love.timer.getTime()) love.math.setRandomSeed(love.timer.getTime())
-- Figure out the X_SCALE and Y_SCALE
local curWidth, curHeight = love.graphics.getDimensions()
_G.X_SCALE = truncate(curWidth / GAME_WORLD_DIM_WIDTH, 3)
_G.Y_SCALE = truncate(curHeight / GAME_WORLD_DIM_HEIGHT, 3)
--Game values (reset after each load) --Game values (reset after each load)
HEALTH = 3 HEALTH = 3
@@ -117,6 +130,10 @@ function love.load(args)
Bullets1 = {} Bullets1 = {}
Bullets2 = {} Bullets2 = {}
--PowerUp stuff
PowerUps = {}
PUTimeToPlace = _G.PU_TIMER
DebugFlag = false DebugFlag = false
EnableKeyPress1 = true EnableKeyPress1 = true
KeyPressTime1 = 0 KeyPressTime1 = 0
@@ -126,9 +143,9 @@ function love.load(args)
KeyPressTime2 = 0 KeyPressTime2 = 0
KeyDelay2 = P2_DELAY KeyDelay2 = P2_DELAY
local playerSpeed = 12000 --TODO: two player speeds for upgrades
UserPlayer1 = Player(1, 1000, 100, HEALTH, "assets/player1.png", playerSpeed) UserPlayer1 = Player(1, 1000, 100, HEALTH, "assets/player1.png", 12000)
UserPlayer2 = Player(2, 200, 300, HEALTH, "assets/player2.png", playerSpeed) UserPlayer2 = Player(2, 200, 300, HEALTH, "assets/player2.png", 12000)
--STI Map loading --STI Map loading
LoadMap(_G.CUR_LEVEL) LoadMap(_G.CUR_LEVEL)
@@ -153,7 +170,7 @@ function love.update(dt)
if _G.GAMESTATE == "MENU" then if _G.GAMESTATE == "MENU" then
UpdateMenu(dt) UpdateMenu(dt)
-- Handle music -- Handle music
if not musicMenu:isPlaying() then if not musicMenu:isPlaying() and not _G.MUTED then
musicMenu:setVolume(0.5) musicMenu:setVolume(0.5)
love.audio.play(musicMenu) love.audio.play(musicMenu)
end end
@@ -161,7 +178,7 @@ function love.update(dt)
if _G.GAMESTATE == "PAUSE" then if _G.GAMESTATE == "PAUSE" then
UpdatePause(dt) UpdatePause(dt)
-- Handle music -- Handle music
if not musicPause:isPlaying() then if not musicPause:isPlaying() and not _G.MUTED then
musicBattle:setVolume(0) musicBattle:setVolume(0)
musicPause:setVolume(0.5) musicPause:setVolume(0.5)
love.audio.play(musicBattle) love.audio.play(musicBattle)
@@ -171,7 +188,7 @@ function love.update(dt)
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
UpdateGame(dt) UpdateGame(dt)
-- Handle music -- Handle music
if not musicBattle:isPlaying() then if not musicBattle:isPlaying() and not _G.MUTED then
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
love.audio.play(musicBattle) love.audio.play(musicBattle)
@@ -192,11 +209,6 @@ function love.draw()
end end
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
DrawGame() DrawGame()
if DebugFlag then
love.graphics.setFont(DebugFont)
love.graphics.print("Debug Mode", 1200, 850)
love.graphics.print("" .. GAMESTATE, 200, 200)
end
end end
if _G.GAMESTATE == "WIN" then if _G.GAMESTATE == "WIN" then
DrawWin() DrawWin()
+2
View File
@@ -8,6 +8,8 @@ function LoadMap(lvl)
if GameMap.layers["Walls"] then if GameMap.layers["Walls"] then
for _, obj in ipairs(GameMap.layers["Walls"].objects) do for _, obj in ipairs(GameMap.layers["Walls"].objects) do
local wall = World:newRectangleCollider(obj.x, obj.y, obj.width, obj.height) local wall = World:newRectangleCollider(obj.x, obj.y, obj.width, obj.height)
-- local wall =
-- World:newRectangleCollider(obj.x * _G.X_SCALE, obj.y * _G.Y_SCALE, obj.width * _G.X_SCALE, obj.height * _G.Y_SCALE)
wall:setType("static") wall:setType("static")
table.insert(Walls, wall) table.insert(Walls, wall)
Walls[#Walls]:setCollisionClass("Wall") Walls[#Walls]:setCollisionClass("Wall")
+39 -7
View File
@@ -1,6 +1,7 @@
Player = Object:extend() Player = Object:extend()
cos = math.cos local cos = math.cos
sin = math.sin --optimisation local sin = math.sin --optimisation
local max = math.max --optimisation
-- Constructor for the Player class -- Constructor for the Player class
function Player:new(p, x, y, health, image, speed) function Player:new(p, x, y, health, image, speed)
@@ -10,12 +11,18 @@ function Player:new(p, x, y, health, image, speed)
self.y = y self.y = y
self.health = health self.health = health
self.speed = speed self.speed = speed
self.bulletSpeed = _G.DEFAULT_B_SPEED
self.width = self.image:getWidth() self.width = self.image:getWidth()
self.height = self.image:getHeight() self.height = self.image:getHeight()
--Power up flag
self.PUName = ""
self.PUTime = 0
self.PUOn = false
-- Collision Stuff -- Collision Stuff
--self.collider = World:newRectangleCollider(x, y, 50, 62) --self.collider = World:newRectangleCollider(x, y, 50, 62)
self.collider = World:newCircleCollider(x, y, 24) self.collider = World:newCircleCollider(x, y, 24 * X_SCALE)
self.collider:setFixedRotation(true) self.collider:setFixedRotation(true)
if self.p == 1 then if self.p == 1 then
@@ -26,7 +33,9 @@ function Player:new(p, x, y, health, image, speed)
-- Rotation Stuff -- Rotation Stuff
self.rotation = math.rad(90) self.rotation = math.rad(90)
self.rotSpeed = 2 self.rotSpeed = 3
--self.scaleX = 1 * _G.X_SCALE
--self.scaleY = 1 * _G.Y_SCALE
self.scaleX = 1 self.scaleX = 1
self.scaleY = 1 self.scaleY = 1
self.originX = self.width / 2 self.originX = self.width / 2
@@ -84,13 +93,36 @@ function Player:updateCol()
end end
end end
function Player:getPowerUp(powerup)
self.PUName = powerup.name
self.PUTime = powerup.time
end
function Player:powerup()
self.PUOn = true
if self.PUName == "speed" then
--print("" .. self.PUName .. " for " .. self.PUTime)
self.speed = self.speed * 2.5
self.rotSpeed = self.rotSpeed * 1.5
end
end
-- Update method for the Player class -- Update method for the Player class
function Player:update(dt) function Player:update(dt)
local bulletSpeed = 20000 if self.PUOn then
self.PUTime = self.PUTime - dt
if max(0, self.PUTime) <= 0 then
-- Reset the player
self.PUName = "none"
self.PUTime = 0
self.PUOn = false
self.speed = _G.DEFAULT_P_SPEED
end
end
if EnableKeyPress1 == true and self.p == 1 then if EnableKeyPress1 == true and self.p == 1 then
if love.keyboard.isDown("space") then if love.keyboard.isDown("space") then
local newBullet = self:shoot(bulletSpeed) local newBullet = self:shoot(self.bulletSpeed)
table.insert(Bullets1, newBullet) table.insert(Bullets1, newBullet)
KeyPressTime1 = KeyDelay1 KeyPressTime1 = KeyDelay1
EnableKeyPress1 = false EnableKeyPress1 = false
@@ -99,7 +131,7 @@ function Player:update(dt)
if EnableKeyPress2 == true and self.p == 2 then if EnableKeyPress2 == true and self.p == 2 then
if love.keyboard.isDown("return") then if love.keyboard.isDown("return") then
local newBullet = self:shoot(bulletSpeed) local newBullet = self:shoot(self.bulletSpeed)
table.insert(Bullets2, newBullet) table.insert(Bullets2, newBullet)
KeyPressTime2 = KeyDelay2 KeyPressTime2 = KeyDelay2
EnableKeyPress2 = false EnableKeyPress2 = false
+70
View File
@@ -0,0 +1,70 @@
PowerUp = Object:extend()
-- PowerUp is the super class for all power-ups
-- found in the game
function PowerUp:new(name, x, y, image, time, lifetime)
self.name = name
self.x = x
self.y = y
self.image = love.graphics.newImage(image)
self.time = time
self.lifetime = lifetime
self.width = self.image:getWidth()
self.height = self.image:getHeight()
self.rotation = 1
self.scaleX = 1
self.scaleY = 1
self.originX = self.width / 2
self.originY = self.height / 2
-- Collider
self.collider = World:newRectangleCollider(x, y, 20, 20)
self.collider:setCollisionClass("PowerUp")
self.collider:setType("static")
self.collider:setPosition(self.x, self.y)
end
-- TODO: clean up colliosn on reset
-- make image draw
-- more stuff
-- see you later
function PowerUp:apply(player) end
function PowerUp:remove(player) end
function PowerUp:update(dt)
--check if the power up is past its lifetime
--spinnnnnn
self.rotation = self.rotation + 1.5 * dt
--grown and shrink
--[[
if self.scaleX >= 1.0 then
self.scaleX = self.scaleX - 0.2 * dt
elseif self.scaleX <= 1.8 then
self.scaleX = self.scaleX + 0.2 * dt
end
]]
self.x = self.collider:getX()
self.y = self.collider:getY()
end
function PowerUp:draw()
for _, _ in ipairs(PowerUps) do
love.graphics.draw(
self.image,
self.x,
self.y,
self.rotation,
self.scaleX,
self.scaleY,
self.originX,
self.originY
)
end
end
+13
View File
@@ -8,6 +8,12 @@ function ClearWalls(walls)
end end
end end
function ClearPowerUps(powerup)
for i, v in ipairs(powerup) do
v.collider:destroy()
end
end
function StopAllMusic() function StopAllMusic()
-- TODO: maybe find a way -- TODO: maybe find a way
-- to find all 'streaming' -- to find all 'streaming'
@@ -51,6 +57,10 @@ end
function RestartGame() function RestartGame()
setNewLevelFromRandom(getLevelCount()) setNewLevelFromRandom(getLevelCount())
--reset wins
_G.P1_WIN = false
_G.P2_WIN = false
-- Stop the music -- Stop the music
--StopAllMusic() --StopAllMusic()
@@ -64,5 +74,8 @@ function RestartGame()
--Clear Walls --Clear Walls
ClearWalls(Walls) ClearWalls(Walls)
--ClearPowerUps
ClearPowerUps(PowerUps)
-- Done! -- Done!
end end
+6
View File
@@ -0,0 +1,6 @@
function truncate(number, decdigits)
number = number * (10 ^ decdigits)
number = math.floor(number)
number = number / (10 ^ decdigits)
return number
end