From 27700d10245e51da5016865f67b84ded524d81bc Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:11:46 +0800 Subject: [PATCH 1/7] optimize --- source/funkin/game/Note.hx | 89 ++++++++++++++++++++++++------------- source/funkin/game/Strum.hx | 85 +++++++++++++++++++++++++++-------- 2 files changed, 123 insertions(+), 51 deletions(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 82879bd3d0..4176c2a5c5 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -126,8 +126,7 @@ class Note extends FlxSprite static var DEFAULT_FIELDS:Array = ["time", "id", "type", "sLen"]; - public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) - { + public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) { super(); moves = false; @@ -241,24 +240,28 @@ class Note extends FlxSprite */ public var strumRelativePos:Bool = true; - override function drawComplex(camera:FlxCamera) { - var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false); + override public function isOnScreen(?camera:FlxCamera):Bool { + var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false); if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); - if (downscrollCam && __strum != null) { - final xx = x; - x += origin.x - offset.x; - x -= __strum.x; x *= -1; x += __strum.x; - x -= origin.x - offset.x; - x += __strum.width; // ??? maybe this isnt good - super.drawComplex(camera); - x = xx; - } else - super.drawComplex(camera); + final oldX = x; + if (downscrollCam && __strum != null) + x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width; + final isOnScreen = super.isOnScreen(camera); + x = oldX; + return isOnScreen; } static var __notePosFrameOffset:FlxPoint = new FlxPoint(); static var __posPoint:FlxPoint = new FlxPoint(); + static var __lastAngle:Float = Math.NaN; + static var __lastAngleSin:Float = 0; + static var __lastAngleCos:Float = 0; + static var __lastStrumW:Float = Math.NaN; + static var __lastStrumH:Float = Math.NaN; + static var __lastStrumHalfW:Float = 0; + static var __lastStrumHalfH:Float = 0; + override function draw() { @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; @:privateAccess if (__strumCameras != null) FlxCamera._defaultCameras = __strumCameras; @@ -267,15 +270,27 @@ class Note extends FlxSprite if (negativeScroll) y -= height; if (__strum != null && strumRelativePos) { final pos = __posPoint.set(x, y); - // distance = pos.y , we can use it safely like this - final xx = -origin.x + offset.x + (pos.y * Math.cos((__noteAngle + 90) * FlxAngle.TO_RAD)); - final yy = -origin.y + offset.y + (pos.y * Math.sin((__noteAngle + 90) * FlxAngle.TO_RAD)); - setPosition( - xx + __strum.x + (__strum.width * 0.5), - yy + __strum.y + (__strum.height * 0.5) - ); + + if (__noteAngle != __lastAngle) { + __lastAngle = __noteAngle; + final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD); + __lastAngleCos = result.cos; + __lastAngleSin = result.sin; + } + + if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) { + __lastStrumW = __strum.width; + __lastStrumH = __strum.height; + __lastStrumHalfW = __strum.width * 0.5; + __lastStrumHalfH = __strum.height * 0.5; + } + + final dist = pos.y; + x = -origin.x + offset.x + (dist * __lastAngleCos) + __strum.x + __lastStrumHalfW; + y = -origin.y + offset.y + (dist * __lastAngleSin) + __strum.y + __lastStrumHalfH; super.draw(); - setPosition(pos.x, pos.y); + x = pos.x; + y = dist; } else { super.draw(); } @@ -294,7 +309,7 @@ class Note extends FlxSprite if (lastScrollSpeed != scrollSpeed) { lastScrollSpeed = scrollSpeed; if (nextSustain != null) { - scale.y = (sustainLength * 0.45 * Math.abs(scrollSpeed)) / frameHeight; + scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight; updateHitbox(); scale.y += gapFix / frameHeight; } @@ -304,18 +319,28 @@ class Note extends FlxSprite } public function updateSustainClip() if (wasGoodHit && !noSustainClip) { - var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * Math.abs(lastScrollSpeed), 0, 1); - var rect = clipRect == null ? FlxRect.get() : clipRect; - clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t)); + var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1); + @:bypassAccessor { + if (clipRect == null) clipRect = FlxRect.get(); + clipRect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t)); + } + @:privateAccess { + if (frame != null && _frame != null) + _frame = frame.clipTo(clipRect, _frame); + } } @:noCompletion - override function set_clipRect(rect:FlxRect):FlxRect - { - clipRect = rect; - - if (frames != null) - frame = frames.frames[animation.frameIndex]; + override function set_clipRect(rect:FlxRect):FlxRect { + @:bypassAccessor clipRect = rect; + + @:privateAccess if (frame != null) { + if (rect != null && _frame != null) + _frame = frame.clipTo(rect, _frame); + else if (_frame != null) + _frame = frame.copyTo(_frame); + dirty = true; + } return rect; } diff --git a/source/funkin/game/Strum.hx b/source/funkin/game/Strum.hx index b075aad85a..5e42e77ef9 100644 --- a/source/funkin/game/Strum.hx +++ b/source/funkin/game/Strum.hx @@ -2,6 +2,7 @@ package funkin.game; import flixel.math.FlxPoint; import flixel.math.FlxAngle; +import flixel.util.typeLimit.OneOfTwo; import funkin.backend.system.Conductor; class Strum extends FlxSprite { @@ -52,8 +53,27 @@ class Strum extends FlxSprite { public var updateNotesPosY:Bool = true; public var extraCopyFields(default, set):Array = []; - private inline function set_extraCopyFields(val:Array) - return extraCopyFields = val == null ? [] : val; + @:noCompletion public var __cachedCopyFields:Array>> = null; + + private function set_extraCopyFields(val:Array) { + extraCopyFields = val == null ? [] : val; + __cachedCopyFields = null; + return extraCopyFields; + } + + private inline function __initCachedCopyFields() { + if (__cachedCopyFields != null) return; + __cachedCopyFields = [for (field in extraCopyFields) CoolUtil.parsePropertyString(field)]; + } + + private inline function __applyCopyFields(daNote:Note) { + for (i in 0...extraCopyFields.length) { + final parsed = __cachedCopyFields[i]; + final fromProp = CoolUtil.parseProperty(this, parsed); + final toProp = CoolUtil.parseProperty(daNote, parsed); + toProp.setValue(fromProp.getValue()); + } + } /** * Whenever the strum is pressed. @@ -129,13 +149,28 @@ class Strum extends FlxSprite { } public override function draw() { - lastDrawCameras = cameras.copy(); + if (cameras.length == 1) { + if (lastDrawCameras.length != 1 || lastDrawCameras[0] != cameras[0]) { + lastDrawCameras = [cameras[0]]; + } + } else { + lastDrawCameras = cameras.copy(); + } super.draw(); } @:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI @:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED + static var __lastStrumW:Float = Math.NaN; + static var __lastStrumH:Float = Math.NaN; + static var __lastStrumHalfW:Float = 0; + static var __lastStrumHalfH:Float = 0; + static var __noteOffset:FlxPoint = FlxPoint.get(); + static var __lastNoteAngle:Float = Math.NaN; + static var __lastAngleCos:Float = 0; + static var __lastAngleSin:Float = 0; + /** * Updates the position of a note. * @param daNote The note @@ -153,8 +188,10 @@ class Strum extends FlxSprite { } updateNotePos(daNote); - for (field in extraCopyFields) - CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo + if (extraCopyFields.length > 0) { + __initCachedCopyFields(); + __applyCopyFields(daNote); + } } private inline function updateNotePos(daNote:Note) { @@ -169,24 +206,34 @@ class Strum extends FlxSprite { if (daNote.isSustainNote) daNote.y += daNote.height * 0.5; } } else { + if (width != __lastStrumW || height != __lastStrumH) { + __lastStrumW = width; + __lastStrumH = height; + __lastStrumHalfW = width * 0.5; + __lastStrumHalfH = height * 0.5; + } + + if (daNote.__noteAngle != __lastNoteAngle) { + __lastNoteAngle = daNote.__noteAngle; + final result = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD); + __lastAngleCos = result.cos; + __lastAngleSin = result.sin; + } + final speed = getScrollSpeed(daNote); final distance = (daNote.strumTime - Conductor.songPosition) * 0.45 * speed; - final __noteAngle = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD); - final angleX = __noteAngle.cos; - final angleY = __noteAngle.sin; - final _noteOffset = FlxPoint.get(angleX * distance, angleY * distance); - _noteOffset.x += -daNote.origin.x + daNote.offset.x; - _noteOffset.y += -daNote.origin.y + daNote.offset.y; + __noteOffset.set(__lastAngleCos * distance, __lastAngleSin * distance); + __noteOffset.x += -daNote.origin.x + daNote.offset.x; + __noteOffset.y += -daNote.origin.y + daNote.offset.y; if (daNote.isSustainNote) { - final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); // daNote.height works better than this.height in this case ??? - _noteOffset.x += angleX * m; - _noteOffset.y += angleY * m; + final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); + __noteOffset.x += __lastAngleCos * m; + __noteOffset.y += __lastAngleSin * m; } - _noteOffset.x += x + (width * 0.5); - _noteOffset.y += y + (height * 0.5); - if (shouldX) daNote.x = _noteOffset.x; - if (shouldY) daNote.y = _noteOffset.y; - _noteOffset.put(); + __noteOffset.x += x + __lastStrumHalfW; + __noteOffset.y += y + __lastStrumHalfH; + if (shouldX) daNote.x = __noteOffset.x; + if (shouldY) daNote.y = __noteOffset.y; } } } From c3c25c8b55f07fe78a204cd030b5555f9bbc0c67 Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:29:40 +0800 Subject: [PATCH 2/7] Delete the unnecessary --- source/funkin/game/Note.hx | 1 - 1 file changed, 1 deletion(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 4176c2a5c5..dc762d4ee2 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -251,7 +251,6 @@ class Note extends FlxSprite return isOnScreen; } - static var __notePosFrameOffset:FlxPoint = new FlxPoint(); static var __posPoint:FlxPoint = new FlxPoint(); static var __lastAngle:Float = Math.NaN; From 071d9f7efce7aeb9d42ab88db460e6e25b3f1e9f Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:40:44 +0800 Subject: [PATCH 3/7] Delete __posPoint --- source/funkin/game/Note.hx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index dc762d4ee2..5cdf12134c 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -251,8 +251,6 @@ class Note extends FlxSprite return isOnScreen; } - static var __posPoint:FlxPoint = new FlxPoint(); - static var __lastAngle:Float = Math.NaN; static var __lastAngleSin:Float = 0; static var __lastAngleCos:Float = 0; @@ -268,7 +266,8 @@ class Note extends FlxSprite var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0; if (negativeScroll) y -= height; if (__strum != null && strumRelativePos) { - final pos = __posPoint.set(x, y); + final originalX = x; + final originalY = y; if (__noteAngle != __lastAngle) { __lastAngle = __noteAngle; @@ -284,12 +283,11 @@ class Note extends FlxSprite __lastStrumHalfH = __strum.height * 0.5; } - final dist = pos.y; - x = -origin.x + offset.x + (dist * __lastAngleCos) + __strum.x + __lastStrumHalfW; - y = -origin.y + offset.y + (dist * __lastAngleSin) + __strum.y + __lastStrumHalfH; + x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW; + y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH; super.draw(); - x = pos.x; - y = dist; + x = originalX; + y = originalY; } else { super.draw(); } From 2b03bc93159352cc1608aa2fb766331b140d4b41 Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:07:17 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Note.hx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/funkin/game/Note.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 5cdf12134c..13a79100ff 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -272,8 +272,8 @@ class Note extends FlxSprite if (__noteAngle != __lastAngle) { __lastAngle = __noteAngle; final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD); - __lastAngleCos = result.cos; __lastAngleSin = result.sin; + __lastAngleCos = result.cos; } if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) { From b77c736d0f9e342a29dd798a4e3eee69f6bba605 Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:10:28 +0800 Subject: [PATCH 5/7] @:dox(hide) --- source/funkin/game/Note.hx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 13a79100ff..1c48f4e004 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -251,13 +251,13 @@ class Note extends FlxSprite return isOnScreen; } - static var __lastAngle:Float = Math.NaN; - static var __lastAngleSin:Float = 0; - static var __lastAngleCos:Float = 0; - static var __lastStrumW:Float = Math.NaN; - static var __lastStrumH:Float = Math.NaN; - static var __lastStrumHalfW:Float = 0; - static var __lastStrumHalfH:Float = 0; + @:dox(hide) static var __lastAngle:Float = Math.NaN; + @:dox(hide) static var __lastAngleSin:Float = 0; + @:dox(hide) static var __lastAngleCos:Float = 0; + @:dox(hide) static var __lastStrumW:Float = Math.NaN; + @:dox(hide) static var __lastStrumH:Float = Math.NaN; + @:dox(hide) static var __lastStrumHalfW:Float = 0; + @:dox(hide) static var __lastStrumHalfH:Float = 0; override function draw() { @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; From 0825488f1cf53aeb4400ff0bf2d8930afb8e03d7 Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Tue, 31 Mar 2026 17:34:08 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Strum.hx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/funkin/game/Strum.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/funkin/game/Strum.hx b/source/funkin/game/Strum.hx index 5e42e77ef9..ede6360fe4 100644 --- a/source/funkin/game/Strum.hx +++ b/source/funkin/game/Strum.hx @@ -215,7 +215,7 @@ class Strum extends FlxSprite { if (daNote.__noteAngle != __lastNoteAngle) { __lastNoteAngle = daNote.__noteAngle; - final result = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD); + final result = FlxMath.fastSinCos((__lastNoteAngle + 90) * FlxAngle.TO_RAD); __lastAngleCos = result.cos; __lastAngleSin = result.sin; } From 7546de130ac1fc16cb5ddb3907841e31b2745381 Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:49:45 +0800 Subject: [PATCH 7/7] Fix the bug --- source/funkin/game/Note.hx | 43 ++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 1c48f4e004..e3d88625ab 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -240,17 +240,6 @@ class Note extends FlxSprite */ public var strumRelativePos:Bool = true; - override public function isOnScreen(?camera:FlxCamera):Bool { - var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false); - if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); - final oldX = x; - if (downscrollCam && __strum != null) - x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width; - final isOnScreen = super.isOnScreen(camera); - x = oldX; - return isOnScreen; - } - @:dox(hide) static var __lastAngle:Float = Math.NaN; @:dox(hide) static var __lastAngleSin:Float = 0; @:dox(hide) static var __lastAngleCos:Float = 0; @@ -296,6 +285,38 @@ class Note extends FlxSprite @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; } + var __lastDownscrollCam:Bool = false; + var __lastX:Float = 0; + + @:noCompletion @:dox(hide) override function isOnScreen(?camera:FlxCamera):Bool { + var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false); + + if (downscrollCam == __lastDownscrollCam) + return super.isOnScreen(camera); + else + __lastX = x; + + if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); + if (downscrollCam && __strum != null) { + x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width; + } + final isOnScreen = super.isOnScreen(camera); + return isOnScreen; + } + + override function drawComplex(camera:FlxCamera):Void { + super.drawComplex(camera); + + if (__lastDownscrollCam) { + __lastDownscrollCam = false; + x = __lastX; + } + } + + public function isOnScreenOriginal(?camera:FlxCamera):Bool { + return super.isOnScreen(camera); + } + // The * 0.5 is so that it's easier to hit them too late, instead of too early public var earlyPressWindow:Float = 0.5; public var latePressWindow:Float = 1;