Click-to-place somewhat working.

This is a 65% decent stopping point before I completely hose it trying to animate the ball.
This commit is contained in:
Sage Vaillancourt 2025-03-18 14:35:51 -04:00
parent a2d796900f
commit 359ebab56a
15 changed files with 642 additions and 120 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 B

After

Width:  |  Height:  |  Size: 569 B

BIN
assets/images/GolferUp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

View File

@ -9,6 +9,14 @@ Ball = love.graphics.newImage("assets/images/Ball.png")
---@type love.Texture
Flag = love.graphics.newImage("assets/images/Flag.png")
-- luacheck: ignore
---@type love.Texture
GolferDown = love.graphics.newImage("assets/images/GolferDown.png")
-- luacheck: ignore
---@type love.Texture
GolferLeft = love.graphics.newImage("assets/images/GolferLeft.png")
-- luacheck: ignore
---@type love.Texture
GolferRightActivated = love.graphics.newImage("assets/images/GolferRightActivated.png")
@ -17,6 +25,10 @@ GolferRightActivated = love.graphics.newImage("assets/images/GolferRightActivate
---@type love.Texture
GolferRight = love.graphics.newImage("assets/images/GolferRight.png")
-- luacheck: ignore
---@type love.Texture
GolferUp = love.graphics.newImage("assets/images/GolferUp.png")
-- luacheck: ignore
---@type love.Texture
Grass = love.graphics.newImage("assets/images/Grass.png")

367
lib/inspect.lua Normal file
View File

@ -0,0 +1,367 @@
local _tl_compat
if (tonumber((_VERSION or ""):match("[%d.]*$")) or 0) < 5.3 then
local p, m = pcall(require, "compat53.module")
if p then
_tl_compat = m
end
end
local math = _tl_compat and _tl_compat.math or math
local string = _tl_compat and _tl_compat.string or string
local table = _tl_compat and _tl_compat.table or table
local inspect = { Options = {} }
inspect._VERSION = "inspect.lua 3.1.0"
inspect._URL = "http://github.com/kikito/inspect.lua"
inspect._DESCRIPTION = "human-readable representations of tables"
inspect._LICENSE = [[
MIT LICENSE
Copyright (c) 2022 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
inspect.KEY = setmetatable({}, {
__tostring = function()
return "inspect.KEY"
end,
})
inspect.METATABLE = setmetatable({}, {
__tostring = function()
return "inspect.METATABLE"
end,
})
local tostring = tostring
local rep = string.rep
local match = string.match
local char = string.char
local gsub = string.gsub
local fmt = string.format
local _rawget
if rawget then
_rawget = rawget
else
_rawget = function(t, k)
return t[k]
end
end
local function rawpairs(t)
return next, t, nil
end
local function smartQuote(str)
if match(str, '"') and not match(str, "'") then
return "'" .. str .. "'"
end
return '"' .. gsub(str, '"', '\\"') .. '"'
end
local shortControlCharEscapes = {
["\a"] = "\\a",
["\b"] = "\\b",
["\f"] = "\\f",
["\n"] = "\\n",
["\r"] = "\\r",
["\t"] = "\\t",
["\v"] = "\\v",
["\127"] = "\\127",
}
local longControlCharEscapes = { ["\127"] = "\127" }
for i = 0, 31 do
local ch = char(i)
if not shortControlCharEscapes[ch] then
shortControlCharEscapes[ch] = "\\" .. i
longControlCharEscapes[ch] = fmt("\\%03d", i)
end
end
local function escape(str)
return (gsub(gsub(gsub(str, "\\", "\\\\"), "(%c)%f[0-9]", longControlCharEscapes), "%c", shortControlCharEscapes))
end
local luaKeywords = {
["and"] = true,
["break"] = true,
["do"] = true,
["else"] = true,
["elseif"] = true,
["end"] = true,
["false"] = true,
["for"] = true,
["function"] = true,
["goto"] = true,
["if"] = true,
["in"] = true,
["local"] = true,
["nil"] = true,
["not"] = true,
["or"] = true,
["repeat"] = true,
["return"] = true,
["then"] = true,
["true"] = true,
["until"] = true,
["while"] = true,
}
local function isIdentifier(str)
return type(str) == "string" and not not str:match("^[_%a][_%a%d]*$") and not luaKeywords[str]
end
local flr = math.floor
local function isSequenceKey(k, sequenceLength)
return type(k) == "number" and flr(k) == k and 1 <= k and k <= sequenceLength
end
local defaultTypeOrders = {
["number"] = 1,
["boolean"] = 2,
["string"] = 3,
["table"] = 4,
["function"] = 5,
["userdata"] = 6,
["thread"] = 7,
}
local function sortKeys(a, b)
local ta, tb = type(a), type(b)
if ta == tb and (ta == "string" or ta == "number") then
return a < b
end
local dta = defaultTypeOrders[ta] or 100
local dtb = defaultTypeOrders[tb] or 100
return dta == dtb and ta < tb or dta < dtb
end
local function getKeys(t)
local seqLen = 1
while _rawget(t, seqLen) ~= nil do
seqLen = seqLen + 1
end
seqLen = seqLen - 1
local keys, keysLen = {}, 0
for k in rawpairs(t) do
if not isSequenceKey(k, seqLen) then
keysLen = keysLen + 1
keys[keysLen] = k
end
end
table.sort(keys, sortKeys)
return keys, keysLen, seqLen
end
local function countCycles(x, cycles)
if type(x) == "table" then
if cycles[x] then
cycles[x] = cycles[x] + 1
else
cycles[x] = 1
for k, v in rawpairs(x) do
countCycles(k, cycles)
countCycles(v, cycles)
end
countCycles(getmetatable(x), cycles)
end
end
end
local function makePath(path, a, b)
local newPath = {}
local len = #path
for i = 1, len do
newPath[i] = path[i]
end
newPath[len + 1] = a
newPath[len + 2] = b
return newPath
end
local function processRecursive(process, item, path, visited)
if item == nil then
return nil
end
if visited[item] then
return visited[item]
end
local processed = process(item, path)
if type(processed) == "table" then
local processedCopy = {}
visited[item] = processedCopy
local processedKey
for k, v in rawpairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end
end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
if type(mt) ~= "table" then
mt = nil
end
setmetatable(processedCopy, mt)
processed = processedCopy
end
return processed
end
local function puts(buf, str)
buf.n = buf.n + 1
buf[buf.n] = str
end
local Inspector = {}
local Inspector_mt = { __index = Inspector }
local function tabify(inspector)
puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
end
function Inspector:getId(v)
local id = self.ids[v]
local ids = self.ids
if not id then
local tv = type(v)
id = (ids[tv] or 0) + 1
ids[v], ids[tv] = id, id
end
return tostring(id)
end
function Inspector:putValue(v)
local buf = self.buf
local tv = type(v)
if tv == "string" then
puts(buf, smartQuote(escape(v)))
elseif tv == "number" or tv == "boolean" or tv == "nil" or tv == "cdata" or tv == "ctype" then
puts(buf, tostring(v))
elseif tv == "table" and not self.ids[v] then
local t = v
if t == inspect.KEY or t == inspect.METATABLE then
puts(buf, tostring(t))
elseif self.level >= self.depth then
puts(buf, "{...}")
else
if self.cycles[t] > 1 then
puts(buf, fmt("<%d>", self:getId(t)))
end
local keys, keysLen, seqLen = getKeys(t)
puts(buf, "{")
self.level = self.level + 1
for i = 1, seqLen + keysLen do
if i > 1 then
puts(buf, ",")
end
if i <= seqLen then
puts(buf, " ")
self:putValue(t[i])
else
local k = keys[i - seqLen]
tabify(self)
if isIdentifier(k) then
puts(buf, k)
else
puts(buf, "[")
self:putValue(k)
puts(buf, "]")
end
puts(buf, " = ")
self:putValue(t[k])
end
end
local mt = getmetatable(t)
if type(mt) == "table" then
if seqLen + keysLen > 0 then
puts(buf, ",")
end
tabify(self)
puts(buf, "<metatable> = ")
self:putValue(mt)
end
self.level = self.level - 1
if keysLen > 0 or type(mt) == "table" then
tabify(self)
elseif seqLen > 0 then
puts(buf, " ")
end
puts(buf, "}")
end
else
puts(buf, fmt("<%s %d>", tv, self:getId(v)))
end
end
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
local newline = options.newline or "\n"
local indent = options.indent or " "
local process = options.process
if process then
root = processRecursive(process, root, {}, {})
end
local cycles = {}
countCycles(root, cycles)
local inspector = setmetatable({
buf = { n = 0 },
ids = {},
cycles = cycles,
depth = depth,
level = 0,
newline = newline,
indent = indent,
}, Inspector_mt)
inspector:putValue(root)
return table.concat(inspector.buf)
end
setmetatable(inspect, {
__call = function(_, root, options)
return inspect.inspect(root, options)
end,
})
_G.Inspect = inspect
return inspect

View File

@ -609,9 +609,8 @@ function M.adjust_err_msg_with_iter(err_msg, iter_msg)
end
if
(err_msg:find(M.SKIP_PREFIX) == 1) or (
err_msg:match("(" .. RE_FILE_LINE .. ")" .. M.SKIP_PREFIX .. ".*") ~= nil
)
(err_msg:find(M.SKIP_PREFIX) == 1)
or (err_msg:match("(" .. RE_FILE_LINE .. ")" .. M.SKIP_PREFIX .. ".*") ~= nil)
then
-- substitute prefix by iteration message
err_msg = err_msg:gsub(".*" .. M.SKIP_PREFIX, iter_msg, 1)

View File

@ -1495,9 +1495,10 @@ local unpack = (_VERSION >= "Lua 5.2") and table.unpack or _G.unpack
--[[local]]
loadLuaString = (
(_VERSION >= "Lua 5.2" or jit) and function(lua, chunkName, env)
return load(lua, chunkName, "bt", env)
end
(_VERSION >= "Lua 5.2" or jit)
and function(lua, chunkName, env)
return load(lua, chunkName, "bt", env)
end
or function(lua, chunkName, env)
local chunk, err = loadstring(lua, chunkName)
if not chunk then
@ -2811,20 +2812,26 @@ local function doEarlyExpansions(tokensToExpand, stats)
outTokens,
newTokenAt({ type = "pp_entry", value = "!!", representation = "!!", double = true }, ppSymbolTok)
)
tableInsert(outTokens, newTokenAt({
type = "punctuation",
value = "(",
representation = "(",
}, ppSymbolTok))
tableInsert(
outTokens,
newTokenAt({
type = "punctuation",
value = "(",
representation = "(",
}, ppSymbolTok)
)
tableInsert(
outTokens,
newTokenAt({ type = "identifier", value = "__EVAL", representation = "__EVAL" }, ppSymbolTok)
)
tableInsert(outTokens, newTokenAt({
type = "punctuation",
value = "(",
representation = "(",
}, ppSymbolTok))
tableInsert(
outTokens,
newTokenAt({
type = "punctuation",
value = "(",
representation = "(",
}, ppSymbolTok)
)
tableInsert(
outTokens,
newTokenAt(
@ -2832,16 +2839,22 @@ local function doEarlyExpansions(tokensToExpand, stats)
ppSymbolTok
)
)
tableInsert(outTokens, newTokenAt({
type = "punctuation",
value = ")",
representation = ")",
}, ppSymbolTok))
tableInsert(outTokens, newTokenAt({
type = "punctuation",
value = ")",
representation = ")",
}, ppSymbolTok))
tableInsert(
outTokens,
newTokenAt({
type = "punctuation",
value = ")",
representation = ")",
}, ppSymbolTok)
)
tableInsert(
outTokens,
newTokenAt({
type = "punctuation",
value = ")",
representation = ")",
}, ppSymbolTok)
)
-- Anything else.
else

View File

@ -29,11 +29,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---@field index number is the System's index in the World. Lower indexed Systems are processed before higher indices. The index is a read only field; to set the index, use tiny.setSystemIndex(world, system).
---@field indices table<any, any> field is a table of Entity keys to their indices in the entities list. Most Systems can ignore this.
---@field modified boolean indicator for if the System has been modified in the last update. If so, the onModify callback will be called on the System in the next update, if it has one. This is usually managed by tiny-ecs, so users should mostly ignore this, too.
---@field preProcess nil | fun(self, dt: number): nil | table
---@field postProcess nil | fun(self, dt: number)
---@field isDrawSystem nil | boolean
--- @module tiny-ecs
-- @author Calvin Rose
-- @license MIT
-- @copyright 2016
--- @author Calvin Rose
--- @license MIT
--- @copyright 2016
local tiny = {}
-- Local versions of standard lua functions

View File

@ -1,5 +1,6 @@
require("tiny-debug")
tiny = require("lib/tiny")
require("lib/inspect")
require("utils")
require("tiny-tools")
@ -11,22 +12,22 @@ require("generated/all-systems")
local width, height = love.graphics.getWidth(), love.graphics.getHeight()
local squareSize = 80
local tileSize = math.floor(squareSize * 1.2)
local squareSide = 80
local tileSize = math.floor(squareSide * 1.2)
local marginSize = 10
local squareSize = { x = squareSide, y = squareSide }
CursorMask = 1
BallMask = 2
local function emptyTile(unhighlightSiblings, gridPosition)
local size = { x = squareSize, y = squareSize }
return {
unhighlightSiblings = unhighlightSiblings,
canBeCollidedBy = CursorMask,
highlightOnMouseOver = T.marker,
size = size,
size = squareSize,
gridPosition = gridPosition,
drawAsRectangle = { size = size },
drawAsRectangle = { size = squareSize },
}
end
@ -34,6 +35,8 @@ local function replaceAt(grid, y, x, entity)
local current = grid[y][x]
grid[y][x] = entity
current.highlighted = nil
entity.parentGrid = grid
current.unhighlightSiblings[entity] = true
current.unhighlightSiblings[current] = nil
entity.unhighlightSiblings = current.unhighlightSiblings
@ -50,10 +53,15 @@ local function replaceAt(grid, y, x, entity)
current.above.below = current.below
current.below.above = current.above
-- print("replacement: " .. Inspect(entity, { depth = 1 }))
World:removeEntity(current)
World:addEntity(entity)
end
function Replace(toReplace, replacement)
replaceAt(toReplace.parentGrid, toReplace.gridPosition.y, toReplace.gridPosition.x, replacement)
end
function PositionAtGridXy(x, y)
return {
x = 20 + ((x - 1) * tileSize),
@ -68,13 +76,14 @@ Scenarios = {
World:addEntity({
size = cursorSize,
moveWithCursor = T.marker,
isCursor = T.marker,
canCollideWith = bit.bor(CursorMask, BallMask),
position = { x = -999, y = -999 },
highlightsCollided = T.marker,
drawAsRectangle = {
size = cursorSize,
mode = "fill",
},
-- drawAsRectangle = {
-- size = cursorSize,
-- mode = "fill",
-- },
})
World:addEntity({
position = { x = 0, y = 0 },
@ -85,6 +94,7 @@ Scenarios = {
-- Temporary storages for connecting grid items
local previous
local unhighlightSiblings = {}
local yxGrid = {}
local xCount = 8
@ -94,6 +104,7 @@ Scenarios = {
yxGrid[y] = {}
for x = 1, xCount do
local current = World:addEntity(emptyTile(unhighlightSiblings, { x = x, y = y }))
current.parentGrid = yxGrid
yxGrid[y][x] = current
unhighlightSiblings[current] = true
current.toLeft = previous
@ -132,7 +143,8 @@ Scenarios = {
z = 1,
effectsToApply = {
endOfRound = T.marker,
}
movement = { x = 0, y = 0 },
},
})
replaceAt(yxGrid, 2, 2, {
drawAsSprite = SmallSandTrap,
@ -140,26 +152,32 @@ Scenarios = {
spriteAfterEffect = SmallSandTrapActivated,
effectsToApply = {
slowsBy = { x = 1, y = 1 },
movement = { x = 0, y = 0, },
movement = { x = 0, y = 0 },
},
})
replaceAt(yxGrid, 1, 1, {
World:addEntity({
canBeCollidedBy = CursorMask,
pickedUpOnClick = T.marker,
size = squareSize,
drawAsSprite = GolferRight,
z = 1,
spriteAfterEffect = GolferRightActivated,
effectsToApply = {
movement = { x = 6, y = 0, },
movement = { x = 99, y = 0 },
},
position = { x = 20, y = height - 80 },
})
replaceAt(yxGrid, 1, 7, {
World:addEntity({
canBeCollidedBy = CursorMask,
pickedUpOnClick = T.marker,
drawAsSprite = GolferRight,
size = squareSize,
drawAsSprite = GolferDown,
z = 1,
spriteAfterEffect = GolferRightActivated,
effectsToApply = {
movement = { x = 0, y = 3 },
movement = { x = 0, y = 99 },
},
position = { x = 20 + squareSide, y = height - 80 },
})
World:addEntity({
ballEffects = {},
@ -167,10 +185,15 @@ Scenarios = {
gridPosition = { x = 1, y = 1 },
z = 2,
})
-- TODO: Make the start button start
local startButtonX, startButtonY = StartButton:getDimensions()
World:addEntity({
canBeCollidedBy = CursorMask,
drawAsSprite = StartButton,
addOnActivate = {
{ roundState = "active" },
},
z = 3,
size = { x = startButtonX, y = startButtonY },
position = {
x = width - 120,
y = height - 50,
@ -179,7 +202,8 @@ Scenarios = {
end,
}
Scenarios.firstLevel()
local currentLevel = Scenarios.firstLevel
currentLevel()
function love.load()
love.graphics.setBackgroundColor(1, 1, 1)
@ -190,8 +214,9 @@ function love.draw()
local dt = love.timer.getDelta()
if love.keyboard.isDown("r") then
World:clearEntities()
Scenarios.firstLevel()
currentLevel()
end
World:setSystemIndex(LiveForNFrames, 1)
World:update(dt, function(_, system)
return not system.isDrawSystem
end)

View File

@ -1,3 +1,27 @@
filteredSystem("activated", { activated = T.Entity }, function(e, _, system)
local activated = e.activated
if activated.addOnActivate then
for _, toAdd in ipairs(activated.addOnActivate) do
system.world:addEntity(toAdd)
end
end
if activated.pickedUpOnClick and #HeldByCursor.entities == 0 then
activated.placedOnClick = T.marker
activated.moveWithCursor = T.marker
activated.canBeCollidedBy = 0
system.world:addEntity(activated)
elseif activated.gridPosition then
for _, held in pairs(HeldByCursor.entities) do
held.placedOnClick = nil
held.moveWithCursor = nil
held.highlighted = nil
held.canBeCollidedBy = CursorMask
Replace(activated, held)
end
end
system.world:removeEntity(e)
end)
Collisions = filteredSystem("collisionResolution", { collisionBetween = T.Collision }, function(e, _, system)
local collidedInto, collider = e.collisionBetween[1], e.collisionBetween[2]
if collider.highlightsCollided then
@ -13,10 +37,11 @@ Collisions = filteredSystem("collisionResolution", { collisionBetween = T.Collis
collidedInto.canReceiveButtons = T.marker
system.world:addEntity(collidedInto)
end
if collidedInto.pickedUpOnClick ~= nil then -- and #HeldByCursor.entities == 0 and love.mouse.isDown(1) then
print("Click!")
collidedInto.moveWithCursor = T.marker
system.world:addEntity(collidedInto)
if collidedInto.gridPosition then
--print("ready to place " .. #HeldByCursor.entities .. " entities")
end
if MouseJustPressed(1, true) and collider.isCursor then
system.world:addEntity({ activated = collidedInto })
end
end
system.world:removeEntity(e)

View File

@ -31,7 +31,6 @@ local spriteDrawSystem = drawSystem(
if not e.drawAsSprite then
return
end
local width, height = e.drawAsSprite:getDimensions()
gfx.draw(e.drawAsSprite, e.position.x, e.position.y)
end
)
@ -63,7 +62,7 @@ drawSystem(
gfx.rectangle("fill", bgLeftEdge, bgTopEdge, bgWidth, bgHeight)
gfx.setColor(0, 0, 0)
gfx.drawRect("line", bgLeftEdge, bgTopEdge, bgWidth, bgHeight)
gfx.rectangle("line", bgLeftEdge, bgTopEdge, bgWidth, bgHeight)
end
gfx.print(e.drawAsText.text, bgLeftEdge + margin, bgTopEdge + margin)

View File

@ -8,8 +8,30 @@ buttonInputSystem = filteredSystem("buttonInput", { canReceiveButtons = T.marker
system.world:addEntity(e)
end)
Mouse = filteredSystem("Mouse", { mouseButtonPress = { position = T.XyPair, button = T.number } })
function MouseJustPressed(button, clear)
for _, event in pairs(Mouse.entities) do
if event.mouseButtonPress and event.mouseButtonPress.button == button then
if clear then
event.mouseButtonPress = nil
World:removeEntity(event)
end
return true
end
end
return false
end
HeldByCursor = filteredSystem("HeldByCursor", { pickedUpOnClick = T.marker, moveWithCursor = T.marker })
LiveForNFrames = filteredSystem("liveForNFrames", { liveForNFrames = T.number }, function(e, _, system)
e.liveForNFrames = e.liveForNFrames - 1
if e.liveForNFrames <= 0 then
system.world:removeEntity(e)
end
end)
function buttonInputSystem:preProcess()
if #self.entities == 0 then
return
@ -37,6 +59,19 @@ function love.mousemoved(x, y)
mouseX, mouseY = x, y
end
function love.mousepressed(x, y, button)
World:addEntity({
mouseButtonPress = {
position = {
x = x,
y = y,
},
button = button,
},
liveForNFrames = 1,
})
end
local keyDebounceSec = 0.1
local delay = 0
@ -76,7 +111,7 @@ local menuSystem = filteredSystem(
if isDown("return") then
pressed = true
system.world:addEntity({
round = "start",
roundState = "active",
})
end
@ -94,8 +129,13 @@ local menuSystem = filteredSystem(
cursorTracking = filteredSystem("cursorTracking", { moveWithCursor = T.marker, position = T.XyPair }, function(e)
if mouseInControl then
e.position.x = mouseX
e.position.y = mouseY
local offsetX, offsetY = 0, 0
if e.size then
offsetX = e.size.x / 2
offsetY = e.size.y / 2
end
e.position.x = mouseX - offsetX
e.position.y = mouseY - offsetY
end
end)

View File

@ -1,7 +1,5 @@
local gridElements = filteredSystem("gridElements", { gridPosition = T.XyPair, effectsToApply = T.AnyComponent })
local roundRunning = false
filteredSystem("timers", { timerSec = T.number, callback = T.SelfFunction }, function(e, dt, system)
e.timerSec = e.timerSec - dt
if e.timerSec < 0 then
@ -14,72 +12,96 @@ local function sign(n)
return n > 0 and 1 or n < 0 and -1 or 0
end
local roundSystem = filteredSystem("rounds", { round = T.str })
local activeBallEffects = filteredSystem("activeBallEffects", { ballEffects = T.AnyComponent, gridPosition = T.XyPair }, function(e, dt, system)
local roundActive = false
for _, state in pairs(roundSystem.entities) do
if state.round == "start" then
roundActive = true
end
end
if not roundActive then
return
end
local gridPosition, effects = e.gridPosition, e.ballEffects
-- Search for new effects from the current tile
for _, gridElement in pairs(gridElements.entities) do
if
gridPosition.x == gridElement.gridPosition.x
and gridPosition.y == gridElement.gridPosition.y
then
-- More direct-mutation-y than I'd like,
-- but offers a simple way to overwrite existing effects.
-- We're "setting InRelations" :D
for key, value in pairs(gridElement.effectsToApply) do
effects[key] = value
end
if gridElement.spriteAfterEffect then
gridElement.drawAsSprite = gridElement.spriteAfterEffect
gridElement.spriteAfterEffect = nil
end
gridElement.effectsToApply = nil
system.world:addEntity(gridElement)
end
end
-- Apply any effects currently connected to this ball
if effects.movement ~= nil then
gridPosition.x = gridPosition.x + sign(effects.movement.x)
gridPosition.y = gridPosition.y + sign(effects.movement.y)
effects.movement.x = effects.movement.x - sign(effects.movement.x)
effects.movement.y = effects.movement.y - sign(effects.movement.y)
if effects.movement.x == 0 and effects.movement.y == 0 then
effects.movement = nil
end
end
-- TODO: Trigger the round end
-- for _, _ in pairs(effects) do
-- -- Return if there are any effects left
-- return
-- end
-- system.world:addEntity({ round = "end" })
local roundSystem = filteredSystem("rounds", { roundState = T.str }, function(e)
print("roundState: " .. e.roundState)
end)
local stepTimeSec = 0.3
function roundSystem:preProcess()
if #self.entities ~= 0 then
print("#states: " .. #self.entities)
end
end
local activeBallEffects = filteredSystem(
"activeBallEffects",
{ ballEffects = T.AnyComponent, gridPosition = T.XyPair },
function(e, dt, system)
local gridPosition, effects = e.gridPosition, e.ballEffects
-- Search for new effects from the current tile
for _, gridElement in pairs(gridElements.entities) do
if gridPosition.x == gridElement.gridPosition.x and gridPosition.y == gridElement.gridPosition.y then
-- More direct-mutation-y than I'd like,
-- but offers a simple way to overwrite existing effects.
-- We're "setting InRelations" :D
for key, value in pairs(gridElement.effectsToApply) do
effects[key] = value
end
if gridElement.spriteAfterEffect then
gridElement.drawAsSprite = gridElement.spriteAfterEffect
gridElement.spriteAfterEffect = nil
end
gridElement.effectsToApply = nil
system.world:addEntity(gridElement)
end
end
-- Apply any effects currently connected to this ball
if effects.movement ~= nil then
gridPosition.x = gridPosition.x + sign(effects.movement.x)
gridPosition.y = gridPosition.y + sign(effects.movement.y)
effects.movement.x = effects.movement.x - sign(effects.movement.x)
effects.movement.y = effects.movement.y - sign(effects.movement.y)
if effects.movement.x == 0 and effects.movement.y == 0 then
effects.movement = nil
end
end
if effects.endOfRound ~= nil then
effects.endOfRound = nil
system.world:addEntity({ roundState = "end" })
system.world:removeEntity(e)
print("End of round")
return
end
for _, _ in pairs(effects) do
-- Return if there are any effects left
print("Setting roundState to animating...")
--system.world:addEntity({ roundState = "animating" })
--system.world:removeEntity(e)
return
end
print("End of round")
system.world:addEntity({ roundState = "end" })
end
)
local stepTimeSec = 0.1
local stepTimer = stepTimeSec
function activeBallEffects:preProcess(dt)
stepTimer = stepTimer - dt
if stepTimer <= 0 then
stepTimer = stepTimeSec
return
else
return tiny.SKIP_PROCESS
end
-- for _, round in pairs(roundSystem.entities) do
-- if round.roundState == "animating" then
-- return tiny.SKIP_PROCESS
-- end
-- end
for _, round in pairs(roundSystem.entities) do
if round.roundState == "active" then
return
end
end
return tiny.SKIP_PROCESS
end

View File

@ -1,12 +1,18 @@
---@meta
---@meta tiny-ecs
---@class World
World = {}
function World:add(...) end
---@generic T : Entity
---@param entity T
---@return T
function World:addEntity(entity) end
---@generic T : System
---@param system T
---@return T
function World:addSystem(system) end
function World:remove(...) end
@ -15,17 +21,28 @@ function World:removeEntity(entity) end
function World:removeSystem(system) end
--- Manages Entities and Systems marked for deletion or addition. Call this
--- before modifying Systems and Entities outside of a call to `tiny.update`.
--- Do not call this within a call to `tiny.update`.
function World:refresh() end
---@param dt number
function World:update(dt) end
---@param systemFilter nil | fun(world: World, system: System): boolean
function World:update(dt, systemFilter) end
--- Removes all Entities from the World.
function World:clearEntities() end
--- Removes all Systems from the World.
function World:clearSystems() end
--- Gets number of Entities in the World.
function World:getEntityCount() end
--- Gets number of Systems in World.
function World:getSystemCount() end
function World:setSystemIndex() end
--- Sets the index of a System in the World, and returns the old index. Changes
--- the order in which they Systems processed, because lower indexed Systems are
--- processed first. Returns the old system.index.
function World:setSystemIndex(world, system, index) end