From 4d8aa419a85f565d4c41ea02ceec2d9d722960de Mon Sep 17 00:00:00 2001 From: Arslaan Pathan Date: Tue, 1 Jul 2025 21:23:12 +1200 Subject: Add rounds system, nerf knockback, and a lot more --- assets/scripts/local2P.lua | 258 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 57 deletions(-) (limited to 'assets/scripts/local2P.lua') diff --git a/assets/scripts/local2P.lua b/assets/scripts/local2P.lua index 84ea73d..b425085 100644 --- a/assets/scripts/local2P.lua +++ b/assets/scripts/local2P.lua @@ -1,20 +1,29 @@ ----@diagnostic disable: undefined-global +---@diagnostic disable: undefined-global, lowercase-global backgrounds = require("assets.backgrounds.backgrounds-data") sprite_height = 128 sprite_width = 64 -gamePaused = false +remaining_rounds = 9 +current_round = 1 + +gamePaused = true isKO = false +isOverlay = true +isNewRound = false +isFight = false + +math.randomseed(os.time()) -groundTiles = { - { x = 250, y = HEIGHT - 300, width = 200, height = 30 }, - { x = WIDTH - 250 - 200, y = HEIGHT - 300, width = 200, height = 30 }, - { x = 0, y = HEIGHT - 100, width = WIDTH, height = 100 } +groundTiles = {} + +specialGroundTiles = { + { x = -50, y = 0, width = 55, height = HEIGHT, special = true }, + { x = WIDTH - 5, y = 0, width = 50, height = HEIGHT, special = true } } -knockbackMultiplierX = 35.4 -knockbackMultiplierY = 8.73 +knockbackMultiplierX = 22.4 +knockbackMultiplierY = 7.73 minimalKnockbackMultiplierY = 40.3 @@ -31,6 +40,7 @@ function SafeInitCharacter(character, default_x, default_y) character.can_apply_knockback = false character.facing = "right" character.isDead = false + character.wins = 0 end function Setup() @@ -38,13 +48,57 @@ function Setup() setBgImage(backgrounds[bgIndex]) SafeInitCharacter(player1Character, 250, 150) SafeInitCharacter(player2Character, WIDTH - 250 - (250 / 2), 150) + + groundTiles = {} + + local tileSize = 50 + local gridWidth = math.floor(WIDTH / tileSize) + local gridHeight = math.floor(HEIGHT / tileSize) + local clusterSizeMin, clusterSizeMax = 3, 5 + local clusterCount = 8 + + for _ = 1, clusterCount do + local clusterX = math.random(1, gridWidth - clusterSizeMax - 2) + local clusterY = math.random(5, gridHeight - 3) + local clusterSize = math.random(clusterSizeMin, clusterSizeMax) + + for i = 0, clusterSize - 1 do + table.insert(groundTiles, { + x = (clusterX + i) * tileSize, + y = clusterY * tileSize, + width = tileSize, + height = tileSize, + special = false + }) + end + end + + for _, tile in ipairs(specialGroundTiles) do + table.insert(groundTiles, tile) + end + + Timer.after(0.5, function () + isOverlay = false + isNewRound = true + Timer.after(2, function () + isNewRound = false + isFight = true + Timer.after(2, function () + isFight = false + gamePaused = false + end) + end) + end) end gravity = 1570 function DrawGroundTiles() for _, tile in ipairs(groundTiles) do - queueRectForRender(tile.x, tile.y, tile.width, tile.height, 100, 100, 100, 255) -- gray boxes + if tile.special then + return + end + queueTextureForRender("assets/images/tile.png", tile.x, tile.y) end end @@ -79,73 +133,85 @@ function IsHittingCeiling(character) return false end -function IsTouchingWall(character, direction) - for _, tile in ipairs(groundTiles) do - local charBottom = character.y + sprite_height - local charTop = character.y - local tileBottom = tile.y + tile.height - local tileTop = tile.y - - local verticalOverlapAmount = math.min(charBottom, tileBottom) - math.max(charTop, tileTop) - local verticalOverlap = verticalOverlapAmount > 12 - - -- New: Check if tile is within a certain horizontal range before collision test - local horizontalDistance - if direction == "left" then - horizontalDistance = character.x - (tile.x + tile.width) - if horizontalDistance > 15 then -- Only check if tile is within 15 pixels to the left - goto continue - end - elseif direction == "right" then - horizontalDistance = tile.x - (character.x + sprite_width) - if horizontalDistance > 15 then -- Only check if tile is within 15 pixels to the right - goto continue - end - end +function AABBOverlap(a, b) + return a.x < b.x + b.width and + a.x + a.width > b.x and + a.y < b.y + b.height and + a.y + a.height > b.y +end - if direction == "left" then - local nextX = character.x - character.speed - local willCollide = nextX < tile.x + tile.width and character.x >= tile.x + tile.width +function IsTouchingWall(character, direction, exclude_special) + local velocity = character.x_velocity - if willCollide and verticalOverlap then - character.x = tile.x + tile.width - return true - end - elseif direction == "right" then - local nextX = character.x + sprite_width + character.speed - local willCollide = nextX > tile.x and character.x + sprite_width <= tile.x + -- Clamp how far ahead we look + local max_check_distance = 1.0 -- only check 1 pixel ahead + if velocity > max_check_distance then velocity = max_check_distance end + if velocity < -max_check_distance then velocity = -max_check_distance end + + -- Prevent missing collisions on tiny glide + if math.abs(velocity) < 0.01 then + velocity = (direction == "right") and 0.01 or -0.01 + end + + local futureX = character.x + velocity + + local charBox = { + x = futureX, + y = character.y, + width = sprite_width, + height = sprite_height + } - if willCollide and verticalOverlap then + for _, tile in ipairs(groundTiles) do + if tile.special and exclude_special then goto continue end + + local tileBox = { + x = tile.x, + y = tile.y, + width = tile.width, + height = tile.height + } + + if AABBOverlap(charBox, tileBox) then + -- Resolve overlap + if direction == "left" then + character.x = tile.x + tile.width + elseif direction == "right" then character.x = tile.x - sprite_width - return true end + character.x_velocity = 0 + return true end + ::continue:: end + return false end function HandleP1Input() if player1Character.isDead then return end - if Input.isKeyPressedOnce("W") and player1Character.can_jump then + if Input.isKeyDown("W") and player1Character.can_jump then player1Character.y_velocity = player1Character.jump_strength * -1.0 player1Character.can_jump = false end if Input.isKeyDown("D") then - if not IsTouchingWall(player1Character, "right") then + if not IsTouchingWall(player1Character, "right", false) then player1Character.x_velocity = player1Character.speed player1Character.facing = "right" else player1Character.x_velocity = 0 + player1Character.x = math.floor(player1Character.x) end end if Input.isKeyDown("A") then - if not IsTouchingWall(player1Character, "left") then + if not IsTouchingWall(player1Character, "left", false) then player1Character.x_velocity = -player1Character.speed player1Character.facing = "left" else player1Character.x_velocity = 0 + player1Character.x = math.floor(player1Character.x) end end @@ -156,25 +222,27 @@ end function HandleP2Input() if player2Character.isDead then return end - if Input.isKeyPressedOnce("UP") and player2Character.can_jump then + if Input.isKeyDown("UP") and player2Character.can_jump then player2Character.y_velocity = player2Character.jump_strength * -1.0 player2Character.can_jump = false end if Input.isKeyDown("RIGHT") then - if not IsTouchingWall(player2Character, "right") then + if not IsTouchingWall(player2Character, "right", false) then player2Character.x_velocity = player2Character.speed player2Character.facing = "right" else player2Character.x_velocity = 0 + player2Character.x = math.floor(player2Character.x) end end if Input.isKeyDown("LEFT") then - if not IsTouchingWall(player2Character, "left") then + if not IsTouchingWall(player2Character, "left", false) then player2Character.x_velocity = -player2Character.speed player2Character.facing = "left" else player2Character.x_velocity = 0 + player2Character.x = math.floor(player2Character.x) end end @@ -255,22 +323,44 @@ function KillPlayer(character) isKO = true Timer.after(2, function() - character.lives = character.lives - 1 + remaining_rounds = remaining_rounds - 1 + current_round = current_round + 1 character.knockback_counter = 0 character.combo_chain = 0 - if character.lives > 0 then - Respawn(character) - character.isDead = false + + if character == player1Character then + player2Character.wins = player2Character.wins + 1 + else + player1Character.wins = player1Character.wins + 1 + end + + if remaining_rounds > 0 then + Setup() else -- Handle game over here end - gamePaused = false isKO = false + if remaining_rounds > 0 then + isOverlay = true + Timer.after(2, function () + isOverlay = false + isNewRound = true + Timer.after(2, function () + isNewRound = false + isFight = true + Timer.after(2, function () + gamePaused = false + isFight = false + end) + end) + end) + end end) end function RegisterHit(attacker, target, damage) target.knockback_counter = target.knockback_counter + damage + target.combo_chain = 0 attacker.combo_chain = attacker.combo_chain + 1 if attacker.combo_chain >= 4 then @@ -332,6 +422,10 @@ end function ApplyPhysics(character) if character.isDead then return end + + local last_x = character.x + local last_y = character.y + character.y_velocity = character.y_velocity + gravity * deltaTime character.y = character.y + character.y_velocity * deltaTime character.x = character.x + character.x_velocity * deltaTime @@ -348,6 +442,15 @@ function ApplyPhysics(character) IsHittingCeiling(character) end + if IsTouchingWall(character, "left", true) then + character.x = last_x + character.x_velocity = 0 + end + if IsTouchingWall(character, "right", true) then + character.x = last_x + character.x_velocity = 0 + end + if not IsOnGround(character) then character.can_jump = false end @@ -365,8 +468,12 @@ function ApplyPhysics(character) end end -function DrawKOGraphic() +function DrawOverlay() queueRectForRender(0, 0, 1280, 720, 0, 0, 0, 150) +end + +function DrawKOGraphic() + DrawOverlay() local fontFile = "assets/fonts/OpenSans-Bold.ttf" local fontSize = 96 @@ -375,10 +482,38 @@ function DrawKOGraphic() local x = (1280 - textWidth) / 2 local y = 720 / 2 - fontSize / 2 - queueTextForRender(text, fontFile, x, y, fontSize, 255, 0, 0, 255) queueTextForRender(text, fontFile, x + 5, y + 5, fontSize, 255, 255, 0, 255) + queueTextForRender(text, fontFile, x, y, fontSize, 255, 0, 0, 255) +end + +function DrawNewRoundGraphic() + DrawOverlay() + + local fontFile = "assets/fonts/OpenSans-Bold.ttf" + local fontSize = 96 + local text = "Round " .. current_round + if remaining_rounds == 1 then + text = "Final Round" + end + local textWidth = getTextWidth(fontFile, fontSize, text) + local x = (1280 - textWidth) // 2 + local y = 720 // 2 - fontSize // 2 + + queueTextForRender(text, fontFile, x, y, fontSize, 255, 255, 255, 255) end +function DrawFightGraphic() + DrawOverlay() + + local fontFile = "assets/fonts/OpenSans-Bold.ttf" + local fontSize = 96 + local text = "FIGHT!" + local textWidth = getTextWidth(fontFile, fontSize, text) + local x = (1280 - textWidth) // 2 + local y = 720 // 2 - fontSize // 2 + + queueTextForRender(text, fontFile, x, y, fontSize, 255, 255, 0, 255) +end function Update() local maxDelta = 0.05 -- max 50 ms per frame @@ -404,4 +539,13 @@ function Update() if isKO then DrawKOGraphic() end + if isOverlay then + DrawOverlay() + end + if isNewRound then + DrawNewRoundGraphic() + end + if isFight then + DrawFightGraphic() + end end -- cgit v1.2.3