Almost-working upgrade menu.

Basic input system.
More advanced text-drawing system.
This commit is contained in:
Sage Vaillancourt 2025-03-06 01:06:46 -05:00
parent 42ec7b74fc
commit 2e87bc8836
14 changed files with 477 additions and 66 deletions

View File

@ -28,6 +28,8 @@ TomatoSprite = playdate.graphics.image.new("assets/images/TomatoSprite.png")
-- !!(dirLookup('assets/sounds', 'wav', 'playdate.sound.sampleplayer.new', 'pd_sampleplayer'))
-- !!(dirLookup('assets/music', 'wav', 'playdate.sound.sampleplayer.new', 'pd_sampleplayer'))
-- !!(dirLookup('assets/fonts', 'fnt', 'playdate.graphics.font.new', 'pd_font', nil, nil, function(varName, value)
-- return varName:gsub("[- ]", "") .. " = " .. value:gsub("fnt", "pft")
-- end))
-- luacheck: ignore
---@type pd_font
AshevilleSans14Bold = playdate.graphics.font.new("assets/fonts/Asheville-Sans-14-Bold.pft")

View File

@ -28,6 +28,6 @@ end)!!(generatedFileWarning())
!!(dirLookup('assets/images', 'png', 'playdate.graphics.image.new', 'pd_image'))
-- !!(dirLookup('assets/sounds', 'wav', 'playdate.sound.sampleplayer.new', 'pd_sampleplayer'))
-- !!(dirLookup('assets/music', 'wav', 'playdate.sound.sampleplayer.new', 'pd_sampleplayer'))
-- !!(dirLookup('assets/fonts', 'fnt', 'playdate.graphics.font.new', 'pd_font', nil, nil, function(varName, value)
-- return varName:gsub("[- ]", "") .. " = " .. value:gsub("fnt", "pft")
-- end))
!!(dirLookup('assets/fonts', 'fnt', 'playdate.graphics.font.new', 'pd_font', nil, nil, function(varName, value)
return varName:gsub("[- ]", "") .. " = " .. value:gsub("fnt", "pft")
end))

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,295 @@
tracking=1
space 3
! 2
" 5
# 9
$ 8
% 12
& 11
' 3
( 5
) 5
* 8
+ 8
, 3
- 6
. 2
/ 6
0 9
1 4
2 9
3 9
4 9
5 9
6 9
7 9
8 10
9 9
: 2
; 2
< 7
= 7
> 7
? 9
@ 11
A 10
B 9
C 9
D 9
E 8
F 8
G 9
H 9
I 2
J 8
K 10
L 9
M 12
N 9
O 9
P 9
Q 9
R 9
S 9
T 10
U 9
V 10
W 14
X 8
Y 8
Z 8
[ 3
\ 6
] 3
^ 6
_ 8
` 3
a 8
b 8
c 8
d 8
e 8
f 6
g 8
h 8
i 2
j 4
k 8
l 2
m 12
n 8
o 8
p 8
q 8
r 6
s 8
t 6
u 8
v 8
w 12
x 9
y 8
z 8
{ 6
| 2
} 6
~ 10
… 8
¥ 8
‼ 5
™ 8
© 11
® 11
。 16
、 16
ぁ 16
あ 16
ぃ 16
い 16
ぅ 16
う 16
ぇ 16
え 16
ぉ 16
お 16
か 16
が 16
き 16
ぎ 16
く 16
ぐ 16
け 16
げ 16
こ 16
ご 16
さ 16
ざ 16
し 16
じ 16
す 16
ず 16
せ 16
ぜ 16
そ 16
ぞ 16
た 16
だ 16
ち 16
ぢ 16
っ 16
つ 16
づ 16
て 16
で 16
と 16
ど 16
な 16
に 16
ぬ 16
ね 16
の 16
は 16
ば 16
ぱ 16
ひ 16
び 16
ぴ 16
ふ 16
ぶ 16
ぷ 16
へ 16
べ 16
ぺ 16
ほ 16
ぼ 16
ぽ 16
ま 16
み 16
む 16
め 16
も 16
ゃ 16
や 16
ゅ 16
ゆ 16
ょ 16
よ 16
ら 16
り 16
る 16
れ 16
ろ 16
ゎ 16
わ 16
ゐ 16
ゑ 16
を 16
ん 16
ゔ 16
ゕ 16
ゖ 16
゛ 1
゜ 0
ゝ 16
ゞ 16
ゟ 16
16
ァ 16
ア 16
ィ 16
イ 16
ゥ 16
ウ 16
ェ 16
エ 16
ォ 16
オ 16
カ 16
ガ 16
キ 16
ギ 16
ク 16
グ 16
ケ 16
ゲ 16
コ 16
ゴ 16
サ 16
ザ 16
シ 16
ジ 16
ス 16
ズ 16
セ 16
ゼ 16
ソ 16
ゾ 16
タ 16
ダ 16
チ 16
ヂ 16
ッ 16
ツ 16
ヅ 16
テ 16
デ 16
ト 16
ド 16
ナ 16
ニ 16
ヌ 16
ネ 16
16
ハ 16
バ 16
パ 16
ヒ 16
ビ 16
ピ 16
フ 16
ブ 16
プ 16
ヘ 16
ベ 16
ペ 16
ホ 16
ボ 16
ポ 16
マ 16
ミ 16
ム 16
メ 16
モ 16
ャ 16
ヤ 16
ュ 16
ユ 16
ョ 16
ヨ 16
ラ 16
リ 16
ル 16
レ 16
ロ 16
ヮ 16
ワ 16
ヰ 16
ヱ 16
ヲ 16
ン 16
ヴ 16
ヵ 16
ヶ 16
ヷ 16
ヸ 16
ヹ 16
ヺ 16
・ 16
ー 16
ヽ 16
ヾ 16
ヿ 16
「 16
」 16
円 16
<EFBFBD> 13

View File

@ -15,15 +15,19 @@ world = tiny.world()
import("tiny-tools.lua")
import("assets.lua")
import("systems/filter-types.lua")
import("systems/camera-pan.lua")
import("systems/collision-detection.lua")
import("systems/collision-resolution.lua")
import("systems/draw.lua")
import("systems/gravity.lua")
import("systems/move-toward.lua")
import("systems/velocity.lua")
import("systems/rounds.lua")
import("systems/spawner.lua")
import("systems/velocity.lua")
import("systems/camera-pan.lua")
import("systems/collision-resolution.lua")
import("systems/collision-detection.lua")
import("systems/draw.lua")
import("systems/input.lua")
import("systems/menu.lua")
import("ingredients/ingredients.lua")
import("cart.lua")
import("utils.lua")
@ -79,7 +83,7 @@ function playdate.update()
floor.position.x = Camera.pan.x - 600
world:update(deltaSeconds)
world:update(math.min(1 / 40, deltaSeconds))
gfx.setDrawOffset(0, 0)
Score:draw()

View File

@ -4,10 +4,46 @@ drawRectanglesSystem = filteredSystem({ position = T.XyPair, drawAsRectangle = {
gfx.fillRect(e.position.x, e.position.y, e.drawAsRectangle.size.x, e.drawAsRectangle.size.y)
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)
e.drawAsSprite:draw(e.position.x, e.position.y)
end)
local textHeight = AshevilleSans14Bold:getHeight()
local xMargin = 4
drawTextSystem = filteredSystem(
{ position = T.XyPair, drawAsText = { text = T.str, style = Maybe(T.str) } },
function(e, dt)
local textWidth = AshevilleSans14Bold:getTextWidth(e.drawAsText.text)
if e.drawAsText.style == TextStyle.Inverted then
gfx.fillRect(
e.position.x - xMargin - textWidth / 2,
e.position.y - 2,
textWidth + (xMargin * 2),
textHeight + 2
)
gfx.setImageDrawMode(gfx.kDrawModeInverted)
end
if e.drawAsText.style == TextStyle.Bordered then
gfx.setColor(gfx.kColorWhite)
gfx.fillRect(
e.position.x - xMargin - textWidth / 2,
e.position.y - 2,
textWidth + (xMargin * 2),
textHeight + 2
)
gfx.setColor(gfx.kColorBlack)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
gfx.drawRect(
e.position.x - xMargin - textWidth / 2,
e.position.y - 2,
textWidth + (xMargin * 2),
textHeight + 2
)
end
AshevilleSans14Bold:drawTextAligned(e.drawAsText.text, e.position.x, e.position.y, kTextAlignment.center)
if e.drawAsText.style == TextStyle.Inverted then
gfx.setImageDrawMode(gfx.kDrawModeCopy)
end
end
)

View File

@ -18,6 +18,8 @@ local XyPair = { x = 1, y = 1 }
---@alias CanSpawn { entity: Entity }
---@alias InRelations Entity[]
T = {
XyPair = XyPair,
bool = true,
@ -49,6 +51,10 @@ T = {
RoundStateAction = "start",
---@type CanSpawn
CanSpawn = {},
---@type InRelations
InRelations = {},
---@type InputState
InputState = {},
}
---@generic T
@ -57,3 +63,9 @@ T = {
function Maybe(t)
return { maybe = t }
end
TextStyle = {
Inverted = "INVERTED",
Bordered = "BORDERED",
None = "None",
}

18
src/systems/input.lua Normal file
View File

@ -0,0 +1,18 @@
---@alias InputState { upJustPressed: boolean, downJustPressed: boolean, rightJustPressed: boolean, leftJustPressed: boolean, aJustPressed: boolean, bJustPressed: boolean }
local buttonJustPressed = playdate.buttonJustPressed
local inputState = {}
inputSystem = filteredSystem({ canReceiveInput = T.marker }, function(e, _, system)
e.inputState = inputState
system.world:addEntity(e)
end)
function inputSystem:preProcess()
inputState.upJustPressed = buttonJustPressed(playdate.kButtonUp)
inputState.downJustPressed = buttonJustPressed(playdate.kButtonDown)
inputState.rightJustPressed = buttonJustPressed(playdate.kButtonRight)
inputState.leftJustPressed = buttonJustPressed(playdate.kButtonLeft)
inputState.aJustPressed = buttonJustPressed(playdate.kButtonA)
inputState.bJustPressed = buttonJustPressed(playdate.kButtonB)
end

26
src/systems/menu.lua Normal file
View File

@ -0,0 +1,26 @@
menuController = filteredSystem({ menuItems = T.InRelations, inputState = T.InputState }, function(e, _, _)
for _, menuItem in pairs(e.menuItems) do
if menuItem.highlighted then
if e.inputState.aJustPressed then
menuItem.onSelect()
end
if e.inputState.downJustPressed and menuItem.navigateDown then
menuItem.highlighted = false
menuItem.navigateDown.highlighted = true
return
end
if e.inputState.upJustPressed and menuItem.navigateUp then
menuItem.highlighted = false
menuItem.navigateUp.highlighted = true
return
end
end
end
for _, menuItem in pairs(e.menuItems) do
if menuItem.highlighted then
menuItem.drawAsText.style = TextStyle.Inverted
else
menuItem.drawAsText.style = TextStyle.Bordered
end
end
end)

View File

@ -15,27 +15,24 @@ local function normalizeVector(xy1, xy2)
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
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)

View File

@ -22,6 +22,8 @@ roundSystem = filteredSystem({ roundAction = T.RoundStateAction, position = Mayb
stopMovingOnCollision = true,
})
-- TODO: Big ol' numbers displaying how many ingredients were collected?
-- TODO: Could layer ingredients in rows of three? Maybe just when it's higher?
local delayPerDrop = 150
local delay = 0
for i, collectable in ipairs(collectedEntities.entities) do
@ -48,30 +50,51 @@ roundSystem = filteredSystem({ roundAction = T.RoundStateAction, position = Mayb
end
local availableUpgrades = Utils.getNDifferentValues(getAvailableSpawnerUpgrades(), 3)
-- Sorting from shortest to longest sort of makes them look like a bun?
table.sort(availableUpgrades, function(a, b)
return #a.name > #b.name
end)
y = y - 50
local menuEntity = {
menuItems = {},
canReceiveInput = T.marker,
}
local upgradeBelow
for _, upgrade in ipairs(availableUpgrades) do
printTable(upgrade)
local collX, collY = 75, 30
local collX, collY = 75, 21
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)
local upgradeEntity = {
onSelect = upgrade.apply,
drawAsText = {
text = upgrade.name,
style = TextStyle.Inverted,
},
size = { x = collX, y = collY },
mass = 0.5,
velocity = { x = 0, y = 0 },
position = { x = e.position.x, y = y },
canCollideWith = 2,
canBeCollidedBy = 2,
isSolid = true,
stopMovingOnCollision = true,
onCollidingRemove = onCollidingRemove,
focusOnCollide = i,
navigateDown = upgradeBelow,
highlighted = true,
}
if upgradeBelow then
upgradeBelow.navigateUp = upgradeEntity
upgradeBelow.highlighted = false
upgradeBelow.drawAsText.style = TextStyle.Bordered
end
upgradeBelow = upgradeEntity
menuEntity.menuItems[#menuEntity.menuItems + 1] = upgradeEntity
playdate.timer.new(delay, function(_system, _upgradeEntity)
_system.world:addEntity(_upgradeEntity)
end, system, upgradeEntity)
delay = delay + delayPerDrop
system.world:addEntity(menuEntity)
end
system.world:removeEntity(e)
end

View File

@ -109,7 +109,7 @@ function getAvailableSpawnerUpgrades()
local upgrades = {}
for _, spawner in pairs(spawnerSystem.entities) do
if spawner.hasUpgradeSpeed then
upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
-- upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
end
if spawner.canSpawn.entity.score then
@ -117,7 +117,7 @@ function getAvailableSpawnerUpgrades()
name = "Double " .. spawner.name .. " value",
apply = function()
spawner.canSpawn.entity.score = spawner.canSpawn.entity.score * 2
end
end,
}
end
@ -126,7 +126,8 @@ function getAvailableSpawnerUpgrades()
name = "Double " .. spawner.name .. " frequency",
apply = function()
spawner.odds = spawner.odds * 2
end
-- addEntity({ roundAction = "NEXT_ROUND" })
end,
}
-- if not spawner.canSpawn.entity.velocity then

View File

@ -1,10 +1,7 @@
local sqrt = math.sqrt
velocitySystem = filteredSystem({ position = T.XyPair, velocity = T.XyPair }, function(e, dt, system)
if not e.velocity then
return
end
if sqrt((e.velocity.x * e.velocity.x) + (e.velocity.y * e.velocity.y)) < 1.5 then
if sqrt((e.velocity.x * e.velocity.x) + (e.velocity.y * e.velocity.y)) < 2 then
e.velocity = nil
if e.spawnEntitiesWhenStopped then
e:spawnEntitiesWhenStopped(system.world)

View File

@ -25,4 +25,4 @@ function Utils.getNDifferentValues(fromArr, n)
randoms[#randoms + 1] = fromArr[i]
end
return randoms
end
end