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
|
-- GENERATED FILE - DO NOT EDIT
|
||||||
-- Instead, edit the source file directly: assets.lua2p.
|
-- 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(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--selene: allow(unscoped_variables)
|
||||||
Glove = playdate.graphics.image.new("images/game/Glove.png")
|
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")
|
PlayerFrown = playdate.graphics.image.new("images/game/PlayerFrown.png")
|
||||||
--selene: allow(unused_variable)
|
--selene: allow(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--selene: allow(unscoped_variables)
|
||||||
PlayerBack = playdate.graphics.image.new("images/game/PlayerBack.png")
|
BaseLogo = playdate.graphics.image.new("images/game/BaseLogo.png")
|
||||||
--selene: allow(unused_variable)
|
|
||||||
--selene: allow(unscoped_variables)
|
|
||||||
PlayerLowHat = playdate.graphics.image.new("images/game/PlayerLowHat.png")
|
|
||||||
--selene: allow(unused_variable)
|
--selene: allow(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--selene: allow(unscoped_variables)
|
||||||
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
|
GloveHoldingBall = playdate.graphics.image.new("images/game/GloveHoldingBall.png")
|
||||||
--selene: allow(unused_variable)
|
--selene: allow(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--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")
|
MenuImage = playdate.graphics.image.new("images/game/MenuImage.png")
|
||||||
--selene: allow(unused_variable)
|
--selene: allow(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--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(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--selene: allow(unscoped_variables)
|
||||||
Minimap = playdate.graphics.image.new("images/game/Minimap.png")
|
Minimap = playdate.graphics.image.new("images/game/Minimap.png")
|
||||||
--selene: allow(unused_variable)
|
--selene: allow(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--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")
|
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(unused_variable)
|
||||||
--selene: allow(unscoped_variables)
|
--selene: allow(unscoped_variables)
|
||||||
|
|
|
@ -129,6 +129,7 @@ end
|
||||||
---@return Runner
|
---@return Runner
|
||||||
function Baserunning:newRunner()
|
function Baserunning:newRunner()
|
||||||
local new = {
|
local new = {
|
||||||
|
-- imageSet = math.random() < C.WokeMeter and FemmeSet or MascSet, -- TODO? lol.
|
||||||
x = C.RightHandedBattersBox.x - 60,
|
x = C.RightHandedBattersBox.x - 60,
|
||||||
y = C.RightHandedBattersBox.y + 60,
|
y = C.RightHandedBattersBox.y + 60,
|
||||||
nextBase = C.RightHandedBattersBox,
|
nextBase = C.RightHandedBattersBox,
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
-- selene: allow(shadowing)
|
|
||||||
local gfx = playdate.graphics
|
|
||||||
|
|
||||||
local GloveSizeX, GloveSizeY <const> = Glove:getSize()
|
local GloveSizeX, GloveSizeY <const> = Glove:getSize()
|
||||||
local GloveOffX, GloveOffY <const> = GloveSizeX / 2, GloveSizeY / 2
|
local GloveOffX, GloveOffY <const> = GloveSizeX / 2, GloveSizeY / 2
|
||||||
|
|
||||||
|
@ -10,7 +7,7 @@ local GloveOffX, GloveOffY <const> = GloveSizeX / 2, GloveSizeY / 2
|
||||||
---@return boolean isHoldingBall
|
---@return boolean isHoldingBall
|
||||||
local function drawFielderGlove(ball, fielderX, fielderY)
|
local function drawFielderGlove(ball, fielderX, fielderY)
|
||||||
local distanceFromBall = utils.distanceBetweenZ(fielderX, fielderY, 0, ball.x, ball.y, ball.z)
|
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
|
if distanceFromBall > 20 then
|
||||||
Glove:draw(shoulderX, shoulderY)
|
Glove:draw(shoulderX, shoulderY)
|
||||||
return false
|
return false
|
||||||
|
@ -20,11 +17,12 @@ local function drawFielderGlove(ball, fielderX, fielderY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param playerSprites SpriteCollection
|
||||||
---@param ball Point3d
|
---@param ball Point3d
|
||||||
---@param x number
|
---@param x number
|
||||||
---@param y number
|
---@param y number
|
||||||
---@return boolean isHoldingBall
|
---@return boolean isHoldingBall
|
||||||
function drawFielder(ball, x, y)
|
function drawFielder(playerSprites, ball, x, y)
|
||||||
gfx.fillRect(x, y, 14, 25)
|
playerSprites.smiling:draw(x, y - 20)
|
||||||
return drawFielderGlove(ball, x, y)
|
return drawFielderGlove(ball, x, y)
|
||||||
end
|
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)
|
FielderDanceAnimator:reset(C.DanceBounceMs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param fielderSprites SpriteCollection
|
||||||
---@param ball Point3d
|
---@param ball Point3d
|
||||||
---@return boolean ballIsHeldByAFielder
|
---@return boolean ballIsHeldByAFielder
|
||||||
function Fielding:drawFielders(ball)
|
function Fielding:drawFielders(fielderSprites, ball)
|
||||||
local ballIsHeld = false
|
local ballIsHeld = false
|
||||||
|
local danceOffset = FielderDanceAnimator:currentValue()
|
||||||
for _, fielder in pairs(self.fielders) do
|
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
|
end
|
||||||
return ballIsHeld
|
return ballIsHeld
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,20 +25,23 @@ blipper = {}
|
||||||
|
|
||||||
--- Build an object that simply "blips" between the given images at the given interval.
|
--- 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.
|
--- 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)
|
local blinker = playdate.graphics.animation.blinker.new(msInterval, msInterval, true)
|
||||||
blinker:start()
|
blinker:start()
|
||||||
return {
|
return {
|
||||||
blinker = blinker,
|
blinker = blinker,
|
||||||
image1 = image1,
|
smiling = smiling,
|
||||||
image2 = image2,
|
lowHat = lowHat,
|
||||||
draw = function(self, disableBlipping, x, y)
|
draw = function(self, disableBlipping, x, y)
|
||||||
local currentImage = (disableBlipping or self.blinker.on) and self.image2 or self.image1
|
local currentImage = (disableBlipping or self.blinker.on) and self.lowHat or self.smiling
|
||||||
local offsetY = currentImage == PlayerLowHat and -1 or 0
|
local offsetY = currentImage == lowHat and -1 or 0
|
||||||
currentImage:draw(x, y + offsetY)
|
currentImage:draw(x, y + offsetY)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
--selene: allow(unscoped_variables)
|
--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 'utils.lua'
|
||||||
import 'constants.lua'
|
import 'constants.lua'
|
||||||
import 'assets.lua'
|
import 'assets.lua'
|
||||||
|
import 'draw/player.lua'
|
||||||
import 'draw/overlay.lua'
|
import 'draw/overlay.lua'
|
||||||
import 'draw/fielder.lua'
|
import 'draw/fielder.lua'
|
||||||
|
|
||||||
|
@ -64,6 +65,9 @@ local teams <const> = {
|
||||||
|
|
||||||
local UserTeam <const> = teams.away
|
local UserTeam <const> = teams.away
|
||||||
local battingTeam = 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 inning = 1
|
||||||
local offenseState = C.Offense.batting
|
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
|
-- Delay to keep end-of-inning on the scoreboard for a few seconds
|
||||||
playdate.timer.new(3000, function()
|
playdate.timer.new(3000, function()
|
||||||
battingTeam = currentlyFieldingTeam
|
battingTeam = currentlyFieldingTeam
|
||||||
|
if battingTeam == teams.home then
|
||||||
|
battingTeamSprites = HomeTeamSprites
|
||||||
|
runnerBlipper = HomeTeamBlipper
|
||||||
|
fieldingTeamSprites = AwayTeamSprites
|
||||||
|
else
|
||||||
|
battingTeamSprites = AwayTeamSprites
|
||||||
|
fieldingTeamSprites = HomeTeamSprites
|
||||||
|
runnerBlipper = AwayTeamBlipper
|
||||||
|
end
|
||||||
if gameOver then
|
if gameOver then
|
||||||
announcer:say("AND THAT'S THE BALL GAME!")
|
announcer:say("AND THAT'S THE BALL GAME!")
|
||||||
else
|
else
|
||||||
|
@ -279,6 +292,7 @@ local function updateBatting(batDeg, batSpeed)
|
||||||
pitchTracker:reset()
|
pitchTracker:reset()
|
||||||
local hitBallScaler = gfx.animator.new(2000, 9 + (mult * mult * 0.5), C.SmallestBallRadius, utils.easingHill)
|
local hitBallScaler = gfx.animator.new(2000, 9 + (mult * mult * 0.5), C.SmallestBallRadius, utils.easingHill)
|
||||||
launchBall(ballDestX, ballDestY, playdate.easingFunctions.outQuint, 2000, nil, hitBallScaler)
|
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
|
if utils.isFoulBall(ballDestX, ballDestY) then
|
||||||
announcer:say("Foul ball!")
|
announcer:say("Foul ball!")
|
||||||
|
@ -451,7 +465,7 @@ function playdate.update()
|
||||||
|
|
||||||
GrassBackground:draw(-400, -240)
|
GrassBackground:draw(-400, -240)
|
||||||
|
|
||||||
local ballIsHeld = fielding:drawFielders(ball)
|
local ballIsHeld = fielding:drawFielders(fieldingTeamSprites, ball)
|
||||||
|
|
||||||
if offenseState == C.Offense.batting then
|
if offenseState == C.Offense.batting then
|
||||||
gfx.setLineWidth(5)
|
gfx.setLineWidth(5)
|
||||||
|
@ -463,18 +477,18 @@ function playdate.update()
|
||||||
for _, runner in pairs(baserunning.runners) do
|
for _, runner in pairs(baserunning.runners) do
|
||||||
if runner == baserunning.batter then
|
if runner == baserunning.batter then
|
||||||
if batAngleDeg > 50 and batAngleDeg < 200 then
|
if batAngleDeg > 50 and batAngleDeg < 200 then
|
||||||
PlayerBack:draw(runner.x, runner.y - playerHeightOffset)
|
battingTeamSprites.back:draw(runner.x, runner.y - playerHeightOffset)
|
||||||
else
|
else
|
||||||
Player:draw(runner.x, runner.y - playerHeightOffset)
|
battingTeamSprites.smiling:draw(runner.x, runner.y - playerHeightOffset)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- TODO? Change blip speed depending on runner speed?
|
-- 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
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, runner in pairs(baserunning.outRunners) do
|
for _, runner in pairs(baserunning.outRunners) do
|
||||||
PlayerFrown:draw(runner.x, runner.y - playerHeightOffset)
|
battingTeamSprites.frowning:draw(runner.x, runner.y - playerHeightOffset)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not ballIsHeld then
|
if not ballIsHeld then
|
||||||
|
|