Skip to content

Commit

Permalink
small improvements to game logic
Browse files Browse the repository at this point in the history
  • Loading branch information
GitPaulo committed Jan 6, 2025
1 parent 53d584f commit 170c4c8
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 89 deletions.
59 changes: 7 additions & 52 deletions src/entities/fighter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ function Fighter:init(

-- Set the default animation to idle
self.currentAnimation = self.animations.idle

-- Font
self.eventFont = love.graphics.newFont(20)
end

function Fighter:validateFighterParameters()
Expand Down Expand Up @@ -218,21 +215,17 @@ function Fighter:updateState(dt, other)
local isHitPeriodOver = currentTime >= self.hitEndTime
local isIdle = self.state == 'idle'

-- Handle knockback
if self.knockbackActive or self.knockbackDelayTimer > 0 then
self:checkForKnockback(dt)
end

-- Check if active attack
if isAttacking then
self:checkAttackActivity(currentTime)
end

-- Check for clash
if not self.isClashing then
self:checkForClash(other)
end

-- Handle knockback
if self.knockbackActive or self.knockbackDelayTimer > 0 then
self:checkForKnockback(dt)
end

-- Transition from attacking to recovery if the attack period has ended
if isAttacking and isAttackPeriodOver then
if self.isAirborne then
Expand Down Expand Up @@ -576,6 +569,7 @@ function Fighter:checkForKnockback(dt)
self:takeDamage(self.pendingDamage)
self.pendingDamage = nil
self.knockbackApplied = false
self.isClashing = false
end
else -- Move incrementally towards the target
local knockbackStep = self.knockbackSpeed * dt * self.direction * -1 -- Move in the opposite direction
Expand Down Expand Up @@ -677,7 +671,7 @@ function Fighter:applyKnockback()
self.lostClash = false -- Reset lost clash flag

-- Play clash sound effect
SoundManager:playSound(self.sounds.clash, {clone = true})
SoundManager:playSound(self.sounds.clash, {preventOverlap = true})
end

function Fighter:winClash(loser)
Expand Down Expand Up @@ -705,8 +699,6 @@ function Fighter:render(other)
if _G.isDebug then
self:drawHitboxes(other)
end
self:drawBlockingText()
self:drawClashText(other)
end

function Fighter:drawSprite()
Expand Down Expand Up @@ -779,43 +771,6 @@ function Fighter:drawHitboxes()
end
end

function Fighter:drawBlockingText()
if self.isBlockingDamage then
love.graphics.setFont(self.eventFont)
love.graphics.setColor(1, 1, 0, 1)
love.graphics.print('Blocked!', self.x - 18, self.y - 22)
love.graphics.setColor(1, 1, 1, 1) -- Reset color
end
end

function Fighter:drawClashText(other)
local currentTime = love.timer.getTime()
local displayTime = 1 -- Display for 1 seconds
if self.isClashing and currentTime - self.clashTime < displayTime then
-- Draw "Clash!" between the two fighters
love.graphics.setFont(self.eventFont)
love.graphics.setColor(1, 1, 0, 1)
local clashX = (self.x + other.x) / 2
local clashY = math.min(self.y, other.y) - 20
love.graphics.printf('Clash!', clashX - 50, clashY, 100, 'center')

-- Draw "LOST" over the losing player
if _G.isDebug then
if self.lostClash then
love.graphics.setColor(1, 0, 0, 1)
love.graphics.printf('Lost', self.x - 28, self.y - 25, 100, 'center')
elseif other.lostClash then
love.graphics.setColor(1, 0, 0, 1)
love.graphics.printf('Lost', other.x - 28, other.y - 25, 100, 'center')
end
end

love.graphics.setColor(1, 1, 1, 1) -- Reset color
else
self.isClashing = false
end
end

function Fighter:getAttackHitbox()
if not self.attackType or not self.hitboxes[self.attackType] then
return nil
Expand Down
20 changes: 16 additions & 4 deletions src/sound/soundmanager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,27 @@ function SoundManager:playSound(sound, params)
local volume = params.volume or 1
local pitch = params.pitch or 1
local cloneSound = params.clone or false
local preventOverlap = params.preventOverlap or false

-- Prevent playing the same sound if it's already playing and preventOverlap is true
if preventOverlap and sound:isPlaying() then
return
end

-- print('playing sound', sound, delay, repeatCount, volume, pitch, preventOverlap)

if cloneSound then
sound = sound:clone()
end

if delay > 0 then
self:scheduleSound(sound, delay, repeatCount, volume, pitch)
self:scheduleSound(sound, delay, repeatCount, volume, pitch, preventOverlap)
else
self:executeSound(sound, repeatCount, volume, pitch)
end
end

function SoundManager:scheduleSound(sound, delay, repeatCount, volume, pitch)
function SoundManager:scheduleSound(sound, delay, repeatCount, volume, pitch, preventOverlap)
local currentTime = love.timer.getTime()
table.insert(
self.scheduledSounds,
Expand All @@ -33,7 +41,8 @@ function SoundManager:scheduleSound(sound, delay, repeatCount, volume, pitch)
sound = sound,
repeatCount = repeatCount,
volume = volume,
pitch = pitch
pitch = pitch,
preventOverlap = preventOverlap
}
)
end
Expand All @@ -53,7 +62,10 @@ function SoundManager:update()
for i = #self.scheduledSounds, 1, -1 do
local soundData = self.scheduledSounds[i]
if currentTime >= soundData.time then
self:executeSound(soundData.sound, soundData.repeatCount, soundData.volume, soundData.pitch)
-- Prevent playing if preventOverlap is enabled and sound is still playing
if not (soundData.preventOverlap and soundData.sound:isPlaying()) then
self:executeSound(soundData.sound, soundData.repeatCount, soundData.volume, soundData.pitch)
end
table.remove(self.scheduledSounds, i)
end
end
Expand Down
127 changes: 94 additions & 33 deletions src/states/game.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ function Game:enter(params)
assert(self.fighter1, 'Fighter 1 must be provided to the game state')
assert(self.fighter2, 'Fighter 2 must be provided to the game state')

