Add box score and transitions
Add constants defining the top of the outfield wall (not used yet) Take scores out of mutable global state (that might be just about all of it sewn up) Finish switching batttingTeam to a TeamId value
This commit is contained in:
parent
6007ac971f
commit
5c45b7bba0
|
@ -44,6 +44,7 @@ function Announcer:popIn()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param text string
|
||||||
function Announcer:say(text)
|
function Announcer:say(text)
|
||||||
self.textQueue[#self.textQueue + 1] = text
|
self.textQueue[#self.textQueue + 1] = text
|
||||||
if #self.textQueue == 1 then
|
if #self.textQueue == 1 then
|
||||||
|
|
|
@ -8,6 +8,8 @@ Glove = playdate.graphics.image.new("images/game/Glove.png")
|
||||||
-- luacheck: ignore
|
-- luacheck: ignore
|
||||||
PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png")
|
PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png")
|
||||||
-- luacheck: ignore
|
-- luacheck: ignore
|
||||||
|
BigBat = playdate.graphics.image.new("images/game/BigBat.png")
|
||||||
|
-- luacheck: ignore
|
||||||
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
|
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
|
||||||
-- luacheck: ignore
|
-- luacheck: ignore
|
||||||
GameLogo = playdate.graphics.image.new("images/game/GameLogo.png")
|
GameLogo = playdate.graphics.image.new("images/game/GameLogo.png")
|
||||||
|
|
|
@ -125,6 +125,18 @@ C.WalkedRunnerSpeed = 10
|
||||||
|
|
||||||
C.ResetFieldersAfterSeconds = 2.5
|
C.ResetFieldersAfterSeconds = 2.5
|
||||||
|
|
||||||
|
C.OutfieldWall = {
|
||||||
|
{ x = 0, y = 137 },
|
||||||
|
{ x = 233, y = 32 },
|
||||||
|
{ x = 450, y = 29 },
|
||||||
|
{ x = 550, y = 59 },
|
||||||
|
{ x = 739, y = 64 },
|
||||||
|
{ x = 850, y = 19 },
|
||||||
|
{ x = 1100, y = 31 },
|
||||||
|
{ x = 1185, y = 181 },
|
||||||
|
{ x = 1201, y = 224 },
|
||||||
|
}
|
||||||
|
|
||||||
if not playdate then
|
if not playdate then
|
||||||
return C
|
return C
|
||||||
end
|
end
|
||||||
|
|
15
src/dbg.lua
15
src/dbg.lua
|
@ -35,8 +35,23 @@ function dbg.loadTheBases(br)
|
||||||
br.runners[4].nextBase = C.Bases[C.Home]
|
br.runners[4].nextBase = C.Bases[C.Home]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@return BoxScoreData
|
||||||
|
function dbg.mockBoxScoreData(inningCount)
|
||||||
|
inningCount = inningCount or 9
|
||||||
|
local data = {
|
||||||
|
home = {},
|
||||||
|
away = {},
|
||||||
|
}
|
||||||
|
for i = 1, inningCount do
|
||||||
|
data.home[i] = math.floor(math.random() * 5)
|
||||||
|
data.away[i] = math.floor(math.random() * 5)
|
||||||
|
end
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
---@param points XyPair[]
|
---@param points XyPair[]
|
||||||
function dbg.drawLine(points)
|
function dbg.drawLine(points)
|
||||||
|
playdate.graphics.setColor(playdate.graphics.kColorWhite)
|
||||||
for i = 2, #points do
|
for i = 2, #points do
|
||||||
local prev = points[i - 1]
|
local prev = points[i - 1]
|
||||||
local next = points[i]
|
local next = points[i]
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
---@class BoxScore
|
||||||
|
---@field data BoxScoreData
|
||||||
|
BoxScore = {}
|
||||||
|
|
||||||
|
---@param data BoxScoreData
|
||||||
|
function BoxScore.new(data)
|
||||||
|
return setmetatable({
|
||||||
|
data = data,
|
||||||
|
}, { __index = BoxScore })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: Convert the box-score into a whole "scene"
|
||||||
|
-- * Scroll left and right through games that go into extra innings
|
||||||
|
-- * Scroll up and down through other stats.
|
||||||
|
-- + Balls and strikes
|
||||||
|
-- + Batting average
|
||||||
|
-- + Graph of team scores over time
|
||||||
|
-- + Farthest hit ball
|
||||||
|
|
||||||
|
local MarginY <const> = 70
|
||||||
|
|
||||||
|
local ScoreFont <const> = playdate.graphics.font.new("fonts/Asheville-Sans-14-Bold.pft")
|
||||||
|
local NumWidth <const> = ScoreFont:getTextWidth("0")
|
||||||
|
local NumHeight <const> = ScoreFont:getHeight()
|
||||||
|
local AwayWidth <const> = ScoreFont:getTextWidth("AWAY")
|
||||||
|
local InningMargin = 4
|
||||||
|
|
||||||
|
local InningDrawWidth <const> = (InningMargin * 2) + (NumWidth * 2)
|
||||||
|
local ScoreDrawHeight = NumHeight * 2
|
||||||
|
|
||||||
|
-- luacheck: ignore 143
|
||||||
|
---@type pd_graphics_lib
|
||||||
|
local gfx = playdate.graphics
|
||||||
|
|
||||||
|
local function formatScore(n)
|
||||||
|
if n <= 9 then
|
||||||
|
return " " .. n
|
||||||
|
elseif n <= 19 then
|
||||||
|
return " " .. n
|
||||||
|
else
|
||||||
|
return tostring(n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local HomeY <const> = -4 + (NumHeight * 2) + MarginY
|
||||||
|
local AwayY <const> = -4 + (NumHeight * 3) + MarginY
|
||||||
|
|
||||||
|
local function drawInning(x, inningNumber, homeScore, awayScore)
|
||||||
|
gfx.setColor(gfx.kColorBlack)
|
||||||
|
gfx.setColor(gfx.kColorWhite)
|
||||||
|
gfx.setLineWidth(1)
|
||||||
|
gfx.drawRect(x, 34 + MarginY, InningDrawWidth, ScoreDrawHeight)
|
||||||
|
|
||||||
|
inningNumber = " " .. inningNumber
|
||||||
|
homeScore = formatScore(homeScore)
|
||||||
|
awayScore = formatScore(awayScore)
|
||||||
|
|
||||||
|
x = x - 8 + (InningDrawWidth / 2)
|
||||||
|
ScoreFont:drawTextAligned(inningNumber, x, -4 + NumHeight + MarginY, gfx.kAlignRight)
|
||||||
|
ScoreFont:drawTextAligned(awayScore, x, HomeY, gfx.kAlignRight)
|
||||||
|
ScoreFont:drawTextAligned(homeScore, x, AwayY, gfx.kAlignRight)
|
||||||
|
end
|
||||||
|
|
||||||
|
function BoxScore:update()
|
||||||
|
local originalDrawMode = gfx.getImageDrawMode()
|
||||||
|
gfx.clear(gfx.kColorBlack)
|
||||||
|
gfx.setImageDrawMode(gfx.kDrawModeInverted)
|
||||||
|
gfx.setColor(gfx.kColorBlack)
|
||||||
|
local inningStart = 4 + (AwayWidth * 1.5)
|
||||||
|
local widthAndMarg = InningDrawWidth + 4
|
||||||
|
ScoreFont:drawTextAligned(" HOME", 10, HomeY, gfx.kAlignRight)
|
||||||
|
ScoreFont:drawTextAligned("AWAY", 10, AwayY, gfx.kAlignRight)
|
||||||
|
for i = 1, #self.data.away do
|
||||||
|
drawInning(inningStart + ((i - 1) * widthAndMarg), i, self.data.home[i], self.data.away[i])
|
||||||
|
end
|
||||||
|
local homeScore, awayScore = utils.totalScores(self.data)
|
||||||
|
drawInning(4 + inningStart + (widthAndMarg * #self.data.away), "F", homeScore, awayScore)
|
||||||
|
gfx.setImageDrawMode(originalDrawMode)
|
||||||
|
end
|
|
@ -83,11 +83,10 @@ local ScoreboardHeight <const> = 55
|
||||||
local Indicator = "> "
|
local Indicator = "> "
|
||||||
local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator)
|
local IndicatorWidth <const> = ScoreFont:getTextWidth(Indicator)
|
||||||
|
|
||||||
---@param teams any
|
|
||||||
---@param battingTeam any
|
---@param battingTeam any
|
||||||
---@return string, number, string, number
|
---@return string, number, string, number
|
||||||
function getIndicators(teams, battingTeam)
|
function getIndicators(battingTeam)
|
||||||
if teams.home == battingTeam then
|
if battingTeam == "home" then
|
||||||
return Indicator, 0, "", IndicatorWidth
|
return Indicator, 0, "", IndicatorWidth
|
||||||
end
|
end
|
||||||
return "", IndicatorWidth, Indicator, 0
|
return "", IndicatorWidth, Indicator, 0
|
||||||
|
@ -101,11 +100,11 @@ local stats = {
|
||||||
battingTeam = nil,
|
battingTeam = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawScoreboardImpl(x, y, teams)
|
function drawScoreboardImpl(x, y)
|
||||||
local homeScore = stats.homeScore
|
local homeScore = stats.homeScore
|
||||||
local awayScore = stats.awayScore
|
local awayScore = stats.awayScore
|
||||||
|
|
||||||
local homeIndicator, homeOffset, awayIndicator, awayOffset = getIndicators(teams, stats.battingTeam)
|
local homeIndicator, homeOffset, awayIndicator, awayOffset = getIndicators(stats.battingTeam)
|
||||||
|
|
||||||
local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore)
|
local homeScoreText = homeIndicator .. "HOME " .. (homeScore > 9 and homeScore or " " .. homeScore)
|
||||||
local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore)
|
local awayScoreText = awayIndicator .. "AWAY " .. (awayScore > 9 and awayScore or " " .. awayScore)
|
||||||
|
@ -146,17 +145,17 @@ end
|
||||||
|
|
||||||
local newStats = stats
|
local newStats = stats
|
||||||
|
|
||||||
function drawScoreboard(x, y, teams, outs, battingTeam, inning)
|
function drawScoreboard(x, y, homeScore, awayScore, outs, battingTeam, inning)
|
||||||
if
|
if
|
||||||
newStats.homeScore ~= teams.home.score
|
newStats.homeScore ~= homeScore
|
||||||
or newStats.awayScore ~= teams.away.score
|
or newStats.awayScore ~= awayScore
|
||||||
or newStats.outs ~= outs
|
or newStats.outs ~= outs
|
||||||
or newStats.inning ~= inning
|
or newStats.inning ~= inning
|
||||||
or newStats.battingTeam ~= battingTeam
|
or newStats.battingTeam ~= battingTeam
|
||||||
then
|
then
|
||||||
newStats = {
|
newStats = {
|
||||||
homeScore = teams.home.score,
|
homeScore = homeScore,
|
||||||
awayScore = teams.away.score,
|
awayScore = awayScore,
|
||||||
outs = outs,
|
outs = outs,
|
||||||
inning = inning,
|
inning = inning,
|
||||||
battingTeam = battingTeam,
|
battingTeam = battingTeam,
|
||||||
|
@ -165,5 +164,5 @@ function drawScoreboard(x, y, teams, outs, battingTeam, inning)
|
||||||
stats = newStats
|
stats = newStats
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
drawScoreboardImpl(x, y, teams)
|
drawScoreboardImpl(x, y)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
Transitions = {
|
||||||
|
---@type Scene | nil
|
||||||
|
nextScene = nil,
|
||||||
|
---@type Scene | nil
|
||||||
|
previousScene = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
local gfx = playdate.graphics
|
||||||
|
|
||||||
|
-- local function animateOut() end
|
||||||
|
-- local function animateIn() end
|
||||||
|
|
||||||
|
local previousSceneImage
|
||||||
|
local previousSceneMask
|
||||||
|
|
||||||
|
local nextSceneImage
|
||||||
|
|
||||||
|
-- local nextSceneOffScreen = false
|
||||||
|
-- local stillAnimating = false
|
||||||
|
|
||||||
|
-- TODO: Okay but like imagine.
|
||||||
|
-- Push a blank image context,
|
||||||
|
-- draw the previous scene on one side,
|
||||||
|
-- draw the next scene on the other,
|
||||||
|
-- SWING a bat to cover the seam.
|
||||||
|
|
||||||
|
local batImageTable = {}
|
||||||
|
|
||||||
|
local batOffset = 80
|
||||||
|
|
||||||
|
local degStep = 3
|
||||||
|
|
||||||
|
function loadBatImageTable()
|
||||||
|
for deg = 90 - (degStep * 3), 270 + (degStep * 3), degStep do
|
||||||
|
local img = gfx.image.new(C.Screen.W, C.Screen.H)
|
||||||
|
gfx.pushContext(img)
|
||||||
|
BigBat:drawRotated(C.Center.x, C.Screen.H + batOffset, 90 + deg)
|
||||||
|
gfx.popContext()
|
||||||
|
batImageTable[deg] = img
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loadBatImageTable()
|
||||||
|
|
||||||
|
local function update()
|
||||||
|
local lastAngle
|
||||||
|
local seamAngle = math.rad(270)
|
||||||
|
while seamAngle > math.rad(90) do
|
||||||
|
local deltaSeconds = playdate.getElapsedTime()
|
||||||
|
playdate.resetElapsedTime()
|
||||||
|
seamAngle = seamAngle - (deltaSeconds * 3)
|
||||||
|
local seamAngleDeg = math.floor(math.deg(seamAngle))
|
||||||
|
seamAngleDeg = seamAngleDeg - (seamAngleDeg % degStep)
|
||||||
|
|
||||||
|
-- Skip re-drawing if no change
|
||||||
|
if lastAngle ~= seamAngleDeg then
|
||||||
|
lastAngle = seamAngleDeg
|
||||||
|
nextSceneImage:draw(0, 0)
|
||||||
|
|
||||||
|
gfx.pushContext(previousSceneMask)
|
||||||
|
gfx.setImageDrawMode(gfx.kDrawModeFillBlack)
|
||||||
|
batImageTable[seamAngleDeg]:draw(0, 0)
|
||||||
|
gfx.popContext()
|
||||||
|
|
||||||
|
previousSceneImage:setMaskImage(previousSceneMask)
|
||||||
|
previousSceneImage:draw(0, 0)
|
||||||
|
batImageTable[seamAngleDeg]:draw(0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
playdate.update = function()
|
||||||
|
Transitions.nextScene:update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param nextScene fun() The next playdate.update function
|
||||||
|
function transitionTo(nextScene)
|
||||||
|
if not Transitions.nextScene then
|
||||||
|
error("Expected Transitions to already have nextScene defined! E.g. by calling transitionBetween")
|
||||||
|
end
|
||||||
|
local previousScene = Transitions.nextScene
|
||||||
|
transitionBetween(previousScene, nextScene)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param previousScene Scene Has the current playdate.update function
|
||||||
|
---@param nextScene Scene Has the next playdate.update function
|
||||||
|
function transitionBetween(previousScene, nextScene)
|
||||||
|
playdate.wait(2) -- TODO: There's some sort of timing wack here.
|
||||||
|
playdate.update = update
|
||||||
|
|
||||||
|
previousSceneImage = gfx.image.new(C.Screen.W, C.Screen.H)
|
||||||
|
gfx.pushContext(previousSceneImage)
|
||||||
|
previousScene:update()
|
||||||
|
gfx.popContext()
|
||||||
|
|
||||||
|
nextSceneImage = gfx.image.new(C.Screen.W, C.Screen.H)
|
||||||
|
gfx.pushContext(nextSceneImage)
|
||||||
|
nextScene:update()
|
||||||
|
gfx.popContext()
|
||||||
|
|
||||||
|
previousSceneMask = gfx.image.new(C.Screen.W, C.Screen.H, gfx.kColorWhite)
|
||||||
|
previousSceneImage:setMaskImage(previousSceneMask)
|
||||||
|
|
||||||
|
Transitions.nextScene = nextScene
|
||||||
|
Transitions.previousScene = previousScene
|
||||||
|
end
|
|
@ -182,7 +182,7 @@ function Fielding:userThrowTo(targetBase, ball, throwFlyMs)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Fielding:celebrate()
|
function Fielding.celebrate()
|
||||||
FielderDanceAnimator:reset(C.DanceBounceMs)
|
FielderDanceAnimator:reset(C.DanceBounceMs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -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
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
@ -24,9 +24,7 @@ local function startGame()
|
||||||
awayTeamSprites = AwayTeamSprites,
|
awayTeamSprites = AwayTeamSprites,
|
||||||
})
|
})
|
||||||
playdate.resetElapsedTime()
|
playdate.resetElapsedTime()
|
||||||
playdate.update = function()
|
transitionBetween(MainMenu, next)
|
||||||
next:update()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pausingEaser(baseEaser)
|
local function pausingEaser(baseEaser)
|
||||||
|
@ -64,9 +62,10 @@ local function arrayElementFromCrank(array, crankPosition)
|
||||||
return array[i]
|
return array[i]
|
||||||
end
|
end
|
||||||
|
|
||||||
local currentLogo = nil
|
local currentLogo
|
||||||
|
|
||||||
function MainMenu.update()
|
--luacheck: ignore
|
||||||
|
function MainMenu:update()
|
||||||
playdate.timer.updateTimers()
|
playdate.timer.updateTimers()
|
||||||
crankStartPos = crankStartPos or playdate.getCrankPosition()
|
crankStartPos = crankStartPos or playdate.getCrankPosition()
|
||||||
|
|
||||||
|
|
74
src/main.lua
74
src/main.lua
|
@ -8,6 +8,8 @@ import 'CoreLibs/timer.lua'
|
||||||
import 'CoreLibs/ui.lua'
|
import 'CoreLibs/ui.lua'
|
||||||
-- stylua: ignore end
|
-- stylua: ignore end
|
||||||
|
|
||||||
|
--- @alias Scene { update: fun(self: self) }
|
||||||
|
|
||||||
--- @alias EasingFunc fun(number, number, number, number): number
|
--- @alias EasingFunc fun(number, number, number, number): number
|
||||||
|
|
||||||
--- @alias LaunchBall fun(
|
--- @alias LaunchBall fun(
|
||||||
|
@ -24,9 +26,11 @@ import 'CoreLibs/ui.lua'
|
||||||
import 'utils.lua'
|
import 'utils.lua'
|
||||||
import 'constants.lua'
|
import 'constants.lua'
|
||||||
import 'assets.lua'
|
import 'assets.lua'
|
||||||
import 'draw/player.lua'
|
import 'draw/box-score.lua'
|
||||||
import 'draw/overlay.lua'
|
|
||||||
import 'draw/fielder.lua'
|
import 'draw/fielder.lua'
|
||||||
|
import 'draw/overlay.lua'
|
||||||
|
import 'draw/player.lua'
|
||||||
|
import 'draw/transitions.lua'
|
||||||
|
|
||||||
import 'main-menu.lua'
|
import 'main-menu.lua'
|
||||||
|
|
||||||
|
@ -44,19 +48,18 @@ import 'npc.lua'
|
||||||
|
|
||||||
local gfx <const>, C <const> = playdate.graphics, C
|
local gfx <const>, C <const> = playdate.graphics, C
|
||||||
|
|
||||||
---@alias Team { score: number, benchPosition: XyPair }
|
---@alias Team { benchPosition: XyPair }
|
||||||
---@type table<TeamId, Team>
|
---@type table<TeamId, Team>
|
||||||
local teams <const> = {
|
local teams <const> = {
|
||||||
home = {
|
home = {
|
||||||
score = 0, -- TODO: Extract this last bit of global mutable state.
|
|
||||||
benchPosition = utils.xy(C.Screen.W + 10, C.Center.y),
|
benchPosition = utils.xy(C.Screen.W + 10, C.Center.y),
|
||||||
},
|
},
|
||||||
away = {
|
away = {
|
||||||
score = 0,
|
|
||||||
benchPosition = utils.xy(-10, C.Center.y),
|
benchPosition = utils.xy(-10, C.Center.y),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@alias BoxScoreData table<TeamId, number[]>
|
||||||
---@alias TeamId 'home' | 'away'
|
---@alias TeamId 'home' | 'away'
|
||||||
|
|
||||||
--- Well, maybe not "Settings", but passive state that probably won't change much, if at all, during a game.
|
--- Well, maybe not "Settings", but passive state that probably won't change much, if at all, during a game.
|
||||||
|
@ -73,6 +76,7 @@ local teams <const> = {
|
||||||
---@field catcherThrownBall boolean
|
---@field catcherThrownBall boolean
|
||||||
---@field offenseState OffenseState
|
---@field offenseState OffenseState
|
||||||
---@field inning number
|
---@field inning number
|
||||||
|
---@field boxScore BoxScoreData
|
||||||
---@field batBase XyPair
|
---@field batBase XyPair
|
||||||
---@field batTip XyPair
|
---@field batTip XyPair
|
||||||
---@field batAngleDeg number
|
---@field batAngleDeg number
|
||||||
|
@ -104,8 +108,6 @@ Game = {}
|
||||||
---@param state MutableState | nil
|
---@param state MutableState | nil
|
||||||
---@return Game
|
---@return Game
|
||||||
function Game.new(settings, announcer, fielding, baserunning, npc, state)
|
function Game.new(settings, announcer, fielding, baserunning, npc, state)
|
||||||
teams.away.score = 0
|
|
||||||
teams.home.score = 0
|
|
||||||
announcer = announcer or Announcer.new()
|
announcer = announcer or Announcer.new()
|
||||||
fielding = fielding or Fielding.new()
|
fielding = fielding or Fielding.new()
|
||||||
settings.userTeam = nil -- "away"
|
settings.userTeam = nil -- "away"
|
||||||
|
@ -137,6 +139,10 @@ function Game.new(settings, announcer, fielding, baserunning, npc, state)
|
||||||
battingTeamSprites = settings.awayTeamSprites,
|
battingTeamSprites = settings.awayTeamSprites,
|
||||||
fieldingTeamSprites = settings.homeTeamSprites,
|
fieldingTeamSprites = settings.homeTeamSprites,
|
||||||
runnerBlipper = runnerBlipper,
|
runnerBlipper = runnerBlipper,
|
||||||
|
boxScore = {
|
||||||
|
home = { 0 },
|
||||||
|
away = { 0 },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, { __index = Game })
|
}, { __index = Game })
|
||||||
|
|
||||||
|
@ -210,10 +216,6 @@ local function getOppositeTeamId(teamId)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Game:getBattingTeam()
|
|
||||||
return teams[self.state.battingTeam] or error("Unknown battingTeam: " .. (self.state.battingTeam or "nil"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function Game:getFieldingTeam()
|
function Game:getFieldingTeam()
|
||||||
return teams[getOppositeTeamId(self.state.battingTeam)]
|
return teams[getOppositeTeamId(self.state.battingTeam)]
|
||||||
end
|
end
|
||||||
|
@ -265,24 +267,33 @@ end
|
||||||
|
|
||||||
function Game:nextHalfInning()
|
function Game:nextHalfInning()
|
||||||
pitchTracker:reset()
|
pitchTracker:reset()
|
||||||
local gameOver = self.state.inning == self.settings.finalInning and teams.away.score ~= teams.home.score
|
local homeScore, awayScore = utils.totalScores(self.state.boxScore)
|
||||||
if not gameOver then
|
local gameOver = self.state.battingTeam == "home"
|
||||||
self.fielding:celebrate()
|
and self.state.inning == self.settings.finalInning
|
||||||
self.state.secondsSinceLastRunnerMove = -7
|
and awayScore ~= homeScore
|
||||||
self.fielding:benchTo(self:getFieldingTeam().benchPosition)
|
|
||||||
self.announcer:say("SWITCHING SIDES...")
|
|
||||||
end
|
|
||||||
|
|
||||||
if gameOver then
|
if gameOver then
|
||||||
self.announcer:say("AND THAT'S THE BALL GAME!")
|
self.announcer:say("AND THAT'S THE BALL GAME!")
|
||||||
else
|
playdate.timer.new(3000, function()
|
||||||
|
transitionTo(BoxScore.new(self.state.boxScore))
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
Fielding.celebrate()
|
||||||
|
self.state.secondsSinceLastRunnerMove = -7
|
||||||
|
self.fielding:benchTo(self:getFieldingTeam().benchPosition)
|
||||||
|
self.announcer:say("SWITCHING SIDES...")
|
||||||
|
|
||||||
self.fielding:resetFielderPositions()
|
self.fielding:resetFielderPositions()
|
||||||
if self.state.battingTeam == teams.home then
|
if self.state.battingTeam == "home" then
|
||||||
self.state.inning = self.state.inning + 1
|
self.state.inning = self.state.inning + 1
|
||||||
|
self.state.boxScore.home[self.state.inning] = 0
|
||||||
|
self.state.boxScore.away[self.state.inning] = 0
|
||||||
end
|
end
|
||||||
self.state.battingTeam = getOppositeTeamId(self.state.battingTeam)
|
self.state.battingTeam = getOppositeTeamId(self.state.battingTeam)
|
||||||
playdate.timer.new(2000, function()
|
playdate.timer.new(2000, function()
|
||||||
if self.state.battingTeam == teams.home then
|
if self.state.battingTeam == "home" then
|
||||||
self.state.battingTeamSprites = self.settings.homeTeamSprites
|
self.state.battingTeamSprites = self.settings.homeTeamSprites
|
||||||
self.state.runnerBlipper = self.homeTeamBlipper
|
self.state.runnerBlipper = self.homeTeamBlipper
|
||||||
self.state.fieldingTeamSprites = self.settings.awayTeamSprites
|
self.state.fieldingTeamSprites = self.settings.awayTeamSprites
|
||||||
|
@ -292,13 +303,13 @@ function Game:nextHalfInning()
|
||||||
self.state.runnerBlipper = self.awayTeamBlipper
|
self.state.runnerBlipper = self.awayTeamBlipper
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param scoredRunCount number
|
---@param scoredRunCount number
|
||||||
function Game:score(scoredRunCount)
|
function Game:score(scoredRunCount)
|
||||||
local batting = self:getBattingTeam()
|
local battingTeamBoxScore = self.state.boxScore[self.state.battingTeam]
|
||||||
batting.score = batting.score + scoredRunCount
|
battingTeamBoxScore[self.state.inning] = battingTeamBoxScore[self.state.inning] + scoredRunCount
|
||||||
|
|
||||||
self.announcer:say("SCORE!")
|
self.announcer:say("SCORE!")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -513,7 +524,8 @@ function Game:updateGameState()
|
||||||
if self.state.secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then
|
if self.state.secondsSinceLastRunnerMove > C.ResetFieldersAfterSeconds then
|
||||||
-- End of play. Throw the ball back to the pitcher
|
-- End of play. Throw the ball back to the pitcher
|
||||||
self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true)
|
self.state.ball:launch(C.PitchStartX, C.PitchStartY, playdate.easingFunctions.linear, nil, true)
|
||||||
self.fielding:markAllIneligible() -- This is ugly, and ideally would not be necessary if Fielding handled the return throw directly.
|
-- This is ugly, and ideally would not be necessary if Fielding handled the return throw directly.
|
||||||
|
self.fielding:markAllIneligible()
|
||||||
self.fielding:resetFielderPositions()
|
self.fielding:resetFielderPositions()
|
||||||
self.state.offenseState = C.Offense.batting
|
self.state.offenseState = C.Offense.batting
|
||||||
-- TODO: Remove, or replace with nextBatter()
|
-- TODO: Remove, or replace with nextBatter()
|
||||||
|
@ -629,11 +641,21 @@ function Game:update()
|
||||||
if math.abs(offsetX) > 10 or math.abs(offsetY) > 10 then
|
if math.abs(offsetX) > 10 or math.abs(offsetY) > 10 then
|
||||||
drawMinimap(self.baserunning.runners, self.fielding.fielders)
|
drawMinimap(self.baserunning.runners, self.fielding.fielders)
|
||||||
end
|
end
|
||||||
drawScoreboard(0, C.Screen.H * 0.77, teams, self.baserunning.outs, self:getBattingTeam(), self.state.inning)
|
local homeScore, awayScore = utils.totalScores(self.state.boxScore)
|
||||||
|
drawScoreboard(
|
||||||
|
0,
|
||||||
|
C.Screen.H * 0.77,
|
||||||
|
homeScore,
|
||||||
|
awayScore,
|
||||||
|
self.baserunning.outs,
|
||||||
|
self.state.battingTeam,
|
||||||
|
self.state.inning
|
||||||
|
)
|
||||||
drawBallsAndStrikes(290, C.Screen.H - 20, pitchTracker.balls, pitchTracker.strikes)
|
drawBallsAndStrikes(290, C.Screen.H - 20, pitchTracker.balls, pitchTracker.strikes)
|
||||||
self.announcer:draw(C.Center.x, 10)
|
self.announcer:draw(C.Center.x, 10)
|
||||||
|
|
||||||
if playdate.isCrankDocked() then
|
if playdate.isCrankDocked() then
|
||||||
|
-- luacheck: ignore
|
||||||
playdate.ui.crankIndicator:draw()
|
playdate.ui.crankIndicator:draw()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ end
|
||||||
---@param catcherThrownBall boolean
|
---@param catcherThrownBall boolean
|
||||||
---@param deltaSec number
|
---@param deltaSec number
|
||||||
---@return number
|
---@return number
|
||||||
|
-- luacheck: no unused
|
||||||
function Npc:updateBatAngle(ball, catcherThrownBall, deltaSec)
|
function Npc:updateBatAngle(ball, catcherThrownBall, deltaSec)
|
||||||
if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then
|
if not catcherThrownBall and ball.y > 200 and ball.y < 230 and (ball.x < C.Center.x + 15) then
|
||||||
npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed)
|
npcBatDeg = npcBatDeg + (deltaSec * npcBatSpeed)
|
||||||
|
|
|
@ -232,6 +232,22 @@ function utils.getNearestOf(array, x, y, extraCondition)
|
||||||
return nearest, nearestDistance
|
return nearest, nearestDistance
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param box BoxScore
|
||||||
|
---@return number homeScore, number awayScore
|
||||||
|
function utils.totalScores(box)
|
||||||
|
local homeScore = 0
|
||||||
|
for _, score in pairs(box.home) do
|
||||||
|
homeScore = homeScore + score
|
||||||
|
end
|
||||||
|
|
||||||
|
local awayScore = 0
|
||||||
|
for _, score in pairs(box.away) do
|
||||||
|
awayScore = awayScore + score
|
||||||
|
end
|
||||||
|
|
||||||
|
return homeScore, awayScore
|
||||||
|
end
|
||||||
|
|
||||||
PitchOutcomes = {
|
PitchOutcomes = {
|
||||||
StrikeOut = {},
|
StrikeOut = {},
|
||||||
Walk = {},
|
Walk = {},
|
||||||
|
|
Loading…
Reference in New Issue