Optimize Note & Strum Rendering (#941)

* optimize

* Delete the unnecessary

* Delete __posPoint

* 更新 Note.hx

* @:dox(hide)

* 更新 Strum.hx

* Fix the bug
This commit is contained in:
HEIHUAa
2026-04-03 21:35:27 +07:00
committed by GitHub
parent a8a5ae7a89
commit 6f8f43d3dc
2 changed files with 146 additions and 56 deletions
+80 -37
View File
@@ -126,8 +126,7 @@ class Note extends FlxSprite
static var DEFAULT_FIELDS:Array<String> = ["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,23 +240,13 @@ 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);
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);
}
static var __notePosFrameOffset:FlxPoint = new FlxPoint();
static var __posPoint:FlxPoint = new FlxPoint();
@: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;
@@ -266,16 +255,28 @@ class Note extends FlxSprite
var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0;
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)
);
final originalX = x;
final originalY = y;
if (__noteAngle != __lastAngle) {
__lastAngle = __noteAngle;
final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD);
__lastAngleSin = result.sin;
__lastAngleCos = result.cos;
}
if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) {
__lastStrumW = __strum.width;
__lastStrumH = __strum.height;
__lastStrumHalfW = __strum.width * 0.5;
__lastStrumHalfH = __strum.height * 0.5;
}
x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW;
y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH;
super.draw();
setPosition(pos.x, pos.y);
x = originalX;
y = originalY;
} else {
super.draw();
}
@@ -284,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;
@@ -294,7 +327,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 +337,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;
override function set_clipRect(rect:FlxRect):FlxRect {
@:bypassAccessor clipRect = rect;
if (frames != null)
frame = frames.frames[animation.frameIndex];
@: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;
}
+66 -19
View File
@@ -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<String> = [];
private inline function set_extraCopyFields(val:Array<String>)
return extraCopyFields = val == null ? [] : val;
@:noCompletion public var __cachedCopyFields:Array<Array<OneOfTwo<String, Int>>> = null;
private function set_extraCopyFields(val:Array<String>) {
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((__lastNoteAngle + 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;
}
}
}