-- Flash screen
self.flashStartTime = love.timer.getTime()
self.flashDuration = 0.8
self.flashActive = false

-- AI setup (assuming fighter2 is controlled by AI)
self.aiController = params.useAI and AIController:new(self.fighter2, self.fighter1) or nil

Expand All @@ -46,6 +51,7 @@ function Game:enter(params)
self.gameOverFont = love.graphics.newFont(32)
self.winnerFont = love.graphics.newFont(20)
self.instructionsFont = love.graphics.newFont(16)
self.eventFont = love.graphics.newFont(20)
end

function Game:exit()
Expand Down Expand Up @@ -85,6 +91,14 @@ function Game:update(dt)
self.fighter1:update(dt, self.fighter2)
self.fighter2:update(dt, self.fighter1)

-- Flash logic
if self.fighter1.isClashing or self.fighter2.isClashing then
if not self.flashActive then
self.flashActive = true
self.flashStartTime = love.timer.getTime()
end
end

-- Check for game over - leave this block last
local hasFighterDied = self.fighter1.state == 'death' or self.fighter2.state == 'death'
if hasFighterDied then
Expand Down Expand Up @@ -122,30 +136,24 @@ function Game:render()
self.fighter1:render(self.fighter2)
self.fighter2:render(self.fighter1)

-- Block
self:drawBlock()

-- Flash screen when fighters collide
self:drawFlash()

-- Render health bars
self:drawHealthBars()

-- Render recovery progress bars
self:drawRecoveryBars()

-- Render FFT visualizer
self:drawFFT()

-- Render recovery progress bars
self:drawRecoveryBar(self.fighter1)
self:drawRecoveryBar(self.fighter2)

-- Render game over screen if game is over
if self.gameOver then
-- Apply semi-transparent red overlay
love.graphics.setColor(1, 0, 0, 0.5)
love.graphics.rectangle('fill', 0, 0, BACKGROUND_FRAME_WIDTH, BACKGROUND_FRAME_HEIGHT)
love.graphics.setColor(1, 1, 1, 1) -- Reset color to white

-- Render game over text
love.graphics.setFont(self.gameOverFont)
love.graphics.printf('Game Over', 0, BACKGROUND_FRAME_HEIGHT / 2 - 60, BACKGROUND_FRAME_WIDTH, 'center')
love.graphics.setFont(self.winnerFont)
love.graphics.printf(self.winner .. ' wins!', 0, BACKGROUND_FRAME_HEIGHT / 2 - 10, BACKGROUND_FRAME_WIDTH, 'center')
love.graphics.setFont(self.instructionsFont)
love.graphics.printf("Press 'ESC' to return to Main Menu", 0, BACKGROUND_FRAME_HEIGHT / 2 + 20, BACKGROUND_FRAME_WIDTH, 'center')
self:drawGameOverScreen()
end

-- Render FPS counter in the top right corner
Expand All @@ -157,28 +165,81 @@ function Game:render()
end
end

