New black away uniforms!
Generate sprites from component images during load. Should make it easy to swap out logos at runtime.
|
@ -1,6 +1,9 @@
|
|||
-- GENERATED FILE - DO NOT EDIT
|
||||
-- Instead, edit the source file directly: assets.lua2p.
|
||||
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
DarkPlayerBack = playdate.graphics.image.new("images/game/DarkPlayerBack.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
Glove = playdate.graphics.image.new("images/game/Glove.png")
|
||||
|
@ -9,25 +12,37 @@ Glove = playdate.graphics.image.new("images/game/Glove.png")
|
|||
PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
PlayerBack = playdate.graphics.image.new("images/game/PlayerBack.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
PlayerLowHat = playdate.graphics.image.new("images/game/PlayerLowHat.png")
|
||||
BaseLogo = playdate.graphics.image.new("images/game/BaseLogo.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
Hat = playdate.graphics.image.new("images/game/Hat.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
DarkPlayerBase = playdate.graphics.image.new("images/game/DarkPlayerBase.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
MenuImage = playdate.graphics.image.new("images/game/MenuImage.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
Player = playdate.graphics.image.new("images/game/Player.png")
|
||||
PlayerSmile = playdate.graphics.image.new("images/game/PlayerSmile.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
Minimap = playdate.graphics.image.new("images/game/Minimap.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
FrownLogo = playdate.graphics.image.new("images/game/FrownLogo.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
GrassBackground = playdate.graphics.image.new("images/game/GrassBackground.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
LightPlayerBase = playdate.graphics.image.new("images/game/LightPlayerBase.png")
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
LightPlayerBack = playdate.graphics.image.new("images/game/LightPlayerBack.png")
|
||||
|
||||
--selene: allow(unused_variable)
|
||||
--selene: allow(unscoped_variables)
|
||||
|
|
|
@ -129,6 +129,7 @@ end
|
|||
---@return Runner
|
||||
function Baserunning:newRunner()
|
||||
local new = {
|
||||
-- imageSet = math.random() < C.WokeMeter and FemmeSet or MascSet, -- TODO? lol.
|
||||
x = C.RightHandedBattersBox.x - 60,
|
||||
y = C.RightHandedBattersBox.y + 60,
|
||||
nextBase = C.RightHandedBattersBox,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
-- selene: allow(shadowing)
|
||||
local gfx = playdate.graphics
|
||||
|
||||
local GloveSizeX, GloveSizeY <const> = Glove:getSize()
|
||||
local GloveOffX, GloveOffY <const> = GloveSizeX / 2, GloveSizeY / 2
|
||||
|
||||
|
@ -10,7 +7,7 @@ local GloveOffX, GloveOffY <const> = GloveSizeX / 2, GloveSizeY / 2
|
|||
---@return boolean isHoldingBall
|
||||
local function drawFielderGlove(ball, fielderX, fielderY)
|
||||
local distanceFromBall = utils.distanceBetweenZ(fielderX, fielderY, 0, ball.x, ball.y, ball.z)
|
||||
local shoulderX, shoulderY = fielderX + 10, fielderY + 5
|
||||
local shoulderX, shoulderY = fielderX + 10, fielderY - 5
|
||||
if distanceFromBall > 20 then
|
||||
Glove:draw(shoulderX, shoulderY)
|
||||
return false
|
||||
|
@ -20,11 +17,12 @@ local function drawFielderGlove(ball, fielderX, fielderY)
|
|||
end
|
||||
end
|
||||
|
||||
---@param playerSprites SpriteCollection
|
||||
---@param ball Point3d
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return boolean isHoldingBall
|
||||
function drawFielder(ball, x, y)
|
||||
gfx.fillRect(x, y, 14, 25)
|
||||
function drawFielder(playerSprites, ball, x, y)
|
||||
playerSprites.smiling:draw(x, y - 20)
|
||||
return drawFielderGlove(ball, x, y)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
-- selene: allow(shadowing)
|
||||
local gfx = playdate.graphics
|
||||
|
||||
---@alias SpriteCollection { smiling: pd_image, lowHat: pd_image, frowning: pd_image, back: pd_image }
|
||||
|
||||
---@param image pd_image
|
||||
---@param drawInverted boolean
|
||||
function maybeDrawInverted(image, x, y, drawInverted)
|
||||
-- TODO: Bring logo up a pixel on the dark player base?
|
||||
local drawMode = gfx.getImageDrawMode()
|
||||
if drawInverted then
|
||||
gfx.setImageDrawMode(gfx.kDrawModeInverted)
|
||||
end
|
||||
image:draw(x, y)
|
||||
gfx.setImageDrawMode(drawMode)
|
||||
end
|
||||
|
||||
---@return SpriteCollection
|
||||
---@param base pd_image
|
||||
---@param isDark boolean
|
||||
function buildCollection(base, back, logo, isDark)
|
||||
local smiling = gfx.image.new(base:getSize())
|
||||
gfx.lockFocus(smiling)
|
||||
base:draw(0, 0)
|
||||
Hat:draw(6, 0)
|
||||
PlayerSmile:draw(5, 9)
|
||||
maybeDrawInverted(logo, 3, 25, isDark)
|
||||
|
||||
local lowHat = gfx.image.new(base:getSize())
|
||||
gfx.lockFocus(lowHat)
|
||||
base:draw(0, 0)
|
||||
Hat:draw(6, 2)
|
||||
PlayerSmile:draw(5, 9)
|
||||
maybeDrawInverted(logo, 3, 25, isDark)
|
||||
|
||||
local frowning = gfx.image.new(base:getSize())
|
||||
|
||||
gfx.lockFocus(frowning)
|
||||
base:draw(0, 0)
|
||||
maybeDrawInverted(logo, 3, 25, isDark)
|
||||
Hat:draw(6, 0)
|
||||
PlayerFrown:draw(5, 9)
|
||||
|
||||
gfx.unlockFocus()
|
||||
|
||||
return {
|
||||
smiling = smiling,
|
||||
lowHat = lowHat,
|
||||
frowning = frowning,
|
||||
back = back,
|
||||
}
|
||||
end
|
||||
|
||||
--selene: allow(unscoped_variables)
|
||||
AwayTeamSprites = buildCollection(DarkPlayerBase, DarkPlayerBack, BaseLogo, true)
|
||||
|
||||
--selene: allow(unscoped_variables)
|
||||
HomeTeamSprites = buildCollection(LightPlayerBase, LightPlayerBack, FrownLogo, false)
|
|
@ -156,12 +156,14 @@ function Fielding:celebrate()
|
|||
FielderDanceAnimator:reset(C.DanceBounceMs)
|
||||
end
|
||||
|
||||
---@param fielderSprites SpriteCollection
|
||||
---@param ball Point3d
|
||||
---@return boolean ballIsHeldByAFielder
|
||||
function Fielding:drawFielders(ball)
|
||||
function Fielding:drawFielders(fielderSprites, ball)
|
||||
local ballIsHeld = false
|
||||
local danceOffset = FielderDanceAnimator:currentValue()
|
||||
for _, fielder in pairs(self.fielders) do
|
||||
ballIsHeld = drawFielder(ball, fielder.x, fielder.y + FielderDanceAnimator:currentValue()) or ballIsHeld
|
||||
ballIsHeld = drawFielder(fielderSprites, ball, fielder.x, fielder.y + danceOffset) or ballIsHeld
|
||||
end
|
||||
return ballIsHeld
|
||||
end
|
||||
|
|
|
@ -25,20 +25,23 @@ blipper = {}
|
|||
|
||||
--- Build an object that simply "blips" between the given images at the given interval.
|
||||
--- Expects `playdate.graphics.animation.blinker.updateAll()` to be called on every update.
|
||||
function blipper.new(msInterval, image1, image2)
|
||||
function blipper.new(msInterval, smiling, lowHat)
|
||||
local blinker = playdate.graphics.animation.blinker.new(msInterval, msInterval, true)
|
||||
blinker:start()
|
||||
return {
|
||||
blinker = blinker,
|
||||
image1 = image1,
|
||||
image2 = image2,
|
||||
smiling = smiling,
|
||||
lowHat = lowHat,
|
||||
draw = function(self, disableBlipping, x, y)
|
||||
local currentImage = (disableBlipping or self.blinker.on) and self.image2 or self.image1
|
||||
local offsetY = currentImage == PlayerLowHat and -1 or 0
|
||||
local currentImage = (disableBlipping or self.blinker.on) and self.lowHat or self.smiling
|
||||
local offsetY = currentImage == lowHat and -1 or 0
|
||||
currentImage:draw(x, y + offsetY)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
--selene: allow(unscoped_variables)
|
||||
PlayerImageBlipper = blipper.new(100, Player, PlayerLowHat)
|
||||
HomeTeamBlipper = blipper.new(100, HomeTeamSprites.smiling, HomeTeamSprites.lowHat)
|
||||
|
||||
--selene: allow(unscoped_variables)
|
||||
AwayTeamBlipper = blipper.new(100, AwayTeamSprites.smiling, AwayTeamSprites.lowHat)
|
||||
|
|
After Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 738 B |
After Width: | Height: | Size: 593 B |
After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 601 B |
After Width: | Height: | Size: 603 B |
24
src/main.lua
|
@ -23,6 +23,7 @@ import 'CoreLibs/ui.lua'
|
|||
import 'utils.lua'
|
||||
import 'constants.lua'
|
||||
import 'assets.lua'
|
||||
import 'draw/player.lua'
|
||||
import 'draw/overlay.lua'
|
||||
import 'draw/fielder.lua'
|
||||
|
||||
|
@ -64,6 +65,9 @@ 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 offenseState = C.Offense.batting
|
||||
|
||||
|
@ -174,6 +178,15 @@ local function nextHalfInning()
|
|||
-- Delay to keep end-of-inning on the scoreboard for a few seconds
|
||||
playdate.timer.new(3000, function()
|
||||
battingTeam = currentlyFieldingTeam
|
||||
if battingTeam == teams.home then
|
||||
battingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = HomeTeamBlipper
|
||||
fieldingTeamSprites = AwayTeamSprites
|
||||
else
|
||||
battingTeamSprites = AwayTeamSprites
|
||||
fieldingTeamSprites = HomeTeamSprites
|
||||
runnerBlipper = AwayTeamBlipper
|
||||
end
|
||||
if gameOver then
|
||||
announcer:say("AND THAT'S THE BALL GAME!")
|
||||
else
|
||||
|
@ -279,6 +292,7 @@ local function updateBatting(batDeg, batSpeed)
|
|||
pitchTracker:reset()
|
||||
local hitBallScaler = gfx.animator.new(2000, 9 + (mult * mult * 0.5), C.SmallestBallRadius, utils.easingHill)
|
||||
launchBall(ballDestX, ballDestY, playdate.easingFunctions.outQuint, 2000, nil, hitBallScaler)
|
||||
-- TODO? A dramatic eye-level view on a home-run could be sick.
|
||||
|
||||
if utils.isFoulBall(ballDestX, ballDestY) then
|
||||
announcer:say("Foul ball!")
|
||||
|
@ -451,7 +465,7 @@ function playdate.update()
|
|||
|
||||
GrassBackground:draw(-400, -240)
|
||||
|
||||
local ballIsHeld = fielding:drawFielders(ball)
|
||||
local ballIsHeld = fielding:drawFielders(fieldingTeamSprites, ball)
|
||||
|
||||
if offenseState == C.Offense.batting then
|
||||
gfx.setLineWidth(5)
|
||||
|
@ -463,18 +477,18 @@ function playdate.update()
|
|||
for _, runner in pairs(baserunning.runners) do
|
||||
if runner == baserunning.batter then
|
||||
if batAngleDeg > 50 and batAngleDeg < 200 then
|
||||
PlayerBack:draw(runner.x, runner.y - playerHeightOffset)
|
||||
battingTeamSprites.back:draw(runner.x, runner.y - playerHeightOffset)
|
||||
else
|
||||
Player:draw(runner.x, runner.y - playerHeightOffset)
|
||||
battingTeamSprites.smiling:draw(runner.x, runner.y - playerHeightOffset)
|
||||
end
|
||||
else
|
||||
-- TODO? Change blip speed depending on runner speed?
|
||||
PlayerImageBlipper:draw(false, runner.x, runner.y - playerHeightOffset)
|
||||
runnerBlipper:draw(false, runner.x, runner.y - playerHeightOffset)
|
||||
end
|
||||
end
|
||||
|
||||
for _, runner in pairs(baserunning.outRunners) do
|
||||
PlayerFrown:draw(runner.x, runner.y - playerHeightOffset)
|
||||
battingTeamSprites.frowning:draw(runner.x, runner.y - playerHeightOffset)
|
||||
end
|
||||
|
||||
if not ballIsHeld then
|
||||
|
|