148 lines
4.8 KiB
Lua
148 lines
4.8 KiB
Lua
local odds = 0
|
|
|
|
---@type { canSpawn: CanSpawn }
|
|
local selectedSpawner
|
|
|
|
spawnerSystem = filteredSystem("spawner", { canSpawn = T.CanSpawn, odds = T.number }, function(spawner, _, _)
|
|
if odds <= 0 then
|
|
return
|
|
end
|
|
odds = odds - spawner.odds
|
|
if odds <= 0 then
|
|
selectedSpawner = spawner
|
|
else
|
|
selectedSpawner = selectedSpawner or spawner
|
|
end
|
|
end)
|
|
|
|
--- May cause process() and postProcess() to be skipped
|
|
function spawnerSystem:preProcess()
|
|
local newestX = Ingredients.newestIngredient().position.x
|
|
local panX = Camera.pan.x
|
|
local rightEdge = panX + 400
|
|
local totalOdds = 0
|
|
for _, spawner in pairs(spawnerSystem.entities) do
|
|
totalOdds = totalOdds + spawner.odds
|
|
end
|
|
|
|
if newestX < rightEdge + 100 then
|
|
odds = math.random() * totalOdds
|
|
selectedSpawner = nil
|
|
return -- A new ingredient needs spawning!
|
|
end
|
|
|
|
-- We do not need a new ingredient at this time
|
|
return tiny.SKIP_PROCESS
|
|
end
|
|
|
|
local spawnEveryX = 30
|
|
|
|
-- Currently spawns AT MOST one new ingredient per frame, which is probably not enough at high speeds!
|
|
function spawnerSystem:postProcess()
|
|
local newestX = Ingredients.newestIngredient().position.x
|
|
local newlySpawned = Ingredients.nextInCache()
|
|
|
|
-- TODO: If performance becomes an issue, maybe just swap out __index
|
|
for k, v in pairs(selectedSpawner.canSpawn.entity) do
|
|
newlySpawned[k] = v
|
|
end
|
|
|
|
-- TODO: May not need to include lower spawners when we reach higher altitudes.
|
|
local panY = math.floor(Camera.pan.y or 0)
|
|
local yRange = selectedSpawner.canSpawn.yRange or { top = panY - 240, bottom = panY + 220 }
|
|
newlySpawned.position = { x = newestX + spawnEveryX, y = math.random(yRange.top, yRange.bottom) }
|
|
|
|
self.world:addEntity(newlySpawned)
|
|
end
|
|
|
|
---@param world World
|
|
function addAllSpawners(world)
|
|
function addCollectableSpawner(name, spawnerOdds, score, sprite, canBounce, yRange)
|
|
local sizeX, sizeY = sprite:getSize()
|
|
local size = { x = sizeX, y = sizeY / 2 }
|
|
|
|
world:addEntity({
|
|
-- NOTE: This name should NOT be used to identify the spawner.
|
|
-- It should only be used to supply visual information when searching for available upgrades.
|
|
name = name,
|
|
odds = spawnerOdds,
|
|
canSpawn = {
|
|
yRange = yRange,
|
|
entity = {
|
|
score = score,
|
|
canBeCollidedBy = 1,
|
|
expireAfterCollision = true,
|
|
size = size,
|
|
drawAsSprite = sprite,
|
|
collectable = sprite,
|
|
expireWhenOffScreenBy = expireWhenOffScreenBy,
|
|
disableCollisionWhenRoundEnds = T.marker,
|
|
canBounce = canBounce,
|
|
},
|
|
},
|
|
})
|
|
end
|
|
|
|
addCollectableSpawner("Lettuce", 0.7, 1, LettuceSprite, {
|
|
flat = { x = 12, y = 220 },
|
|
mult = { x = 1, y = -0.5 },
|
|
})
|
|
|
|
addCollectableSpawner("Tomato", 0.1, 15, TomatoSprite)
|
|
|
|
addCollectableSpawner("Mushroom", 0.02, 5, MushroomSprite, {
|
|
flat = { x = 0, y = 290 },
|
|
mult = { x = 1, y = -1 },
|
|
}, { top = 219, bottom = 223 })
|
|
|
|
addCollectableSpawner("Cheese", 0.05, 1, CheeseSprite, {
|
|
flat = { x = 50, y = 390 },
|
|
mult = { x = 0.7, y = -0.5 },
|
|
})
|
|
end
|
|
|
|
---@alias Upgrade { name: string, apply = fun() }
|
|
|
|
---@return Upgrade[]
|
|
function getAvailableSpawnerUpgrades()
|
|
local upgrades = {}
|
|
for _, spawner in pairs(spawnerSystem.entities) do
|
|
if spawner.hasUpgradeSpeed then
|
|
-- upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
|
|
end
|
|
|
|
if spawner.canSpawn.entity.score then
|
|
local name = "Double " .. spawner.name .. " value"
|
|
upgrades[#upgrades + 1] = {
|
|
name = name,
|
|
apply = function(world)
|
|
print("Applying " .. name)
|
|
spawner.canSpawn.entity.score = spawner.canSpawn.entity.score * 2
|
|
world:addEntity({ roundAction = "start" })
|
|
end,
|
|
}
|
|
end
|
|
|
|
assert(spawner.odds, "Expected all spawners to have an `odds` field!")
|
|
local name = "Double " .. spawner.name .. " frequency"
|
|
upgrades[#upgrades + 1] = {
|
|
name = name,
|
|
apply = function(world)
|
|
print("Applying " .. name)
|
|
spawner.odds = spawner.odds * 2
|
|
world:addEntity({ roundAction = "start" })
|
|
end,
|
|
}
|
|
|
|
-- if not spawner.canSpawn.entity.velocity then
|
|
-- upgrades[#upgrades + 1] = {
|
|
-- name = spawner.name .. " Movement",
|
|
-- upgrade = function()
|
|
-- spawner.canSpawn.entity.velocity = { x = -10, y = 0 }
|
|
-- end,
|
|
-- }
|
|
-- end
|
|
end
|
|
return upgrades
|
|
end
|