Drop available upgrades after ingredient stack.
***Temporarily*** use timers to defer ingredient spawn This should be more component-y for sure.
This commit is contained in:
parent
f570a4a966
commit
94b391801d
|
@ -310,6 +310,7 @@ end
|
||||||
-- Use an empty table as a key for identifying Systems. Any table that contains
|
-- Use an empty table as a key for identifying Systems. Any table that contains
|
||||||
-- this key is considered a System rather than an Entity.
|
-- this key is considered a System rather than an Entity.
|
||||||
local systemTableKey = { "SYSTEM_TABLE_KEY" }
|
local systemTableKey = { "SYSTEM_TABLE_KEY" }
|
||||||
|
tiny.SKIP_PROCESS = { "SKIP_PROCESS_KEY" }
|
||||||
|
|
||||||
-- Checks if a table is a System.
|
-- Checks if a table is a System.
|
||||||
local function isSystem(table)
|
local function isSystem(table)
|
||||||
|
@ -322,12 +323,12 @@ local function processingSystemUpdate(system, dt)
|
||||||
local process = system.process
|
local process = system.process
|
||||||
local postProcess = system.postProcess
|
local postProcess = system.postProcess
|
||||||
|
|
||||||
local shouldSkipSystemProcess = false
|
local shouldSkipSystemProcess
|
||||||
if preProcess then
|
if preProcess then
|
||||||
shouldSkipSystemProcess = preProcess(system, dt)
|
shouldSkipSystemProcess = preProcess(system, dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
if process and not shouldSkipSystemProcess then
|
if process and shouldSkipSystemProcess ~= tiny.SKIP_PROCESS then
|
||||||
if system.nocache then
|
if system.nocache then
|
||||||
local entities = system.world.entities
|
local entities = system.world.entities
|
||||||
local filter = system.filter
|
local filter = system.filter
|
||||||
|
@ -347,7 +348,7 @@ local function processingSystemUpdate(system, dt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if postProcess and not shouldSkipSystemProcess then
|
if postProcess and shouldSkipSystemProcess ~= tiny.SKIP_PROCESS then
|
||||||
postProcess(system, dt)
|
postProcess(system, dt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -474,6 +475,8 @@ end
|
||||||
--- Adds an Entity to the world.
|
--- Adds an Entity to the world.
|
||||||
-- Also call this on Entities that have changed Components such that they
|
-- Also call this on Entities that have changed Components such that they
|
||||||
-- match different Filters. Returns the Entity.
|
-- match different Filters. Returns the Entity.
|
||||||
|
-- TODO: Track entity age when debugging?
|
||||||
|
-- TODO: Track debugName field when debugging?
|
||||||
function tiny.addEntity(world, entity)
|
function tiny.addEntity(world, entity)
|
||||||
local e2c = world.entitiesToChange
|
local e2c = world.entitiesToChange
|
||||||
e2c[#e2c + 1] = entity
|
e2c[#e2c + 1] = entity
|
||||||
|
|
|
@ -9,8 +9,8 @@ function Cart.reset(o)
|
||||||
y = 50,
|
y = 50,
|
||||||
}
|
}
|
||||||
o.velocity = {
|
o.velocity = {
|
||||||
x = 10 + (150 * math.random()),
|
x = 200 + (100 * math.random()),
|
||||||
y = 150 * (math.random() - 1),
|
y = 175 * (math.random() - 1),
|
||||||
}
|
}
|
||||||
o.size = size
|
o.size = size
|
||||||
o.canBeBounced = {
|
o.canBeBounced = {
|
||||||
|
@ -37,7 +37,6 @@ function Cart.reset(o)
|
||||||
position = { x = self.position.x, y = self.position.y },
|
position = { x = self.position.x, y = self.position.y },
|
||||||
focusPriority = 1,
|
focusPriority = 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return o
|
return o
|
||||||
|
|
|
@ -13,16 +13,10 @@ function Effects.makeFloatier(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Cause the given ingredient to spawn more frequently
|
--- Cause the given ingredient to spawn more frequently
|
||||||
function Effects.moreOfIngredient(ingredient, spawner)
|
function Effects.moreOfIngredient(ingredient, spawner) end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Each of the given ingredient will have a *mult score from now on.
|
--- Each of the given ingredient will have a *mult score from now on.
|
||||||
function Effects.multiplyIngredientValue(ingredient, mult, spawner)
|
function Effects.multiplyIngredientValue(ingredient, mult, spawner) end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Each ingredient *multiplies* score in some way, in addition to adding.
|
--- Each ingredient *multiplies* score in some way, in addition to adding.
|
||||||
function Effects.multiplicativeIngredientValue(ingredient, addedMult, spawner)
|
function Effects.multiplicativeIngredientValue(ingredient, addedMult, spawner) end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -16,11 +16,13 @@ import("systems/collision-detection.lua")
|
||||||
import("systems/collision-resolution.lua")
|
import("systems/collision-resolution.lua")
|
||||||
import("systems/draw.lua")
|
import("systems/draw.lua")
|
||||||
import("systems/gravity.lua")
|
import("systems/gravity.lua")
|
||||||
|
import("systems/move-toward.lua")
|
||||||
import("systems/rounds.lua")
|
import("systems/rounds.lua")
|
||||||
import("systems/spawner.lua")
|
import("systems/spawner.lua")
|
||||||
import("systems/velocity.lua")
|
import("systems/velocity.lua")
|
||||||
import("ingredients/ingredients.lua")
|
import("ingredients/ingredients.lua")
|
||||||
import("cart.lua")
|
import("cart.lua")
|
||||||
|
import("utils.lua")
|
||||||
|
|
||||||
local tiny <const> = tiny
|
local tiny <const> = tiny
|
||||||
local gfx <const> = playdate.graphics
|
local gfx <const> = playdate.graphics
|
||||||
|
@ -58,9 +60,11 @@ end
|
||||||
|
|
||||||
world = tiny.world(
|
world = tiny.world(
|
||||||
fallSystem,
|
fallSystem,
|
||||||
|
moveTowardSystem,
|
||||||
velocitySystem,
|
velocitySystem,
|
||||||
roundSystem,
|
roundSystem,
|
||||||
spawnerSystem,
|
spawnerSystem,
|
||||||
|
expireBelowScreenSystem,
|
||||||
collectedEntities,
|
collectedEntities,
|
||||||
collidingEntities,
|
collidingEntities,
|
||||||
collisionResolution,
|
collisionResolution,
|
||||||
|
@ -68,6 +72,7 @@ world = tiny.world(
|
||||||
cameraPanSystem,
|
cameraPanSystem,
|
||||||
drawRectanglesSystem,
|
drawRectanglesSystem,
|
||||||
drawSpriteSystem,
|
drawSpriteSystem,
|
||||||
|
drawTextSystem,
|
||||||
floor,
|
floor,
|
||||||
cart
|
cart
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,6 +9,8 @@ Camera = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expireBelowScreenSystem = filteredSystem({ position = T.XyPair, expireBelowScreenBy = T.number })
|
||||||
|
|
||||||
cameraPanSystem = filteredSystem({ focusPriority = T.number, position = T.XyPair }, function(e, dt)
|
cameraPanSystem = filteredSystem({ focusPriority = T.number, position = T.XyPair }, function(e, dt)
|
||||||
if e.focusPriority >= focusPriority.priority then
|
if e.focusPriority >= focusPriority.priority then
|
||||||
focusPriority.position = e.position
|
focusPriority.position = e.position
|
||||||
|
@ -24,4 +26,11 @@ function cameraPanSystem:postProcess()
|
||||||
Camera.pan.x = math.max(0, focusPriority.position.x - 200)
|
Camera.pan.x = math.max(0, focusPriority.position.x - 200)
|
||||||
Camera.pan.y = math.min(0, focusPriority.position.y - 120)
|
Camera.pan.y = math.min(0, focusPriority.position.y - 120)
|
||||||
gfx.setDrawOffset(-Camera.pan.x, -Camera.pan.y)
|
gfx.setDrawOffset(-Camera.pan.x, -Camera.pan.y)
|
||||||
|
|
||||||
|
for _, entity in pairs(expireBelowScreenSystem.entities) do
|
||||||
|
if entity.position.y - (Camera.pan.y + 240) > entity.expireBelowScreenBy then
|
||||||
|
print("Entity expired - was too far below screen!")
|
||||||
|
self.world:removeEntity(entity)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ collisionResolution = filteredSystem({ collisionBetween = T.Collision }, functio
|
||||||
position = {
|
position = {
|
||||||
x = collider.position.x,
|
x = collider.position.x,
|
||||||
y = collider.position.y,
|
y = collider.position.y,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,25 +55,5 @@ collisionResolution = filteredSystem({ collisionBetween = T.Collision }, functio
|
||||||
system.world:addEntity({ collected = collidedInto.collectable })
|
system.world:addEntity({ collected = collidedInto.collectable })
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if collidedInto.sparkOnCollision and collider.sparkOnCollision and (math.abs(collider.velocity.x) + math.abs(collider.velocity.y)) > 2 then
|
|
||||||
-- local size = { x = 1, y = 1 }
|
|
||||||
-- local spark = {
|
|
||||||
-- position = {
|
|
||||||
-- x = collider.position.x,
|
|
||||||
-- y = collider.position.y + collider.size.y - 2,
|
|
||||||
-- },
|
|
||||||
-- velocity = {
|
|
||||||
-- x = -collider.velocity.x,
|
|
||||||
-- y = 150,
|
|
||||||
-- },
|
|
||||||
-- size = size,
|
|
||||||
-- canCollideWith = 1,
|
|
||||||
-- mass = 1,
|
|
||||||
-- drawAsSprite = Spark,
|
|
||||||
-- expireAfterCollision = true,
|
|
||||||
-- }
|
|
||||||
-- system.world:addEntity(spark)
|
|
||||||
-- end
|
|
||||||
|
|
||||||
system.world:removeEntity(e)
|
system.world:removeEntity(e)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -4,6 +4,10 @@ drawRectanglesSystem = filteredSystem({ position = T.XyPair, drawAsRectangle = {
|
||||||
gfx.fillRect(e.position.x, e.position.y, e.drawAsRectangle.size.x, e.drawAsRectangle.size.y)
|
gfx.fillRect(e.position.x, e.position.y, e.drawAsRectangle.size.x, e.drawAsRectangle.size.y)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
drawTextSystem = filteredSystem({ position = T.XyPair, drawAsText = { text = T.str } }, function(e, dt)
|
||||||
|
gfx.drawTextAligned(e.drawAsText.text, e.position.x, e.position.y, gfx.kAlignCenter)
|
||||||
|
end)
|
||||||
|
|
||||||
drawSpriteSystem = filteredSystem({ position = T.XyPair, drawAsSprite = T.PdImage }, function(e, dt, system)
|
drawSpriteSystem = filteredSystem({ position = T.XyPair, drawAsSprite = T.PdImage }, function(e, dt, system)
|
||||||
e.drawAsSprite:draw(e.position.x, e.position.y)
|
e.drawAsSprite:draw(e.position.x, e.position.y)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -48,7 +48,7 @@ T = {
|
||||||
---@type RoundStateAction
|
---@type RoundStateAction
|
||||||
RoundStateAction = "start",
|
RoundStateAction = "start",
|
||||||
---@type CanSpawn
|
---@type CanSpawn
|
||||||
CanSpawn = {}
|
CanSpawn = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
---@generic T
|
---@generic T
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
local MoveToward = {
|
||||||
|
target = T.XyPair,
|
||||||
|
range = T.number,
|
||||||
|
speed = T.number,
|
||||||
|
}
|
||||||
|
|
||||||
|
local sqrt, abs = math.sqrt, math.abs
|
||||||
|
|
||||||
|
---@param xy1 XyPair
|
||||||
|
---@param xy2 XyPair
|
||||||
|
local function normalizeVector(xy1, xy2)
|
||||||
|
local x = xy1.x - xy2.x
|
||||||
|
local y = xy1.y - xy2.y
|
||||||
|
local distance = sqrt((x * x) + (y * y))
|
||||||
|
return x / distance, y / distance, distance
|
||||||
|
end
|
||||||
|
|
||||||
|
moveTowardSystem = filteredSystem(
|
||||||
|
{ moveToward = MoveToward, position = T.XyPair },
|
||||||
|
function(e, dt, system)
|
||||||
|
local xNorm, yNorm, distance = normalizeVector(e.position, e.moveToward.target)
|
||||||
|
if distance > e.moveToward.range then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO May be incorrect when signs are mismatched between vel and diff
|
||||||
|
local xVel = xNorm * e.moveToward.speed * dt
|
||||||
|
if abs(e.position.x - e.moveToward.target.x) < abs(xVel) then
|
||||||
|
e.position.x = e.moveToward.target.x
|
||||||
|
else
|
||||||
|
e.position.x = e.position.x + xVel
|
||||||
|
end
|
||||||
|
|
||||||
|
local yVel = yNorm * e.moveToward.speed * dt
|
||||||
|
if abs(e.position.y - e.moveToward.target.y) < abs(yVel) then
|
||||||
|
e.position.y = e.moveToward.target.y
|
||||||
|
else
|
||||||
|
e.position.y = e.position.y + yVel
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
|
@ -1,8 +1,11 @@
|
||||||
collectedEntities = filteredSystem({ collected = T.PdImage })
|
collectedEntities = filteredSystem({ collected = T.PdImage })
|
||||||
|
|
||||||
|
local onCollidingRemove = { "mass", "velocity", "canCollideWith" }
|
||||||
|
|
||||||
roundSystem = filteredSystem({ roundAction = T.RoundStateAction, position = Maybe(T.XyPair) }, function(e, _, system)
|
roundSystem = filteredSystem({ roundAction = T.RoundStateAction, position = Maybe(T.XyPair) }, function(e, _, system)
|
||||||
if e.roundAction == "end" then
|
if e.roundAction == "end" then
|
||||||
playdate.setAutoLockDisabled(false)
|
playdate.setAutoLockDisabled(false)
|
||||||
|
|
||||||
local y = e.position.y - 240
|
local y = e.position.y - 240
|
||||||
local rectWidth = 150
|
local rectWidth = 150
|
||||||
local plateSize = { x = rectWidth, y = 10 }
|
local plateSize = { x = rectWidth, y = 10 }
|
||||||
|
@ -19,25 +22,57 @@ roundSystem = filteredSystem({ roundAction = T.RoundStateAction, position = Mayb
|
||||||
stopMovingOnCollision = true,
|
stopMovingOnCollision = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local delayPerDrop = 150
|
||||||
|
local delay = 0
|
||||||
for i, collectable in ipairs(collectedEntities.entities) do
|
for i, collectable in ipairs(collectedEntities.entities) do
|
||||||
local collX, collY = collectable.collected:getSize()
|
local collX, collY = collectable.collected:getSize()
|
||||||
local onCollidingRemove = {"mass", "velocity", "canCollideWith"}
|
|
||||||
y = y - collY - 15
|
y = y - collY - 15
|
||||||
system.world:addEntity({
|
playdate.timer.new(delay, function(ee, ccollX, ccollY, yy, ii, ssystem, ccollectable)
|
||||||
drawAsSprite = collectable.collected,
|
ssystem.world:addEntity({
|
||||||
size = { x = collX, y = collY / 2 },
|
drawAsSprite = ccollectable.collected,
|
||||||
mass = 0.5,
|
size = { x = ccollX, y = ccollY / 2 },
|
||||||
velocity = { x = 0, y = 0 },
|
mass = 0.5,
|
||||||
position = { x = e.position.x - (collX / 2), y = y },
|
velocity = { x = 0, y = 0 },
|
||||||
canCollideWith = 2,
|
position = { x = ee.position.x - (ccollX / 2), y = yy },
|
||||||
canBeCollidedBy = 2,
|
canCollideWith = 2,
|
||||||
isSolid = true,
|
canBeCollidedBy = 2,
|
||||||
stopMovingOnCollision = true,
|
isSolid = true,
|
||||||
onCollidingRemove = onCollidingRemove,
|
stopMovingOnCollision = true,
|
||||||
focusOnCollide = i,
|
onCollidingRemove = onCollidingRemove,
|
||||||
})
|
focusOnCollide = ii,
|
||||||
|
expireBelowScreenBy = 5,
|
||||||
|
})
|
||||||
|
end, e, collX, collY, y, i, system, collectable)
|
||||||
|
delay = delay + delayPerDrop
|
||||||
system.world:removeEntity(collectable)
|
system.world:removeEntity(collectable)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local availableUpgrades = Utils.getNDifferentValues(getAvailableSpawnerUpgrades(), 3)
|
||||||
|
|
||||||
|
y = y - 50
|
||||||
|
for _, upgrade in ipairs(availableUpgrades) do
|
||||||
|
printTable(upgrade)
|
||||||
|
local collX, collY = 75, 30
|
||||||
|
y = y - collY - 15
|
||||||
|
playdate.timer.new(delay, function(ee, ccollX, ccollY, yy, ii, ssystem, ccollectable)
|
||||||
|
ssystem.world:addEntity({
|
||||||
|
drawAsText = {
|
||||||
|
text = upgrade.name,
|
||||||
|
},
|
||||||
|
size = { x = ccollX, y = ccollY / 2 },
|
||||||
|
mass = 0.5,
|
||||||
|
velocity = { x = 0, y = 0 },
|
||||||
|
position = { x = ee.position.x - (ccollX / 2), y = yy },
|
||||||
|
canCollideWith = 2,
|
||||||
|
canBeCollidedBy = 2,
|
||||||
|
isSolid = true,
|
||||||
|
stopMovingOnCollision = true,
|
||||||
|
onCollidingRemove = onCollidingRemove,
|
||||||
|
focusOnCollide = ii,
|
||||||
|
})
|
||||||
|
end, e, collX, collY, y, i, system, collectable)
|
||||||
|
delay = delay + delayPerDrop
|
||||||
|
end
|
||||||
system.world:removeEntity(e)
|
system.world:removeEntity(e)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -3,7 +3,7 @@ local odds = 0
|
||||||
---@type { canSpawn: CanSpawn }
|
---@type { canSpawn: CanSpawn }
|
||||||
local selectedSpawner
|
local selectedSpawner
|
||||||
|
|
||||||
spawnerSystem = filteredSystem({ canSpawn = T.CanSpawn, odds = T.number }, function(spawner, _, system)
|
spawnerSystem = filteredSystem({ canSpawn = T.CanSpawn, odds = T.number }, function(spawner, _, _)
|
||||||
if odds <= 0 then
|
if odds <= 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -15,22 +15,28 @@ spawnerSystem = filteredSystem({ canSpawn = T.CanSpawn, odds = T.number }, funct
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- process() and postProcess() are skipped when preProcess() returns true
|
--- May cause process() and postProcess() to be skipped
|
||||||
function spawnerSystem:preProcess()
|
function spawnerSystem:preProcess()
|
||||||
local newestX = Ingredients.newestIngredient().position.x
|
local newestX = Ingredients.newestIngredient().position.x
|
||||||
local panX = Camera.pan.x
|
local panX = Camera.pan.x
|
||||||
local rightEdge = panX + 400
|
local rightEdge = panX + 400
|
||||||
|
local totalOdds = 0
|
||||||
|
for _, spawner in pairs(spawnerSystem.entities) do
|
||||||
|
totalOdds = totalOdds + spawner.odds
|
||||||
|
end
|
||||||
|
|
||||||
if newestX < rightEdge + 100 then
|
if newestX < rightEdge + 100 then
|
||||||
odds = math.random()
|
odds = math.random() * totalOdds
|
||||||
selectedSpawner = nil
|
selectedSpawner = nil
|
||||||
return false -- A new ingredient needs spawning!
|
return -- A new ingredient needs spawning!
|
||||||
end
|
end
|
||||||
|
|
||||||
-- We do not need a new ingredient at this time
|
-- We do not need a new ingredient at this time
|
||||||
return true
|
return tiny.SKIP_PROCESS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local spawnEveryX = 26
|
||||||
|
|
||||||
-- Currently spawns AT MOST one new ingredient per frame, which is probably not enough at high speeds!
|
-- Currently spawns AT MOST one new ingredient per frame, which is probably not enough at high speeds!
|
||||||
function spawnerSystem:postProcess()
|
function spawnerSystem:postProcess()
|
||||||
local newestX = Ingredients.newestIngredient().position.x
|
local newestX = Ingredients.newestIngredient().position.x
|
||||||
|
@ -44,7 +50,7 @@ function spawnerSystem:postProcess()
|
||||||
-- TODO: May not need to include lower spawners when we reach higher altitudes.
|
-- TODO: May not need to include lower spawners when we reach higher altitudes.
|
||||||
local panY = math.floor(Camera.pan.y or 0)
|
local panY = math.floor(Camera.pan.y or 0)
|
||||||
local yRange = selectedSpawner.canSpawn.yRange or { top = panY - 240, bottom = panY + 220 }
|
local yRange = selectedSpawner.canSpawn.yRange or { top = panY - 240, bottom = panY + 220 }
|
||||||
newlySpawned.position = { x = newestX + 60, y = math.random(yRange.top, yRange.bottom) }
|
newlySpawned.position = { x = newestX + spawnEveryX, y = math.random(yRange.top, yRange.bottom) }
|
||||||
|
|
||||||
self.world:addEntity(newlySpawned)
|
self.world:addEntity(newlySpawned)
|
||||||
end
|
end
|
||||||
|
@ -58,6 +64,8 @@ function addAllSpawners(world)
|
||||||
local size = { x = sizeX, y = sizeY / 2 }
|
local size = { x = sizeX, y = sizeY / 2 }
|
||||||
|
|
||||||
world:addEntity({
|
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,
|
name = name,
|
||||||
odds = spawnerOdds,
|
odds = spawnerOdds,
|
||||||
canSpawn = {
|
canSpawn = {
|
||||||
|
@ -83,7 +91,7 @@ function addAllSpawners(world)
|
||||||
|
|
||||||
addCollectableSpawner("Tomato", 0.1, 15, TomatoSprite)
|
addCollectableSpawner("Tomato", 0.1, 15, TomatoSprite)
|
||||||
|
|
||||||
addCollectableSpawner("Mushroom", 0.7, 5, MushroomSprite, {
|
addCollectableSpawner("Mushroom", 0.02, 5, MushroomSprite, {
|
||||||
flat = { x = 0, y = 290 },
|
flat = { x = 0, y = 290 },
|
||||||
mult = { x = 1, y = -1 },
|
mult = { x = 1, y = -1 },
|
||||||
}, { top = 219, bottom = 223 })
|
}, { top = 219, bottom = 223 })
|
||||||
|
@ -94,15 +102,41 @@ function addAllSpawners(world)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@alias Upgrade { name: string, apply = fun() }
|
||||||
|
|
||||||
|
---@return Upgrade[]
|
||||||
function getAvailableSpawnerUpgrades()
|
function getAvailableSpawnerUpgrades()
|
||||||
local upgrades = {}
|
local upgrades = {}
|
||||||
for _, spawner in pairs(spawnSystem.entities) do
|
for _, spawner in pairs(spawnerSystem.entities) do
|
||||||
if spawner.hasUpgradeSpeed then
|
if spawner.hasUpgradeSpeed then
|
||||||
upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
|
upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
|
||||||
end
|
end
|
||||||
if spawner.hasUpgradeValue then
|
|
||||||
upgrades[#upgrades + 1] = { hasUpgradeValue = spawner.hasUpgradeValue }
|
if spawner.canSpawn.entity.score then
|
||||||
|
upgrades[#upgrades + 1] = {
|
||||||
|
name = "Double " .. spawner.name .. " value",
|
||||||
|
apply = function()
|
||||||
|
spawner.canSpawn.entity.score = spawner.canSpawn.entity.score * 2
|
||||||
|
end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
assert(spawner.odds, "Expected all spawners to have an `odds` field!")
|
||||||
|
upgrades[#upgrades + 1] = {
|
||||||
|
name = "Double " .. spawner.name .. " frequency",
|
||||||
|
apply = function()
|
||||||
|
spawner.odds = spawner.odds * 2
|
||||||
|
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
|
end
|
||||||
return upgrades
|
return upgrades
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
Utils = {}
|
||||||
|
|
||||||
|
--- Returns up to `n` random values from the given array. Will return fewer if `n > #fromArr`
|
||||||
|
---@generic T
|
||||||
|
---@param fromArr T[]
|
||||||
|
---@param n number
|
||||||
|
---@generic T[]
|
||||||
|
function Utils.getNDifferentValues(fromArr, n)
|
||||||
|
assert(n >= 0, "n must be a non-negative integer")
|
||||||
|
if n > #fromArr then
|
||||||
|
n = #fromArr
|
||||||
|
end
|
||||||
|
local found = 0
|
||||||
|
local indexes = {}
|
||||||
|
while found < n do
|
||||||
|
local randomIndex = math.random(#fromArr)
|
||||||
|
if not indexes[randomIndex] then
|
||||||
|
found = found + 1
|
||||||
|
indexes[randomIndex] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local randoms = {}
|
||||||
|
for i in pairs(indexes) do
|
||||||
|
randoms[#randoms + 1] = fromArr[i]
|
||||||
|
end
|
||||||
|
return randoms
|
||||||
|
end
|
Loading…
Reference in New Issue