4
0
This commit is contained in:
Zsolt Tasnadi
2025-12-04 15:04:13 +01:00
parent 007b4243ac
commit 944a493fef

View File

@@ -67,6 +67,7 @@ local POWERUP_SPAWN_CHANCE = 0.3
local Input = {} local Input = {}
local Map = {} local Map = {}
local Powerup = {}
local UI = {} local UI = {}
local TopBar = {} local TopBar = {}
local Splash = {} local Splash = {}
@@ -137,7 +138,11 @@ local POWERUP_TYPES = {
}, },
} }
local function get_powerup_config(type_name) --------------------------------------------------------------------------------
-- Powerup module
--------------------------------------------------------------------------------
function Powerup.get_config(type_name)
for _, p in ipairs(POWERUP_TYPES) do for _, p in ipairs(POWERUP_TYPES) do
if p.type == type_name then if p.type == type_name then
return p return p
@@ -146,7 +151,7 @@ local function get_powerup_config(type_name)
return POWERUP_TYPES[1] return POWERUP_TYPES[1]
end end
local function get_random_powerup_type() function Powerup.get_random_type()
local total_weight = 0 local total_weight = 0
for _, p in ipairs(POWERUP_TYPES) do for _, p in ipairs(POWERUP_TYPES) do
total_weight = total_weight + p.weight total_weight = total_weight + p.weight
@@ -162,6 +167,45 @@ local function get_random_powerup_type()
return POWERUP_TYPES[1].type return POWERUP_TYPES[1].type
end end
function Powerup.init()
State.powerups = {}
for row = 1, MAP_HEIGHT do
for col = 1, MAP_WIDTH do
if State.map[row][col] == BREAKABLE_WALL and math.random() < POWERUP_SPAWN_CHANCE then
table.insert(State.powerups, {gridX = col, gridY = row, type = Powerup.get_random_type()})
end
end
end
end
function Powerup.draw_all()
for _, pw in ipairs(State.powerups) do
if State.map[pw.gridY][pw.gridX] == EMPTY then
local drawX = (pw.gridX - 1) * TILE_SIZE
local drawY = (pw.gridY - 1) * TILE_SIZE
local config = Powerup.get_config(pw.type)
rect(drawX + 5, drawY + 5, 10, 10, COLOR_SHADOW)
rect(drawX + 3, drawY + 3, 10, 10, config.color)
print(config.label, drawX + 5, drawY + 5, COLOR_BLACK)
end
end
end
function Powerup.check_pickup()
for _, player in ipairs(State.players) do
for i = #State.powerups, 1, -1 do
local pw = State.powerups[i]
if State.map[pw.gridY][pw.gridX] == EMPTY and
player.gridX == pw.gridX and player.gridY == pw.gridY then
local config = Powerup.get_config(pw.type)
config.apply(player)
table.remove(State.powerups, i)
sfx(1, nil, 8)
end
end
end
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Input module -- Input module
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@@ -241,21 +285,38 @@ function Map.can_move_to(gridX, gridY, player)
return true return true
end end
function Map.init_powerups() function Map.reset()
State.powerups = {}
for row = 1, MAP_HEIGHT do for row = 1, MAP_HEIGHT do
for col = 1, MAP_WIDTH do for col = 1, MAP_WIDTH do
if State.map[row][col] == BREAKABLE_WALL and math.random() < POWERUP_SPAWN_CHANCE then State.map[row][col] = State.initial_map[row][col]
table.insert(State.powerups, {gridX = col, gridY = row, type = get_random_powerup_type()}) end
end
end
function Map.draw_shadows()
for row = 1, MAP_HEIGHT do
for col = 1, MAP_WIDTH do
local tile = State.map[row][col]
if tile == SOLID_WALL or tile == BREAKABLE_WALL then
local drawX = (col - 1) * TILE_SIZE
local drawY = (row - 1) * TILE_SIZE
rect(drawX + 2, drawY + 2, TILE_SIZE, TILE_SIZE, COLOR_SHADOW)
end end
end end
end end
end end
function Map.reset() function Map.draw_tiles()
for row = 1, MAP_HEIGHT do for row = 1, MAP_HEIGHT do
for col = 1, MAP_WIDTH do for col = 1, MAP_WIDTH do
State.map[row][col] = State.initial_map[row][col] local tile = State.map[row][col]
local drawX = (col - 1) * TILE_SIZE
local drawY = (row - 1) * TILE_SIZE
if tile == SOLID_WALL then
spr(SOLID_WALL_SPRITE, drawX, drawY, 0, 2)
elseif tile == BREAKABLE_WALL then
spr(BREAKABLE_WALL_SPRITE, drawX, drawY, 0, 2)
end
end end
end end
end end
@@ -372,62 +433,11 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function GameBoard.draw() function GameBoard.draw()
-- draw wall shadows first Map.draw_shadows()
for row = 1, MAP_HEIGHT do Bomb.draw_explosions()
for col = 1, MAP_WIDTH do Map.draw_tiles()
local tile = State.map[row][col] Powerup.draw_all()
if tile == SOLID_WALL or tile == BREAKABLE_WALL then Bomb.draw_all()
local drawX = (col - 1) * TILE_SIZE
local drawY = (row - 1) * TILE_SIZE
rect(drawX + 2, drawY + 2, TILE_SIZE, TILE_SIZE, COLOR_SHADOW)
end
end
end
-- draw explosions (after shadows, before walls)
for _, expl in ipairs(State.explosions) do
if expl.spread <= 0 then
rect(expl.x, expl.y, TILE_SIZE, TILE_SIZE, COLOR_RED)
else
local progress = 1 - (expl.spread / (expl.dist * SPREAD_DELAY))
if progress > 0 then
local size = math.floor(TILE_SIZE * progress)
local offset = math.floor((TILE_SIZE - size) / 2)
rect(expl.x + offset, expl.y + offset, size, size, COLOR_RED)
end
end
end
-- draw map tiles
for row = 1, MAP_HEIGHT do
for col = 1, MAP_WIDTH do
local tile = State.map[row][col]
local drawX = (col - 1) * TILE_SIZE
local drawY = (row - 1) * TILE_SIZE
if tile == SOLID_WALL then
spr(SOLID_WALL_SPRITE, drawX, drawY, 0, 2)
elseif tile == BREAKABLE_WALL then
spr(BREAKABLE_WALL_SPRITE, drawX, drawY, 0, 2)
end
end
end
-- draw powerups
for _, pw in ipairs(State.powerups) do
if State.map[pw.gridY][pw.gridX] == EMPTY then
local drawX = (pw.gridX - 1) * TILE_SIZE
local drawY = (pw.gridY - 1) * TILE_SIZE
local config = get_powerup_config(pw.type)
rect(drawX + 5, drawY + 5, 10, 10, COLOR_SHADOW)
rect(drawX + 3, drawY + 3, 10, 10, config.color)
print(config.label, drawX + 5, drawY + 5, COLOR_BLACK)
end
end
-- draw bombs
for _, bomb in ipairs(State.bombs) do
Bomb.draw(bomb.x, bomb.y)
end
-- draw players -- draw players
for idx, player in ipairs(State.players) do for idx, player in ipairs(State.players) do
@@ -445,6 +455,27 @@ function Bomb.draw(x, y)
spr(BOMB_SPRITE, x, y, 0, 2) spr(BOMB_SPRITE, x, y, 0, 2)
end end
function Bomb.draw_all()
for _, bomb in ipairs(State.bombs) do
Bomb.draw(bomb.x, bomb.y)
end
end
function Bomb.draw_explosions()
for _, expl in ipairs(State.explosions) do
if expl.spread <= 0 then
rect(expl.x, expl.y, TILE_SIZE, TILE_SIZE, COLOR_RED)
else
local progress = 1 - (expl.spread / (expl.dist * SPREAD_DELAY))
if progress > 0 then
local size = math.floor(TILE_SIZE * progress)
local offset = math.floor((TILE_SIZE - size) / 2)
rect(expl.x + offset, expl.y + offset, size, size, COLOR_RED)
end
end
end
end
function Bomb.place(player) function Bomb.place(player)
if player.activeBombs >= player.maxBombs then return end if player.activeBombs >= player.maxBombs then return end
@@ -890,17 +921,17 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function Game.init() function Game.init()
State.winner = nil
State.win_timer = 0
Bomb.clear_all()
Map.reset()
State.players = {} State.players = {}
table.insert(State.players, Player.create(2, 2, COLOR_BLUE, false)) table.insert(State.players, Player.create(2, 2, COLOR_BLUE, false))
local p2_is_ai = not State.two_player_mode local p2_is_ai = not State.two_player_mode
table.insert(State.players, Player.create(14, 8, COLOR_RED, p2_is_ai)) table.insert(State.players, Player.create(14, 8, COLOR_RED, p2_is_ai))
Map.init_powerups()
end
function Game.set_winner(player_num) Powerup.init()
State.winner = player_num
State.win_timer = WIN_SCREEN_DURATION
State.score[player_num] = State.score[player_num] + 1
end end
function Game.restart() function Game.restart()
@@ -912,22 +943,14 @@ function Game.restart()
for _, p in ipairs(State.players) do for _, p in ipairs(State.players) do
Player.reset(p) Player.reset(p)
end end
Map.init_powerups()
Powerup.init()
end end
function Game.check_powerup_pickup() function Game.set_winner(player_num)
for _, player in ipairs(State.players) do State.winner = player_num
for i = #State.powerups, 1, -1 do State.win_timer = WIN_SCREEN_DURATION
local pw = State.powerups[i] State.score[player_num] = State.score[player_num] + 1
if State.map[pw.gridY][pw.gridX] == EMPTY and
player.gridX == pw.gridX and player.gridY == pw.gridY then
local config = get_powerup_config(pw.type)
config.apply(player)
table.remove(State.powerups, i)
sfx(1, nil, 8)
end
end
end
end end
function Game.check_death_by_explosion() function Game.check_death_by_explosion()
@@ -960,6 +983,30 @@ function Game.check_death_by_collision()
return false return false
end end
function Game.update()
-- Get human player as target for AI
local human_player = State.players[1]
-- update all players
for idx, player in ipairs(State.players) do
Player.update_movement(player)
if player.is_ai then
AI.update(player, human_player)
elseif idx == 1 then
Player.handle_input(player)
else
Player.handle_input_p2(player)
end
end
Bomb.update_all()
Powerup.check_pickup()
if Game.check_death_by_explosion() then return true end
if Game.check_death_by_collision() then return true end
return false
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Main game loop -- Main game loop
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@@ -985,26 +1032,7 @@ function TIC()
return return
end end
-- Get human player as target for AI if Game.update() then return end
local human_player = State.players[1]
-- update all players
for idx, player in ipairs(State.players) do
Player.update_movement(player)
if player.is_ai then
AI.update(player, human_player)
elseif idx == 1 then
Player.handle_input(player)
else
Player.handle_input_p2(player)
end
end
Bomb.update_all()
Game.check_powerup_pickup()
if Game.check_death_by_explosion() then return end
if Game.check_death_by_collision() then return end
GameBoard.draw() GameBoard.draw()
end end