Skip to content

Commit 6f8f43d

Browse files
authored
Optimize Note & Strum Rendering (#941)
* optimize * Delete the unnecessary * Delete __posPoint * 更新 Note.hx * @:dox(hide) * 更新 Strum.hx * Fix the bug
1 parent a8a5ae7 commit 6f8f43d

2 files changed

Lines changed: 147 additions & 57 deletions

File tree

source/funkin/game/Note.hx

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ class Note extends FlxSprite
126126

127127
static var DEFAULT_FIELDS:Array<String> = ["time", "id", "type", "sLen"];
128128

129-
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note)
130-
{
129+
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) {
131130
super();
132131

133132
moves = false;
@@ -241,23 +240,13 @@ class Note extends FlxSprite
241240
*/
242241
public var strumRelativePos:Bool = true;
243242

244-
override function drawComplex(camera:FlxCamera) {
245-
var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false);
246-
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
247-
if (downscrollCam && __strum != null) {
248-
final xx = x;
249-
x += origin.x - offset.x;
250-
x -= __strum.x; x *= -1; x += __strum.x;
251-
x -= origin.x - offset.x;
252-
x += __strum.width; // ??? maybe this isnt good
253-
super.drawComplex(camera);
254-
x = xx;
255-
} else
256-
super.drawComplex(camera);
257-
}
258-
259-
static var __notePosFrameOffset:FlxPoint = new FlxPoint();
260-
static var __posPoint:FlxPoint = new FlxPoint();
243+
@:dox(hide) static var __lastAngle:Float = Math.NaN;
244+
@:dox(hide) static var __lastAngleSin:Float = 0;
245+
@:dox(hide) static var __lastAngleCos:Float = 0;
246+
@:dox(hide) static var __lastStrumW:Float = Math.NaN;
247+
@:dox(hide) static var __lastStrumH:Float = Math.NaN;
248+
@:dox(hide) static var __lastStrumHalfW:Float = 0;
249+
@:dox(hide) static var __lastStrumHalfH:Float = 0;
261250

262251
override function draw() {
263252
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@@ -266,16 +255,28 @@ class Note extends FlxSprite
266255
var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0;
267256
if (negativeScroll) y -= height;
268257
if (__strum != null && strumRelativePos) {
269-
final pos = __posPoint.set(x, y);
270-
// distance = pos.y , we can use it safely like this
271-
final xx = -origin.x + offset.x + (pos.y * Math.cos((__noteAngle + 90) * FlxAngle.TO_RAD));
272-
final yy = -origin.y + offset.y + (pos.y * Math.sin((__noteAngle + 90) * FlxAngle.TO_RAD));
273-
setPosition(
274-
xx + __strum.x + (__strum.width * 0.5),
275-
yy + __strum.y + (__strum.height * 0.5)
276-
);
258+
final originalX = x;
259+
final originalY = y;
260+
261+
if (__noteAngle != __lastAngle) {
262+
__lastAngle = __noteAngle;
263+
final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD);
264+
__lastAngleSin = result.sin;
265+
__lastAngleCos = result.cos;
266+
}
267+
268+
if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) {
269+
__lastStrumW = __strum.width;
270+
__lastStrumH = __strum.height;
271+
__lastStrumHalfW = __strum.width * 0.5;
272+
__lastStrumHalfH = __strum.height * 0.5;
273+
}
274+
275+
x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW;
276+
y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH;
277277
super.draw();
278-
setPosition(pos.x, pos.y);
278+
x = originalX;
279+
y = originalY;
279280
} else {
280281
super.draw();
281282
}
@@ -284,6 +285,38 @@ class Note extends FlxSprite
284285
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
285286
}
286287

