Skip to content
This repository has been archived by the owner on May 6, 2024. It is now read-only.

Commit

Permalink
Make the skull animations smooth
Browse files Browse the repository at this point in the history
This moves skulls into their own class - Hole (just like the original code for Zuma), and it borrows code from UIWidgetSpriteProgress.

Contributes to issue #9
  • Loading branch information
ShamblesSM committed Feb 21, 2023
1 parent f5f66ea commit 05631b4
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 44 deletions.
91 changes: 91 additions & 0 deletions src/Hole.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
local class = require "com.class"

---@class Hole
---@overload fun(params):Hole
local Hole = class:derive("Hole")

local Vec2 = require("src.Essentials.Vector2")



--[[
!! READ BEFORE IMPLEMENTING THIS TO UPSTREAM !!
This fork-specific class has hardcoded values. De-hardcode and allow for
customization before implementing to upstream.
This only allows for smooth movement of the top sprite. Consider the following
prior to implementing this class to upstream:
- allow ZD-style skull animations (sprite states)
- allow multiple animations/sprite positions
- allow multiple effects
- etc...
]]

---Initializes a new Hole.
---@param path Path
function Hole:new(path)
self.path = path
self.pos = Vec2.round(path.nodes[#path.nodes].pos)

self.skullHoleSprite = _Game.resourceManager:getSprite("sprites/game/skull_hole.json")
self.skullMaskSprite = _Game.resourceManager:getSprite("sprites/game/skull_mask.json")
self.skullFrameSprite = _Game.resourceManager:getSprite("sprites/game/skull_frame.json")
self.skullTopSprite = _Game.resourceManager:getSprite("sprites/game/skull_top.json")
self.skullBottomSprite = _Game.resourceManager:getSprite("sprites/game/skull_bottom.json")
self.skullMaskShader = love.graphics.newShader [[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0)) {
// a discarded pixel wont be applied as the stencil.
discard;
}
return vec4(1.0);
}
]]

self.topSpriteOffset = 0
-- the bottom sprite doesn't move
end



function Hole:update(dt)
local dangerProgress = self.path:getDangerProgress()

-- top sprite
local topSpriteOffsetBuffer = dangerProgress*20
if self.topSpriteOffset < topSpriteOffsetBuffer then
self.topSpriteOffset = math.min(self.topSpriteOffset + 20 * dt, topSpriteOffsetBuffer)
elseif self.topSpriteOffset > topSpriteOffsetBuffer then
self.topSpriteOffset = math.max(self.topSpriteOffset - 4 * dt, topSpriteOffsetBuffer)
end

-- ring of fire
-- the ring of fire uses some sort of animation that changes depending on the state,
-- an opacity value won't do
end



function Hole:draw()
self.skullHoleSprite:draw(self.pos, Vec2(0.5,0.5))
love.graphics.stencil(function()
love.graphics.setShader(self.skullMaskShader)
self.skullMaskSprite:draw(self.pos, Vec2(0.5,0.5))
love.graphics.setShader()
end, "replace", 1)
love.graphics.setStencilTest("greater", 0)

local skullTopPos = Vec2(self.pos.x, (self.pos.y-3) - self.topSpriteOffset)
local skullBotPos = Vec2(self.pos.x, self.pos.y+10)

self.skullTopSprite:draw(skullTopPos, Vec2(0.5,0.5))
self.skullBottomSprite:draw(skullBotPos, Vec2(0.5, 0.5))

love.graphics.setStencilTest()
self.skullFrameSprite:draw(self.pos, Vec2(0.5,0.5))
end



return Hole
54 changes: 10 additions & 44 deletions src/Map.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ local Vec2 = require("src.Essentials.Vector2")
local Sprite = require("src.Essentials.Sprite")

local Path = require("src.Path")
local Hole = require("src.Hole")



Expand Down Expand Up @@ -42,29 +43,11 @@ function Map:new(level, path, pathsBehavior, isDummy)
end
self.shooter = data.shooter
self.targetPoints = data.targetPoints

-- FORK-SPECIFIC CODE:
-- Skulls. SPRITES ARE HARDCODED, DE-HARDCODE FIRST AND ALLOW FOR
-- CUSTOMIZATION BY THE MODDER IF THIS IS TO BE IMPLEMENTED TO UPSTREAM.
self.skullHoleSprite = _Game.resourceManager:getSprite("sprites/game/skull_hole.json")
self.skullMaskSprite = _Game.resourceManager:getSprite("sprites/game/skull_mask.json")
self.skullFrameSprite = _Game.resourceManager:getSprite("sprites/game/skull_frame.json")
self.skullTopSprite = _Game.resourceManager:getSprite("sprites/game/skull_top.json")
self.skullBottomSprite = _Game.resourceManager:getSprite("sprites/game/skull_bottom.json")
self.skullMaskShader = love.graphics.newShader[[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0)) {
// a discarded pixel wont be applied as the stencil.
discard;
}
return vec4(1.0);
}
]]

self.skullPoints = {}
for _, path in pairs(self.paths) do
local lastPoint = path.nodes[#path.nodes].pos
table.insert(self.skullPoints, Vec2.round(lastPoint))

---@type Hole[]
self.holes = {}
for _, pathp in pairs(self.paths) do
table.insert(self.holes, Hole(pathp))
end
end

Expand Down Expand Up @@ -129,28 +112,11 @@ function Map:draw()
end
end
end

-- FORK-SPECIFIC CODE: skull rendering goes here
-- i took this from the love2d page is this a dirty way to do it
for i, pos in pairs(self.skullPoints) do
self.skullHoleSprite:draw(pos, Vec2(0.5,0.5))
love.graphics.stencil(function()
love.graphics.setShader(self.skullMaskShader)
self.skullMaskSprite:draw(pos, Vec2(0.5,0.5))
love.graphics.setShader()
end, "replace", 1)
love.graphics.setStencilTest("greater", 0)

local skullTopPos = Vec2(pos.x, (pos.y-3) - (self.paths[i]:getDangerProgress()*20))
local skullBotPos = Vec2(pos.x, pos.y+10)

self.skullTopSprite:draw(skullTopPos, Vec2(0.5,0.5))
self.skullBottomSprite:draw(skullBotPos, Vec2(0.5, 0.5))

love.graphics.setStencilTest()
self.skullFrameSprite:draw(pos, Vec2(0.5,0.5))

-- Holes
for _, hole in pairs(self.holes) do
hole:draw()
end
-- END FORK-SPECIFIC CODE
end


Expand Down
5 changes: 5 additions & 0 deletions src/Path.lua
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ function Path:update(dt)
if scorpion.delQueue then table.remove(self.scorpions, i) end
end

-- Holes
for _, hole in pairs(self.map.holes) do
hole:update(dt)
end

-- Path Clears
if self:isValidForCurveClear() then
self.pathClearGranted = true
Expand Down

0 comments on commit 05631b4

Please sign in to comment.