function Game:drawRecoveryBar(fighter)
local currentTime = love.timer.getTime()
local lastAttackType = fighter.lastAttackType
function Game:drawBlock()
if self.fighter1.isBlockingDamage then
love.graphics.setFont(self.eventFont)
love.graphics.setColor(1, 1, 0, 1)
love.graphics.print('Blocked', self.fighter1.x - 18, self.fighter1.y - 22)
love.graphics.setColor(1, 1, 1, 1) -- Reset color
end

if self.fighter2.isBlockingDamage then
love.graphics.setFont(self.eventFont)
love.graphics.setColor(1, 1, 0, 1)
love.graphics.print('Blocked', self.fighter2.x - 18, self.fighter2.y - 22)
love.graphics.setColor(1, 1, 1, 1) -- Reset color
end
end

function Game:drawFlash()
if not self.flashActive then
return
end

-- Ensure lastAttackType exists in fighter.attacks
local recoveryDuration =
(lastAttackType and fighter.attacks[lastAttackType]) and fighter.attacks[lastAttackType].recovery or 0
local elapsedTime = currentTime - (fighter.recoveryEndTime - recoveryDuration)
local progress = math.min(elapsedTime / recoveryDuration, 1) -- Ensure progress doesn't exceed 1
local elapsedTime = love.timer.getTime() - self.flashStartTime
if elapsedTime < self.flashDuration then
local alpha = 1 - (elapsedTime / self.flashDuration) -- Fade out smoothly
love.graphics.setColor(1, 1, 1, alpha) -- White with decreasing opacity
love.graphics.rectangle("fill", 0, 0, BACKGROUND_FRAME_WIDTH, BACKGROUND_FRAME_HEIGHT)
love.graphics.setColor(1, 1, 1, 1) -- Reset color
else
self.flashActive = false
end
end

local barWidth = 44 -- Full width of the bar
local barHeight = 4
local x = fighter.id == 1 and 10 or love.graphics.getWidth() - 10 - barWidth
local y = 45 -- Position just under the stamina bar
function Game:drawGameOverScreen()
-- Apply semi-transparent red overlay
love.graphics.setColor(1, 0, 0, 0.5)
love.graphics.rectangle('fill', 0, 0, BACKGROUND_FRAME_WIDTH, BACKGROUND_FRAME_HEIGHT)
love.graphics.setColor(1, 1, 1, 1) -- Reset color to white

-- Render game over text
love.graphics.setFont(self.gameOverFont)
love.graphics.printf('Game Over', 0, BACKGROUND_FRAME_HEIGHT / 2 - 60, BACKGROUND_FRAME_WIDTH, 'center')
love.graphics.setFont(self.winnerFont)
love.graphics.printf(self.winner .. ' wins!', 0, BACKGROUND_FRAME_HEIGHT / 2 - 10, BACKGROUND_FRAME_WIDTH, 'center')
love.graphics.setFont(self.instructionsFont)
love.graphics.printf("Press 'ESC' to return to Main Menu", 0, BACKGROUND_FRAME_HEIGHT / 2 + 20, BACKGROUND_FRAME_WIDTH, 'center')
end

love.graphics.setColor(1, 1, 1, 0.5) -- Background color
love.graphics.rectangle('fill', x, y, barWidth, barHeight)
function Game:drawRecoveryBars()
local function drawRecoveryBar(fighter)
local currentTime = love.timer.getTime()
local lastAttackType = fighter.lastAttackType

love.graphics.setColor(1, 1, 1, 1) -- Progress color
love.graphics.rectangle('fill', x, y, barWidth * progress, barHeight)
-- Ensure lastAttackType exists in fighter.attacks
local recoveryDuration =
(lastAttackType and fighter.attacks[lastAttackType]) and fighter.attacks[lastAttackType].recovery or 0
local elapsedTime = currentTime - (fighter.recoveryEndTime - recoveryDuration)
local progress = math.min(elapsedTime / recoveryDuration, 1) -- Ensure progress doesn't exceed 1

love.graphics.setColor(1, 1, 1, 1) -- Reset color
local barWidth = 44 -- Full width of the bar
local barHeight = 4
local x = fighter.id == 1 and 10 or love.graphics.getWidth() - 10 - barWidth
local y = 45 -- Position just under the stamina bar

love.graphics.setColor(1, 1, 1, 0.5) -- Background color
love.graphics.rectangle('fill', x, y, barWidth, barHeight)

love.graphics.setColor(1, 1, 1, 1) -- Progress color
love.graphics.rectangle('fill', x, y, barWidth * progress, barHeight)

love.graphics.setColor(1, 1, 1, 1) -- Reset color
end

-- Draw recovery bars for both fighters
drawRecoveryBar(self.fighter1)
drawRecoveryBar(self.fighter2)
end

function Game:buildBackground()
Expand Down

0 comments on commit 170c4c8

Please sign in to comment.