aboutsummaryrefslogtreecommitdiff
path: root/assets/scripts/local2P.lua
diff options
context:
space:
mode:
authorArslaan Pathan <[email protected]>2025-06-15 20:27:31 +1200
committerArslaan Pathan <[email protected]>2025-06-15 20:27:31 +1200
commit3c399d6ea4ad3528f1845944bb6d5b00697d2c0b (patch)
tree9f136c5e040a2d853d24fd6974233cc01d6e8ceb /assets/scripts/local2P.lua
parent5348dbdef1c55c076c8603bad98d20c73085d12b (diff)
downloadshowdownofthesticks-3c399d6ea4ad3528f1845944bb6d5b00697d2c0b.tar.xz
showdownofthesticks-3c399d6ea4ad3528f1845944bb6d5b00697d2c0b.zip
Add punch feature + knockback etc, lots of cool shit
Diffstat (limited to 'assets/scripts/local2P.lua')
-rw-r--r--assets/scripts/local2P.lua282
1 files changed, 236 insertions, 46 deletions
diff --git a/assets/scripts/local2P.lua b/assets/scripts/local2P.lua
index 7fd2efa..61262b2 100644
--- a/assets/scripts/local2P.lua
+++ b/assets/scripts/local2P.lua
@@ -1,18 +1,25 @@
---@diagnostic disable: undefined-global
backgrounds = require("assets.backgrounds.backgrounds-data")
+sprite_height = 128
+sprite_width = 64
+
+deltaTimeMultiplier = 60
groundTiles = {
- { x = 250, y = HEIGHT - 300, width = 200, height = 30 },
- { x = WIDTH - 250 - 200, y = HEIGHT - 300, width = 200, height = 30 },
+ { 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 }
}
function SafeInitCharacter(character, default_x, default_y)
- character.x = character.x or default_x
- character.y = character.y or default_y
- character.y_velocity = character.y_velocity or 1
+ character.x = default_x
+ character.x_velocity = 1
+ character.y = default_y
+ character.y_velocity = 1
character.current_sprite = character.asset_dir .. "/sprites/idle.png"
+ character.default_sprite = character.current_sprite
character.can_jump = false
character.knockback_counter = 0
character.combo_chain = 0
@@ -36,32 +43,88 @@ end
function IsOnGround(character)
for _, tile in ipairs(groundTiles) do
- local characterFeetY = character.y + 128
+ local characterFeetY = character.y + sprite_height
- local isWithinX = character.x + 64 > tile.x and character.x < tile.x + tile.width
+ local isWithinX = character.x + sprite_width > tile.x and character.x < tile.x + tile.width
local isTouchingY = characterFeetY >= tile.y and characterFeetY <= tile.y + tile.height
+ local isFalling = character.y_velocity >= 0
+
+ if isWithinX and isTouchingY and isFalling then
+ character.y = tile.y - sprite_height
+ return true
+ end
+ end
+ return false
+end
+
+function IsHittingCeiling(character)
+ for _, tile in ipairs(groundTiles) do
+ local characterHeadY = character.y
+ local isWithinX = character.x + sprite_width > tile.x and character.x < tile.x + tile.width
+ local isTouchingY = characterHeadY <= tile.y + tile.height and characterHeadY >= tile.y
if isWithinX and isTouchingY then
- character.y = tile.y - 128
+ character.y = tile.y + tile.height
+ character.y_velocity = 0
return true
end
end
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 verticalOverlap = charBottom > tileTop and charTop < tileBottom
+
+ if direction == "left" then
+ local nextX = character.x - character.speed
+ local willCollide = nextX < tile.x + tile.width and character.x >= tile.x + tile.width
+
+ 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
+
+ if willCollide and verticalOverlap then
+ character.x = tile.x - sprite_width
+ return true
+ end
+ end
+ end
+ return false
+end
+
function HandleP1Input()
if Input.isKeyPressedOnce("W") and player1Character.can_jump then
- player1Character.y_velocity = player1Character.jump_strength * -1.0
- player1Character.can_jump = false
+ player1Character.y_velocity = player1Character.jump_strength * -1.0
+ player1Character.can_jump = false
end
+
if Input.isKeyDown("D") then
- player1Character.x = player1Character.x + player1Character.speed
+ if not IsTouchingWall(player1Character, "right") then
+ player1Character.x_velocity = player1Character.speed
+ else
+ player1Character.x_velocity = 0
+ end
end
if Input.isKeyDown("A") then
- player1Character.x = player1Character.x - player1Character.speed
+ if not IsTouchingWall(player1Character, "left") then
+ player1Character.x_velocity = -player1Character.speed
+ else
+ player1Character.x_velocity = 0
+ end
end
+
if Input.isKeyPressedOnce("F") then
-
+ PerformPunch(player1Character, player2Character)
end
end
@@ -70,46 +133,28 @@ function HandleP2Input()
player2Character.y_velocity = player2Character.jump_strength * -1.0
player2Character.can_jump = false
end
+
if Input.isKeyDown("RIGHT") then
- player2Character.x = player2Character.x + player2Character.speed
+ if not IsTouchingWall(player2Character, "right") then
+ player2Character.x_velocity = player2Character.speed
+ else
+ player2Character.x_velocity = 0
+ end
end
if Input.isKeyDown("LEFT") then
- player2Character.x = player2Character.x - player2Character.speed
- end
-end
-
-function Update()
- -- P1 physics
- player1Character.y_velocity = player1Character.y_velocity + gravity
- player1Character.y = player1Character.y + player1Character.y_velocity
-
- if IsOnGround(player1Character) then
- player1Character.y_velocity = 0
- player1Character.can_jump = true
+ if not IsTouchingWall(player2Character, "left") then
+ player2Character.x_velocity = -player2Character.speed
+ else
+ player2Character.x_velocity = 0
+ end
end
- -- P2 physics
- player2Character.y_velocity = player2Character.y_velocity + gravity
- player2Character.y = player2Character.y + player2Character.y_velocity
-
- if IsOnGround(player2Character) then
- player2Character.y_velocity = 0
- player2Character.can_jump = true
+ if Input.isKeyPressedOnce("Right Alt") or Input.isKeyPressedOnce("Right Option") then
+ PerformPunch(player2Character, player1Character)
end
+end
- -- Render
- queueTextureForRender(
- player1Character.current_sprite,
- math.floor(player1Character.x),
- math.floor(player1Character.y)
- )
-
- queueTextureForRender(
- player2Character.current_sprite,
- math.floor(player2Character.x),
- math.floor(player2Character.y)
- )
-
+function DrawUI()
local fontFile = "assets/fonts/OpenSans-Bold.ttf"
local fontSize = 24
local text = player1Character.name
@@ -144,10 +189,155 @@ function Update()
local x = WIDTH - textWidth - 40
queueTextForRender(text, fontFile, x, y, fontSize, 0, 0, 0, 255)
+end
+
+function Respawn(character)
+ SafeInitCharacter(character, 250, 150)
+end
+
+function ApplyKnockback(attacker, target)
+ local knockbackMultiplierX = 0.47
+ local knockbackMultiplierY = 0.01
+ target.y_velocity = -10 - (target.knockback_counter * knockbackMultiplierY)
+
+ local direction = 1
+ if target.x < attacker.x then
+ direction = -1
+ end
+ target.x_velocity = target.knockback_counter * knockbackMultiplierX * direction
+ -- target.x = target.x + direction * (target.knockback_counter * 0.7)
+end
+
+function ApplyMinimalKnockback(attacker, target)
+ local knockbackMultiplierX = 0.47
+ local knockbackMultiplierY = 0.01
+ local knockbackCountMinimal = 5
+ target.y_velocity = -10 - (knockbackCountMinimal * knockbackMultiplierY)
+
+ local direction = 1
+ if target.x < attacker.x then
+ direction = -1
+ end
+
+ target.x_velocity = knockbackCountMinimal * knockbackMultiplierX * direction
+ -- target.x = target.x + direction * (target.knockback_counter * 0.7)
+end
+
+function KillPlayer(character)
+ character.lives = character.lives - 1
+ character.knockback_counter = 0
+ character.combo_chain = 0
+ if character.lives > 0 then
+ Respawn(character)
+ end
+end
+
+function RegisterHit(attacker, target, damage)
+ target.knockback_counter = target.knockback_counter + damage
+ attacker.combo_chain = attacker.combo_chain + 1
+
+ if attacker.combo_chain >= 4 then
+ ApplyKnockback(attacker, target)
+ attacker.combo_chain = 0
+ else
+ ApplyMinimalKnockback(attacker, target)
+ end
+
+ if target.knockback_counter >= 1000 then
+ KillPlayer(target)
+ end
+end
+
+function PerformPunch(attacker, target)
+ local punch_range = 27
+ local punch_height = 80
+
+ -- Determine direction of target relative to attacker
+ local punch_direction = (target.x > attacker.x) and "right" or "left"
+
+ -- Set punch sprite
+ attacker.current_sprite = attacker.asset_dir .. "/sprites/punch_" .. punch_direction .. ".png"
+
+ -- Reset sprite after a short delay (e.g., 0.15s)
+ Timer.clearAllTimers()
+ Timer.after(0.15, function()
+ attacker.current_sprite = attacker.default_sprite
+ end)
+
+ -- Define hitbox based on punch direction
+ local hitbox = {
+ x = attacker.x + (punch_direction == "right" and sprite_width or -punch_range),
+ y = attacker.y + (sprite_height / 2) - (punch_height / 2),
+ width = punch_range,
+ height = punch_height
+ }
+
+ local targetHitbox = {
+ x = target.x,
+ y = target.y,
+ width = sprite_width,
+ height = sprite_height
+ }
+
+ local function isColliding(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 isColliding(hitbox, targetHitbox) then
+ RegisterHit(attacker, target, attacker.hit_strength)
+ end
+end
+
+function ApplyPhysics(character)
+ local deltaTimeMultiplier = 60 -- Target 60FPS
+ character.y_velocity = character.y_velocity + gravity * deltaTime * deltaTimeMultiplier
+ character.y = character.y + character.y_velocity * deltaTime * deltaTimeMultiplier
+ character.x = character.x + character.x_velocity * deltaTime * deltaTimeMultiplier
+ character.x_velocity = character.x_velocity * 0.99
+
+ if character.y_velocity > 0 then
+ -- Falling
+ if IsOnGround(character) then
+ character.y_velocity = 0
+ character.can_jump = true
+ end
+ elseif character.y_velocity < 0 then
+ -- Going upward
+ IsHittingCeiling(character)
+ end
+
+ if not IsOnGround(character) then
+ character.can_jump = false
+ end
+
+ if character.y > HEIGHT + 50 then
+ KillPlayer(character)
+ end
+end
+
+function Update()
+ -- Apply physics
+ ApplyPhysics(player1Character)
+ ApplyPhysics(player2Character)
+
+ -- Render characters
+ queueTextureForRender(player1Character.current_sprite, math.floor(player1Character.x), math.floor(player1Character.y))
+ queueTextureForRender(player2Character.current_sprite, math.floor(player2Character.x), math.floor(player2Character.y))
+
+ -- Environment
DrawGroundTiles()
-- Input
HandleP1Input()
HandleP2Input()
+
+ -- UI
+ DrawUI()
+
+ -- Timer
+ Timer.update(deltaTime)
end