From ab39440c2fd564ae76bffc992028a6e335f20804 Mon Sep 17 00:00:00 2001 From: entar Date: Thu, 10 Jul 2025 19:43:45 +0700 Subject: [PATCH] Implemented receptor animations, made holds transparent --- modules/tween.lua | 367 +++++++++++++++++++++++++++++++++++++++ modules/types/note.lua | 1 + modules/types/render.lua | 65 +++++-- sprites/NOTE_assets.json | 273 ----------------------------- stages/billy.lua | 3 + states/playstate.lua | 30 +++- 6 files changed, 451 insertions(+), 288 deletions(-) create mode 100644 modules/tween.lua diff --git a/modules/tween.lua b/modules/tween.lua new file mode 100644 index 0000000..48a1143 --- /dev/null +++ b/modules/tween.lua @@ -0,0 +1,367 @@ +local tween = { + _VERSION = 'tween 2.1.1', + _DESCRIPTION = 'tweening for lua', + _URL = 'https://github.com/kikito/tween.lua', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2014 Enrique GarcĂ­a Cota, Yuichi Tateno, Emmanuel Oga + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +-- easing + +-- Adapted from https://github.com/EmmanuelOga/easing. See LICENSE.txt for credits. +-- For all easing functions: +-- t = time == how much time has to pass for the tweening to complete +-- b = begin == starting property value +-- c = change == ending - beginning +-- d = duration == running time. How much time has passed *right now* + +local pow, sin, cos, pi, sqrt, abs, asin = math.pow, math.sin, math.cos, math.pi, math.sqrt, math.abs, math.asin + +-- linear +local function linear(t, b, c, d) return c * t / d + b end + +-- quad +local function inQuad(t, b, c, d) return c * pow(t / d, 2) + b end +local function outQuad(t, b, c, d) + t = t / d + return -c * t * (t - 2) + b +end +local function inOutQuad(t, b, c, d) + t = t / d * 2 + if t < 1 then return c / 2 * pow(t, 2) + b end + return -c / 2 * ((t - 1) * (t - 3) - 1) + b +end +local function outInQuad(t, b, c, d) + if t < d / 2 then return outQuad(t * 2, b, c / 2, d) end + return inQuad((t * 2) - d, b + c / 2, c / 2, d) +end + +-- cubic +local function inCubic (t, b, c, d) return c * pow(t / d, 3) + b end +local function outCubic(t, b, c, d) return c * (pow(t / d - 1, 3) + 1) + b end +local function inOutCubic(t, b, c, d) + t = t / d * 2 + if t < 1 then return c / 2 * t * t * t + b end + t = t - 2 + return c / 2 * (t * t * t + 2) + b +end +local function outInCubic(t, b, c, d) + if t < d / 2 then return outCubic(t * 2, b, c / 2, d) end + return inCubic((t * 2) - d, b + c / 2, c / 2, d) +end + +-- quart +local function inQuart(t, b, c, d) return c * pow(t / d, 4) + b end +local function outQuart(t, b, c, d) return -c * (pow(t / d - 1, 4) - 1) + b end +local function inOutQuart(t, b, c, d) + t = t / d * 2 + if t < 1 then return c / 2 * pow(t, 4) + b end + return -c / 2 * (pow(t - 2, 4) - 2) + b +end +local function outInQuart(t, b, c, d) + if t < d / 2 then return outQuart(t * 2, b, c / 2, d) end + return inQuart((t * 2) - d, b + c / 2, c / 2, d) +end + +-- quint +local function inQuint(t, b, c, d) return c * pow(t / d, 5) + b end +local function outQuint(t, b, c, d) return c * (pow(t / d - 1, 5) + 1) + b end +local function inOutQuint(t, b, c, d) + t = t / d * 2 + if t < 1 then return c / 2 * pow(t, 5) + b end + return c / 2 * (pow(t - 2, 5) + 2) + b +end +local function outInQuint(t, b, c, d) + if t < d / 2 then return outQuint(t * 2, b, c / 2, d) end + return inQuint((t * 2) - d, b + c / 2, c / 2, d) +end + +-- sine +local function inSine(t, b, c, d) return -c * cos(t / d * (pi / 2)) + c + b end +local function outSine(t, b, c, d) return c * sin(t / d * (pi / 2)) + b end +local function inOutSine(t, b, c, d) return -c / 2 * (cos(pi * t / d) - 1) + b end +local function outInSine(t, b, c, d) + if t < d / 2 then return outSine(t * 2, b, c / 2, d) end + return inSine((t * 2) -d, b + c / 2, c / 2, d) +end + +-- expo +local function inExpo(t, b, c, d) + if t == 0 then return b end + return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001 +end +local function outExpo(t, b, c, d) + if t == d then return b + c end + return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b +end +local function inOutExpo(t, b, c, d) + if t == 0 then return b end + if t == d then return b + c end + t = t / d * 2 + if t < 1 then return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005 end + return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b +end +local function outInExpo(t, b, c, d) + if t < d / 2 then return outExpo(t * 2, b, c / 2, d) end + return inExpo((t * 2) - d, b + c / 2, c / 2, d) +end + +-- circ +local function inCirc(t, b, c, d) return(-c * (sqrt(1 - pow(t / d, 2)) - 1) + b) end +local function outCirc(t, b, c, d) return(c * sqrt(1 - pow(t / d - 1, 2)) + b) end +local function inOutCirc(t, b, c, d) + t = t / d * 2 + if t < 1 then return -c / 2 * (sqrt(1 - t * t) - 1) + b end + t = t - 2 + return c / 2 * (sqrt(1 - t * t) + 1) + b +end +local function outInCirc(t, b, c, d) + if t < d / 2 then return outCirc(t * 2, b, c / 2, d) end + return inCirc((t * 2) - d, b + c / 2, c / 2, d) +end + +-- elastic +local function calculatePAS(p,a,c,d) + p, a = p or d * 0.3, a or 0 + if a < abs(c) then return p, c, p / 4 end -- p, a, s + return p, a, p / (2 * pi) * asin(c/a) -- p,a,s +end +local function inElastic(t, b, c, d, a, p) + local s + if t == 0 then return b end + t = t / d + if t == 1 then return b + c end + p,a,s = calculatePAS(p,a,c,d) + t = t - 1 + return -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b +end +local function outElastic(t, b, c, d, a, p) + local s + if t == 0 then return b end + t = t / d + if t == 1 then return b + c end + p,a,s = calculatePAS(p,a,c,d) + return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b +end +local function inOutElastic(t, b, c, d, a, p) + local s + if t == 0 then return b end + t = t / d * 2 + if t == 2 then return b + c end + p,a,s = calculatePAS(p,a,c,d) + t = t - 1 + if t < 0 then return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b end + return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b +end +local function outInElastic(t, b, c, d, a, p) + if t < d / 2 then return outElastic(t * 2, b, c / 2, d, a, p) end + return inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p) +end + +-- back +local function inBack(t, b, c, d, s) + s = s or 1.70158 + t = t / d + return c * t * t * ((s + 1) * t - s) + b +end +local function outBack(t, b, c, d, s) + s = s or 1.70158 + t = t / d - 1 + return c * (t * t * ((s + 1) * t + s) + 1) + b +end +local function inOutBack(t, b, c, d, s) + s = (s or 1.70158) * 1.525 + t = t / d * 2 + if t < 1 then return c / 2 * (t * t * ((s + 1) * t - s)) + b end + t = t - 2 + return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b +end +local function outInBack(t, b, c, d, s) + if t < d / 2 then return outBack(t * 2, b, c / 2, d, s) end + return inBack((t * 2) - d, b + c / 2, c / 2, d, s) +end + +-- bounce +local function outBounce(t, b, c, d) + t = t / d + if t < 1 / 2.75 then return c * (7.5625 * t * t) + b end + if t < 2 / 2.75 then + t = t - (1.5 / 2.75) + return c * (7.5625 * t * t + 0.75) + b + elseif t < 2.5 / 2.75 then + t = t - (2.25 / 2.75) + return c * (7.5625 * t * t + 0.9375) + b + end + t = t - (2.625 / 2.75) + return c * (7.5625 * t * t + 0.984375) + b +end +local function inBounce(t, b, c, d) return c - outBounce(d - t, 0, c, d) + b end +local function inOutBounce(t, b, c, d) + if t < d / 2 then return inBounce(t * 2, 0, c, d) * 0.5 + b end + return outBounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b +end +local function outInBounce(t, b, c, d) + if t < d / 2 then return outBounce(t * 2, b, c / 2, d) end + return inBounce((t * 2) - d, b + c / 2, c / 2, d) +end + +tween.easing = { + linear = linear, + inQuad = inQuad, outQuad = outQuad, inOutQuad = inOutQuad, outInQuad = outInQuad, + inCubic = inCubic, outCubic = outCubic, inOutCubic = inOutCubic, outInCubic = outInCubic, + inQuart = inQuart, outQuart = outQuart, inOutQuart = inOutQuart, outInQuart = outInQuart, + inQuint = inQuint, outQuint = outQuint, inOutQuint = inOutQuint, outInQuint = outInQuint, + inSine = inSine, outSine = outSine, inOutSine = inOutSine, outInSine = outInSine, + inExpo = inExpo, outExpo = outExpo, inOutExpo = inOutExpo, outInExpo = outInExpo, + inCirc = inCirc, outCirc = outCirc, inOutCirc = inOutCirc, outInCirc = outInCirc, + inElastic = inElastic, outElastic = outElastic, inOutElastic = inOutElastic, outInElastic = outInElastic, + inBack = inBack, outBack = outBack, inOutBack = inOutBack, outInBack = outInBack, + inBounce = inBounce, outBounce = outBounce, inOutBounce = inOutBounce, outInBounce = outInBounce +} + + + +-- private stuff + +local function copyTables(destination, keysTable, valuesTable) + valuesTable = valuesTable or keysTable + local mt = getmetatable(keysTable) + if mt and getmetatable(destination) == nil then + setmetatable(destination, mt) + end + for k,v in pairs(keysTable) do + if type(v) == 'table' then + destination[k] = copyTables({}, v, valuesTable[k]) + else + destination[k] = valuesTable[k] + end + end + return destination +end + +local function checkSubjectAndTargetRecursively(subject, target, path) + path = path or {} + local targetType, newPath + for k,targetValue in pairs(target) do + targetType, newPath = type(targetValue), copyTables({}, path) + table.insert(newPath, tostring(k)) + if targetType == 'number' then + assert(type(subject[k]) == 'number', "Parameter '" .. table.concat(newPath,'/') .. "' is missing from subject or isn't a number") + elseif targetType == 'table' then + checkSubjectAndTargetRecursively(subject[k], targetValue, newPath) + else + assert(targetType == 'number', "Parameter '" .. table.concat(newPath,'/') .. "' must be a number or table of numbers") + end + end +end + +local function checkNewParams(duration, subject, target, easing) + assert(type(duration) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration)) + local tsubject = type(subject) + assert(tsubject == 'table' or tsubject == 'userdata', "subject must be a table or userdata. Was " .. tostring(subject)) + assert(type(target)== 'table', "target must be a table. Was " .. tostring(target)) + assert(type(easing)=='function', "easing must be a function. Was " .. tostring(easing)) + checkSubjectAndTargetRecursively(subject, target) +end + +local function getEasingFunction(easing) + easing = easing or "linear" + if type(easing) == 'string' then + local name = easing + easing = tween.easing[name] + if type(easing) ~= 'function' then + error("The easing function name '" .. name .. "' is invalid") + end + end + return easing +end + +local function performEasingOnSubject(subject, target, initial, clock, duration, easing) + local t,b,c,d + for k,v in pairs(target) do + if type(v) == 'table' then + performEasingOnSubject(subject[k], v, initial[k], clock, duration, easing) + else + t,b,c,d = clock, initial[k], v - initial[k], duration + subject[k] = easing(t,b,c,d) + end + end +end + +-- Tween methods + +local Tween = {} +local Tween_mt = {__index = Tween} + +function Tween:set(clock) + assert(type(clock) == 'number', "clock must be a positive number or 0") + + self.initial = self.initial or copyTables({}, self.target, self.subject) + self.clock = clock + + if self.clock <= 0 then + + self.clock = 0 + copyTables(self.subject, self.initial) + + elseif self.clock >= self.duration then -- the tween has expired + + self.clock = self.duration + copyTables(self.subject, self.target) + + else + + performEasingOnSubject(self.subject, self.target, self.initial, self.clock, self.duration, self.easing) + + end + + return self.clock >= self.duration +end + +function Tween:reset() + return self:set(0) +end + +function Tween:update(dt) + assert(type(dt) == 'number', "dt must be a number") + return self:set(self.clock + dt) +end + + +-- Public interface + +function tween.new(duration, subject, target, easing) + easing = getEasingFunction(easing) + checkNewParams(duration, subject, target, easing) + return setmetatable({ + duration = duration, + subject = subject, + target = target, + easing = easing, + clock = 0 + }, Tween_mt) +end + +return tween \ No newline at end of file diff --git a/modules/types/note.lua b/modules/types/note.lua index d46d7bc..f21b954 100644 --- a/modules/types/note.lua +++ b/modules/types/note.lua @@ -57,6 +57,7 @@ function NoteClass:Spawn() local spriteName if self.hold then sprite.layer = 9 + sprite.alpha = 0.6 self.offset.x = 20 if self.holdEnd then sprite.layer = 10 diff --git a/modules/types/render.lua b/modules/types/render.lua index a473793..b8e56f2 100644 --- a/modules/types/render.lua +++ b/modules/types/render.lua @@ -11,12 +11,13 @@ _G.render = module ---@class Sprite ---@field image love.Image ----@field quads table +---@field quads table> ---@field animation string ---@field position Vector2 ---@field extraOffset Vector2 ---@field modifier number ---@field layer number +---@field alpha number ---Sprite Sheet animatable class local Sprite = {} Sprite.__index = Sprite @@ -28,6 +29,7 @@ Sprite.__index = Sprite ---@field modifier number ---@field rotation number ---@field layer number +---@field alpha number ---Image class local Image = {} Image.__index = Image @@ -40,11 +42,25 @@ Image.__index = Image ---@field modifier number ---@field rotation number ---@field layer number +---@field alpha number ---Rectangle class. local Rectangle = {} Rectangle.__index = Rectangle Rectangle.__class = "Rectangle" +local defaultShader = love.graphics.newShader([[ + extern number alpha; + + vec4 effect(vec4 color, Image text, vec2 text_coor, vec2 screen_coor) { + vec4 main = Texel(text, text_coor); + + main.a *= alpha; + + return main; + } +]]) +defaultShader:send("alpha", 1) + local cachedQuads = {} local cachedImages = {} @@ -79,7 +95,8 @@ function _G.Sprite(image, sheet) extraOffset = Vector2(0,0), rect = false, modifier = 1, - layer = 0 + layer = 0, + alpha = 1 }, Sprite) for index, sprite in next, atlas do @@ -126,7 +143,8 @@ function _G.Sprite(image, sheet) rect = false, modifier = 1, allowedFrame = 0, - layer = 0 + layer = 0, + alpha = 1 }, Sprite) Sprites[#Sprites+1] = newSprite @@ -275,15 +293,20 @@ function module.drawSprites() goto continue end + love.graphics.setShader(defaultShader) + defaultShader:send("alpha", thing.alpha or 1) + if thing.isImage then local cameraOffset = thing.ui and Vector2() or module.cameraPosition if type(thing.shader) == "string" and loadedShaders[thing.shader] then love.graphics.setShader(loadedShaders[thing.shader]) elseif thing.shader then love.graphics.setShader(thing.shader) + else + love.graphics.setShader(defaultShader) end love.graphics.draw(thing.image, thing.position.x + cameraOffset.x * thing.modifier , thing.position.y + cameraOffset.y * thing.modifier, thing.rotation, thing.resize.x * (thing.flipX and -1 or 1), thing.resize.y * (thing.flipY and -1 or 1)) - love.graphics.setShader() + love.graphics.setShader(defaultShader) elseif thing.isSprite then local sprite = thing if sprite.animation and sprite.quads and sprite.quads[sprite.animation] then @@ -302,7 +325,7 @@ function module.drawSprites() love.graphics.draw(sprite.image, quad.quad, (sprite.position.x - quad.offset.x - sprite.extraOffset.x + cameraOffset.x * sprite.modifier), (sprite.position.y - quad.offset.y - sprite.extraOffset.y + cameraOffset.y * sprite.modifier), sprite.rotation or 0, quad.resize.x * (sprite.flipX and -1 or 1), quad.resize.y* (sprite.flipY and -1 or 1)) - love.graphics.setShader() + love.graphics.setShader(defaultShader) end end elseif thing.isRect then @@ -318,25 +341,36 @@ function module.drawSprites() if rect.shader and loadedShaders[rect.shader] then love.graphics.setShader(loadedShaders[rect.shader]) + else + love.graphics.setShader(defaultShader) end love.graphics.draw(rect.image, quad.quad, (rect.position.x + (rect.position.x - quad.offset.x - rect.extraOffset.x) + cameraOffset.x * rect.modifier), (rect.position.y + (rect.position.y - quad.offset.y - rect.extraOffset.y) + cameraOffset.y * rect.modifier), rect.rotation or 0, quad.resize.x * (rect.flipX and -1 or 1), quad.resize.y* (rect.flipY and -1 or 1)) - love.graphics.setShader() + love.graphics.setShader(defaultShader) end elseif thing.isAtlas then local cameraOffset = thing.ui and Vector2() or module.cameraPosition or Vector2() + love.graphics.setShader(thing.shader or defaultShader) + thing.atlas:draw(thing.position.x + (cameraOffset.x * thing.modifier), thing.position.y + (cameraOffset.y * thing.modifier), thing.rotation, thing.resize.x, thing.resize.y) + + love.graphics.setShader(defaultShader) end ::continue:: + love.graphics.setShader() end + love.graphics.setShader() end function module.drawUI() for index, thing in ipairs(leftOvers) do + defaultShader:send("alpha", thing.alpha or 1) + love.graphics.setShader(defaultShader) + if thing.isImage then local cameraOffset = thing.ui and Vector2() or module.cameraPosition love.graphics.draw(thing.image, thing.position.x + cameraOffset.x * thing.modifier , thing.position.y + cameraOffset.y * thing.modifier, thing.rotation, thing.resize.x * (thing.flipX and -1 or 1), thing.resize.y * (thing.flipY and -1 or 1)) @@ -383,9 +417,10 @@ function module.drawUI() elseif thing.isRectangle then love.graphics.rectangle(thing.mode, thing.position.x, thing.position.y, thing.size.x, thing.size.y) end - ::continue:: + love.graphics.setShader() end + love.graphics.setShader() end --- Makes a new Rect object. @@ -416,7 +451,8 @@ function _G.Rect(image, sheet) extraOffset = Vector2(0,0), rect = false, modifier = 1, - layer = 0 + layer = 0, + alpha = 1 }, Sprite) for index, sprite in next, atlas do @@ -459,7 +495,8 @@ function _G.Rect(image, sheet) extraOffset = Vector2(0,0), rect = false, modifier = 1, - layer = 0 + layer = 0, + alpha = 1 }, Sprite) Sprites[#Sprites+1] = newSprite @@ -506,7 +543,8 @@ function _G.Image(path, scrollFactor) position = Vector2(), modifier = scrollFactor or 1, rotation = 0, - layer = 0 + layer = 0, + alpha = 1 }, Image) Images[#Images+1] = newImage @@ -588,6 +626,7 @@ end ---@field rotation number ---@field resize Vector2 ---@field modifier number +---@field alpha number ---Texture Atlas animatable object. local Atlas = {} Atlas.__index = Atlas @@ -616,7 +655,8 @@ function _G.Rectangle(position, size, mode, color) modifier = 1, rotation = 0, layer = 0, - mode = mode or "fill" + mode = mode or "fill", + alpha = 1 }, Rectangle) Rectangles[#Rectangles+1] = Shape @@ -644,7 +684,8 @@ function _G.Atlas(folder) rotation = 0, resize = Vector2(1,1), index = 0, - modifier = 1 + modifier = 1, + alpha = 1 }, Atlas) newAtlas.atlas:load(folder) newAtlas.isAtlas = true diff --git a/sprites/NOTE_assets.json b/sprites/NOTE_assets.json index f13e291..b4066e9 100644 --- a/sprites/NOTE_assets.json +++ b/sprites/NOTE_assets.json @@ -227,118 +227,6 @@ "_width": "146", "_height": "149" }, - { - "_name": "left press0004", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0005", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0006", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0007", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0008", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0009", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0010", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0011", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0012", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0013", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0014", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0015", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0016", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0017", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0018", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, - { - "_name": "left press0019", - "_x": "1898", - "_y": "150", - "_width": "146", - "_height": "149" - }, { "_name": "pruple end hold0000", "_x": "1117", @@ -453,167 +341,6 @@ "_width": "149", "_height": "152" }, - { - "_name": "right press0004", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0005", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0006", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0007", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0008", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0009", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0010", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0011", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0012", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0013", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0014", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0015", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0016", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0017", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0018", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0019", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0020", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0021", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0022", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0023", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0024", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0025", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, - { - "_name": "right press0026", - "_x": "316", - "_y": "398", - "_width": "149", - "_height": "152" - }, { "_name": "up confirm0000", "_x": "488", diff --git a/stages/billy.lua b/stages/billy.lua index 86e8120..cf54472 100644 --- a/stages/billy.lua +++ b/stages/billy.lua @@ -146,6 +146,7 @@ function module.onUpdate(dt, el) note.sprite.position = sharedVars.opponentReceptors[note.direction].position:Add(Vector2(0, -1000)) note.sprite.layer = -3 note.sprite.ui = false + note.sprite.alpha = 0.4 end end for index, note in next, sharedVars.holds do @@ -153,6 +154,7 @@ function module.onUpdate(dt, el) note.sprite.position = sharedVars.opponentReceptors[note.direction].position:Add(Vector2(0, -1000)) note.sprite.layer = -4 note.sprite.ui = false + note.sprite.alpha = 0.05 end end @@ -164,6 +166,7 @@ function module.onUpdate(dt, el) end for index, receptor in next, sharedVars.opponentReceptors do receptor.position = receptor.position:Lerp(moveAway and Vector2(200 * (index - 1), -100) or Vector2(200 * (index - 1), 600), .05) + receptor.alpha = 0.4 end if el > 0 and not introVideo:isPlaying() and not paused and not playedIntro then diff --git a/states/playstate.lua b/states/playstate.lua index 5986b96..44694f7 100644 --- a/states/playstate.lua +++ b/states/playstate.lua @@ -123,6 +123,18 @@ local function state(songName, songDifficulty, show) } } + local receptorOffsets = { + arrow = Vector2(0, 0), + press = Vector2(-5, -5), + confirm = Vector2(35, 35) + } + local receptorAnims = { + "arrow", + "arrow", + "arrow", + "arrow" + } + local directions = { "LEFT", "DOWN", @@ -378,9 +390,11 @@ local function state(songName, songDifficulty, show) if combo > highestCombo then highestCombo = combo end - -- receptors[dir]:PlayAnimation(string.format("%s confirm", string.lower(directions[dir])), 24, false) - -- else - -- receptors[dir]:PlayAnimation(string.format("%s press", string.lower(directions[dir])), 24, false) + receptors[dir]:PlayAnimation(string.format("%s confirm", string.lower(directions[dir])), 24, false) + receptorAnims[dir] = "confirm" + else + receptors[dir]:PlayAnimation(string.format("%s press", string.lower(directions[dir])), 24, false) + receptorAnims[dir] = "press" end end @@ -635,6 +649,8 @@ local function state(songName, songDifficulty, show) hold:Destroy() holdNotes[index] = nil health = health + hold.hitHealth * 0.2 + receptors[hold.direction]:PlayAnimation(string.format("%s confirm", string.lower(directions[hold.direction])), 24, false) + receptorAnims[hold.direction] = "confirm" elseif (hold.position - elapsed) * speed < -150 then hold:Destroy() characters.bf:PlayAnimation("sing"..directions[hold.direction].."miss") @@ -693,6 +709,14 @@ local function state(songName, songDifficulty, show) end end + for index, receptor in next, receptors do + if receptor.ended then + receptor:PlayAnimation(string.format("arrow%s", directions[index]), 24, true) + receptorAnims[index] = "arrow" + end + receptor.extraOffset = receptorOffsets[receptorAnims[index]] + end + if health <= 0 then die() elseif health > 2 then