diff --git a/src/Hole.lua b/src/Hole.lua new file mode 100644 index 00000000..06144aa3 --- /dev/null +++ b/src/Hole.lua @@ -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 \ No newline at end of file diff --git a/src/Map.lua b/src/Map.lua index 5d34737c..75ee5818 100644 --- a/src/Map.lua +++ b/src/Map.lua @@ -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") @@ -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 @@ -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 diff --git a/src/Path.lua b/src/Path.lua index 472b654d..9270cf02 100644 --- a/src/Path.lua +++ b/src/Path.lua @@ -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