288+
var __lastDownscrollCam:Bool = false;
289+
var __lastX:Float = 0;
290+
291+
@:noCompletion @:dox(hide) override function isOnScreen(?camera:FlxCamera):Bool {
292+
var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false);
293+
294+
if (downscrollCam == __lastDownscrollCam)
295+
return super.isOnScreen(camera);
296+
else
297+
__lastX = x;
298+
299+
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
300+
if (downscrollCam && __strum != null) {
301+
x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width;
302+
}
303+
final isOnScreen = super.isOnScreen(camera);
304+
return isOnScreen;
305+
}
306+
307+
override function drawComplex(camera:FlxCamera):Void {
308+
super.drawComplex(camera);
309+
310+
if (__lastDownscrollCam) {
311+
__lastDownscrollCam = false;
312+
x = __lastX;
313+
}
314+
}
315+
316+
public function isOnScreenOriginal(?camera:FlxCamera):Bool {
317+
return super.isOnScreen(camera);
318+
}
319+
287320
// The * 0.5 is so that it's easier to hit them too late, instead of too early
288321
public var earlyPressWindow:Float = 0.5;
289322
public var latePressWindow:Float = 1;
@@ -294,7 +327,7 @@ class Note extends FlxSprite
294327
if (lastScrollSpeed != scrollSpeed) {
295328
lastScrollSpeed = scrollSpeed;
296329
if (nextSustain != null) {
297-
scale.y = (sustainLength * 0.45 * Math.abs(scrollSpeed)) / frameHeight;
330+
scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight;
298331
updateHitbox();
299332
scale.y += gapFix / frameHeight;
300333
}
@@ -304,18 +337,28 @@ class Note extends FlxSprite
304337
}
305338

306339
public function updateSustainClip() if (wasGoodHit && !noSustainClip) {
307-
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * Math.abs(lastScrollSpeed), 0, 1);
308-
var rect = clipRect == null ? FlxRect.get() : clipRect;
309-
clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
340+
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
341+
@:bypassAccessor {
342+
if (clipRect == null) clipRect = FlxRect.get();
343+
clipRect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
344+
}
345+
@:privateAccess {
346+
if (frame != null && _frame != null)
347+
_frame = frame.clipTo(clipRect, _frame);
348+
}
310349
}
311350

