NPCs can play each other
Some timing tweaks and TODOs. Cluster global state tighter together.
This commit is contained in:
parent
b9d25e18d8
commit
1926960c86
|
@ -23,7 +23,7 @@ function Announcer.new()
|
|||
}, { __index = Announcer })
|
||||
end
|
||||
|
||||
local DurationMs <const> = 3000
|
||||
local DurationMs <const> = 2000
|
||||
|
||||
function Announcer:popIn()
|
||||
self.animatorY = AnnouncerAnimatorInY
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
---@field onThirdOut fun()
|
||||
Baserunning = {}
|
||||
|
||||
-- TODO: Implement slides. Would require making fielders' gloves "real objects" whose state is tracked.
|
||||
|
||||
---@param announcer any
|
||||
---@return Baserunning
|
||||
function Baserunning.new(announcer, onThirdOut)
|
||||
|
@ -196,6 +198,9 @@ function Baserunning:updateRunner(runner, runnerIndex, appliedSpeed, deltaSecond
|
|||
end
|
||||
end
|
||||
|
||||
-- TODO: Make this less "sticky" for the user.
|
||||
-- Currently it can be a little hard to run *past* a base.
|
||||
|
||||
local autoRun = (nearestBaseDistance > 40 or runner.forcedTo) and mult * autoRunSpeed
|
||||
or nearestBaseDistance < 5 and 0
|
||||
or (nearestBase == runner.nextBase and autoRunSpeed or -1 * autoRunSpeed)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
--- speed: number,
|
||||
--- }
|
||||
|
||||
-- TODO: Run down baserunners in a pickle.
|
||||
|
||||
-- selene: allow(unscoped_variables)
|
||||
---@class Fielding
|
||||
---@field fielders table<string, Fielder>
|
||||
|
@ -117,6 +119,9 @@ function Fielding:updateFielderPositions(ball, deltaSeconds)
|
|||
fielderTouchingBall = fielder
|
||||
end
|
||||
end
|
||||
-- TODO: The need is growing for a distinction between touching the ball and holding the ball.
|
||||
-- Or, at least, fielders need to start *stopping* the ball when they make contact with it.
|
||||
-- Right now, a line-drive *through* first will be counted as an out.
|
||||
self.fielderTouchingBall = fielderTouchingBall
|
||||
return fielderTouchingBall
|
||||
end
|
||||
|
|
87
src/main.lua
87
src/main.lua
|
@ -42,15 +42,23 @@ local gfx <const>, C <const> = playdate.graphics, C
|
|||
|
||||
local announcer = Announcer.new()
|
||||
local fielding = Fielding.new()
|
||||
-- TODO: Find a way to get baserunning and npc instantiated closer to the top, here.
|
||||
-- Currently difficult because they depend on nextHalfInning/each other.
|
||||
|
||||
---@alias SimpleAnimator { currentValue: fun(self): number; reset: fun(self, durationMs: number | nil) }
|
||||
------------------
|
||||
-- GLOBAL STATE --
|
||||
------------------
|
||||
|
||||
local deltaSeconds = 0
|
||||
|
||||
local ball = Ball.new(gfx.animator)
|
||||
|
||||
---@alias Team { score: number, benchPosition: XyPair }
|
||||
local batBase <const> = utils.xy(C.Center.x - 34, 215)
|
||||
local batTip <const> = utils.xy(0, 0)
|
||||
local batAngleDeg = C.CrankOffsetDeg
|
||||
|
||||
local catcherThrownBall = false
|
||||
|
||||
---@alias Team { score: number, benchPosition: XyPair }
|
||||
---@type table<string, Team>
|
||||
local teams <const> = {
|
||||
home = {
|
||||
|
@ -63,25 +71,28 @@ local teams <const> = {
|
|||
},
|
||||
}
|
||||
|
||||
local UserTeam <const> = teams.away
|
||||
local battingTeam = teams.away
|
||||
local battingTeamSprites = AwayTeamSprites
|
||||
local fieldingTeamSprites = HomeTeamSprites
|
||||
local runnerBlipper = battingTeam == teams.away and AwayTeamBlipper or HomeTeamBlipper
|
||||
local inning = 1
|
||||
|
||||
local battingTeam = teams.away
|
||||
local offenseState = C.Offense.batting
|
||||
|
||||
-- TODO: Replace with timers, repeatedly reset, instead of constantly setting to 0
|
||||
local secondsSinceLastRunnerMove = 0
|
||||
local secondsSincePitchAllowed = -5
|
||||
local secondsSincePitchAllowed = 0
|
||||
|
||||
local catcherThrownBall = false
|
||||
-- These are only sort-of global state. They are purely graphical,
|
||||
-- but they need to be kept in sync with the rest of the globals.
|
||||
local runnerBlipper = battingTeam == teams.away and AwayTeamBlipper or HomeTeamBlipper
|
||||
local battingTeamSprites = AwayTeamSprites
|
||||
local fieldingTeamSprites = HomeTeamSprites
|
||||
|
||||
local batBase <const> = utils.xy(C.Center.x - 34, 215)
|
||||
local batTip <const> = utils.xy(0, 0)
|
||||
-------------------------
|
||||
-- END OF GLOBAL STATE --
|
||||
-------------------------
|
||||
|
||||
local batAngleDeg = C.CrankOffsetDeg
|
||||
local UserTeam <const> = teams.away
|
||||
|
||||
---@alias SimpleAnimator { currentValue: fun(self): number; reset: fun(self, durationMs: number | nil) }
|
||||
---@alias Pitch { x: SimpleAnimator, y: SimpleAnimator, z: SimpleAnimator | nil }
|
||||
|
||||
---@type Pitch[]
|
||||
|
@ -113,8 +124,12 @@ local Pitches <const> = {
|
|||
},
|
||||
}
|
||||
|
||||
---@return boolean userIsOnSide, boolean playerIsOnOtherSide
|
||||
---@return boolean userIsOnSide, boolean userIsOnOtherSide
|
||||
local function userIsOn(side)
|
||||
if UserTeam == nil then
|
||||
-- Both teams are NPC-driven
|
||||
return false, false
|
||||
end
|
||||
local ret
|
||||
if UserTeam == battingTeam then
|
||||
ret = side == C.Sides.offense
|
||||
|
@ -124,13 +139,7 @@ local function userIsOn(side)
|
|||
return ret, not ret
|
||||
end
|
||||
|
||||
--- Launches the ball from its current position to the given destination.
|
||||
---@param destX number
|
||||
---@param destY number
|
||||
---@param easingFunc EasingFunc
|
||||
---@param flyTimeMs number | nil
|
||||
---@param floaty boolean | nil
|
||||
---@param customBallScaler pd_animator | nil
|
||||
---@type LaunchBall
|
||||
local function launchBall(destX, destY, easingFunc, flyTimeMs, floaty, customBallScaler)
|
||||
throwMeter:reset()
|
||||
ball:launch(destX, destY, easingFunc, flyTimeMs, floaty, customBallScaler)
|
||||
|
@ -174,28 +183,26 @@ local function nextHalfInning()
|
|||
announcer:say("SWITCHING SIDES...")
|
||||
end
|
||||
|
||||
-- TODO: Make the overlay handle its own dang delay.
|
||||
-- Delay to keep end-of-inning on the scoreboard for a few seconds
|
||||
playdate.timer.new(3000, function()
|
||||
battingTeam = currentlyFieldingTeam
|
||||
if gameOver then
|
||||
announcer:say("AND THAT'S THE BALL GAME!")
|
||||
else
|
||||
fielding:resetFielderPositions()
|
||||
if battingTeam == teams.home then
|
||||
battingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = HomeTeamBlipper
|
||||
fieldingTeamSprites = AwayTeamSprites
|
||||
else
|
||||
battingTeamSprites = AwayTeamSprites
|
||||
fieldingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = AwayTeamBlipper
|
||||
inning = inning + 1
|
||||
end
|
||||
if gameOver then
|
||||
announcer:say("AND THAT'S THE BALL GAME!")
|
||||
else
|
||||
fielding:resetFielderPositions()
|
||||
battingTeam = currentlyFieldingTeam
|
||||
playdate.timer.new(2000, function()
|
||||
if battingTeam == teams.home then
|
||||
inning = inning + 1
|
||||
battingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = HomeTeamBlipper
|
||||
fieldingTeamSprites = AwayTeamSprites
|
||||
else
|
||||
battingTeamSprites = AwayTeamSprites
|
||||
fieldingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = AwayTeamBlipper
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local baserunning = Baserunning.new(announcer, nextHalfInning)
|
||||
|
@ -443,7 +450,7 @@ local function updateGameState()
|
|||
end
|
||||
if fielderHoldingBall then
|
||||
local outedSomeRunner = baserunning:outEligibleRunners(fielderHoldingBall)
|
||||
if userOnOffense then
|
||||
if not userOnDefense then
|
||||
npc:fielderAction(offenseState, fielderHoldingBall, outedSomeRunner, ball, launchBall)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ function Npc:runningSpeed(ball)
|
|||
|
||||
local runner1 = self.runners[1]
|
||||
|
||||
local ballIsFar = utils.distanceBetweenZ(ball.x, ball.y, ball.z, runner1.x, runner1.y, 0) > 250
|
||||
local ballIsFar = utils.distanceBetweenZ(ball.x, ball.y, ball.z, runner1.x, runner1.y, 0) > 300
|
||||
|
||||
if ballIsFar or runner1.forcedTo then
|
||||
return baseRunningSpeed
|
||||
|
|
Loading…
Reference in New Issue