312351
@:noCompletion
313-
override function set_clipRect(rect:FlxRect):FlxRect
314-
{
315-
clipRect = rect;
316-
317-
if (frames != null)
318-
frame = frames.frames[animation.frameIndex];
352+
override function set_clipRect(rect:FlxRect):FlxRect {
353+
@:bypassAccessor clipRect = rect;
354+
355+
@:privateAccess if (frame != null) {
356+
if (rect != null && _frame != null)
357+
_frame = frame.clipTo(rect, _frame);
358+
else if (_frame != null)
359+
_frame = frame.copyTo(_frame);
360+
dirty = true;
361+
}
319362

320363
return rect;
321364
}

source/funkin/game/Strum.hx

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package funkin.game;
22

33
import flixel.math.FlxPoint;
44
import flixel.math.FlxAngle;
5+
import flixel.util.typeLimit.OneOfTwo;
56
import funkin.backend.system.Conductor;
67

78
class Strum extends FlxSprite {
@@ -52,8 +53,27 @@ class Strum extends FlxSprite {
5253
public var updateNotesPosY:Bool = true;
5354
public var extraCopyFields(default, set):Array<String> = [];
5455

55-
private inline function set_extraCopyFields(val:Array<String>)
56-
return extraCopyFields = val == null ? [] : val;
56+
@:noCompletion public var __cachedCopyFields:Array<Array<OneOfTwo<String, Int>>> = null;
57+
58+
private function set_extraCopyFields(val:Array<String>) {
59+
extraCopyFields = val == null ? [] : val;
60+
__cachedCopyFields = null;
61+
return extraCopyFields;
62+
}
63+
64+
private inline function __initCachedCopyFields() {
65+
if (__cachedCopyFields != null) return;
66+
__cachedCopyFields = [for (field in extraCopyFields) CoolUtil.parsePropertyString(field)];
67+
}
68+
69+
private inline function __applyCopyFields(daNote:Note) {
70+
for (i in 0...extraCopyFields.length) {
71+
final parsed = __cachedCopyFields[i];
72+
final fromProp = CoolUtil.parseProperty(this, parsed);
73+
final toProp = CoolUtil.parseProperty(daNote, parsed);
74+
toProp.setValue(fromProp.getValue());
75+
}
76+
}
5777

5878
/**
5979
* Whenever the strum is pressed.
@@ -129,13 +149,28 @@ class Strum extends FlxSprite {
129149
}
130150

131151
public override function draw() {
132-
lastDrawCameras = cameras.copy();
152+
if (cameras.length == 1) {
153+
if (lastDrawCameras.length != 1 || lastDrawCameras[0] != cameras[0]) {
154+
lastDrawCameras = [cameras[0]];
155+
}
156+
} else {
157+
lastDrawCameras = cameras.copy();
158+
}
133159
super.draw();
134160
}
135161

136162
@:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI
137163
@:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED
138164

165+
static var __lastStrumW:Float = Math.NaN;
166+
static var __lastStrumH:Float = Math.NaN;
167+
static var __lastStrumHalfW:Float = 0;
168+
static var __lastStrumHalfH:Float = 0;
169+
static var __noteOffset:FlxPoint = FlxPoint.get();
170+
static var __lastNoteAngle:Float = Math.NaN;
171+
static var __lastAngleCos:Float = 0;
172+
static var __lastAngleSin:Float = 0;
173+
139174
/**
140175
* Updates the position of a note.
141176
* @param daNote The note
@@ -153,8 +188,10 @@ class Strum extends FlxSprite {
153188
}
154189

155190
updateNotePos(daNote);
156-
for (field in extraCopyFields)
157-
CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo
191+
if (extraCopyFields.length > 0) {
192+
__initCachedCopyFields();
193+
__applyCopyFields(daNote);
194+
}
158195
}
159196

160197
private inline function updateNotePos(daNote:Note) {
@@ -169,24 +206,34 @@ class Strum extends FlxSprite {
169206
if (daNote.isSustainNote) daNote.y += daNote.height * 0.5;
170207
}
171208
} else {
209+
if (width != __lastStrumW || height != __lastStrumH) {
210+
__lastStrumW = width;
211+
__lastStrumH = height;
212+
__lastStrumHalfW = width * 0.5;
213+
__lastStrumHalfH = height * 0.5;
214+
}
215+
216+
if (daNote.__noteAngle != __lastNoteAngle) {
217+
__lastNoteAngle = daNote.__noteAngle;
218+
final result = FlxMath.fastSinCos((__lastNoteAngle + 90) * FlxAngle.TO_RAD);
219+
__lastAngleCos = result.cos;
220+
__lastAngleSin = result.sin;
221+
}
222+
172223
final speed = getScrollSpeed(daNote);
173224
final distance = (daNote.strumTime - Conductor.songPosition) * 0.45 * speed;
174-
final __noteAngle = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD);
175-
final angleX = __noteAngle.cos;
176-
final angleY = __noteAngle.sin;
177-
final _noteOffset = FlxPoint.get(angleX * distance, angleY * distance);
178-
_noteOffset.x += -daNote.origin.x + daNote.offset.x;
179-
_noteOffset.y += -daNote.origin.y + daNote.offset.y;
225+
__noteOffset.set(__lastAngleCos * distance, __lastAngleSin * distance);
226+
__noteOffset.x += -daNote.origin.x + daNote.offset.x;
227+
__noteOffset.y += -daNote.origin.y + daNote.offset.y;
180228
if (daNote.isSustainNote) {
181-
final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); // daNote.height works better than this.height in this case ???
182-
_noteOffset.x += angleX * m;
183-
_noteOffset.y += angleY * m;
229+
final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1));
230+
__noteOffset.x += __lastAngleCos * m;
231+
__noteOffset.y += __lastAngleSin * m;
184232
}
185-
_noteOffset.x += x + (width * 0.5);
186-
_noteOffset.y += y + (height * 0.5);
187-
if (shouldX) daNote.x = _noteOffset.x;
188-
if (shouldY) daNote.y = _noteOffset.y;
189-
_noteOffset.put();
233+
__noteOffset.x += x + __lastStrumHalfW;
234+
__noteOffset.y += y + __lastStrumHalfH;
235+
if (shouldX) daNote.x = __noteOffset.x;
236+
if (shouldY) daNote.y = __noteOffset.y;
190237
}
191238
}
192239
}

0 commit comments

Comments
 (0)