Merge remote-tracking branch 'origin/main' into internal-merge

This commit is contained in:
Ralty
2026-03-29 13:45:10 +07:00
9 changed files with 599 additions and 71 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime build linux
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL
# - name: Tar files
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
- name: Uploading artifact (executable)
+2 -2
View File
@@ -31,7 +31,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime build mac
haxelib run lime build mac -DCOMPILE_EXPERIMENTAL
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
- name: Uploading artifact (executable)
@@ -100,7 +100,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime build mac -debug
haxelib run lime build mac -debug -DCOMPILE_EXPERIMENTAL
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/debug/macos/bin .
- name: Uploading artifact (entire build)
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
- name: Building the game
run: |
haxelib run lime build windows
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v7
with:
@@ -0,0 +1,471 @@
package funkin.backend.shaders;
import haxe.Exception;
import haxe.io.Path;
import flixel.graphics.FlxGraphic;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxSignal.FlxTypedSignal;
import flixel.util.FlxStringUtil;
import hscript.IHScriptCustomBehaviour;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import openfl.display.Shader;
import openfl.display3D._internal.GLProgram;
import openfl.display3D._internal.GLShader;
import openfl.display3D.Program3D;
import openfl.utils._internal.Log;
using StringTools;
@:access(openfl.display3D.Context3D)
@:access(openfl.display3D.Program3D)
@:access(openfl.display.ShaderInput)
@:access(openfl.display.ShaderParameter)
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
#if REGION /* Backward Compatibility */
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
private static var FRAGMENT_SHADER = 0;
private static var VERTEX_SHADER = 1;
public var glslVer(get, set):String;
inline function get_glslVer():String return glVersion;
inline function set_glslVer(v:String):String return glVersion = v;
public var glRawFragmentSource(get, set):String;
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
public var glRawVertexSource(get, set):String;
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
// Unused... cne-openfl uses a different system
var __cancelNextProcessGLData:Bool = false;
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
#end
public static function getShaderCode(key:String, isFragment = true):Null<String> {
var path = "shaders/" + key;
key = Path.withoutExtension(key);
final ext = Path.extension(path);
if (ext == "") path = path + (isFragment ? ".frag" : ".vert");
else isFragment = ext != "vert";
path = Paths.getPath(path);
return Assets.exists(path) ? Assets.getText(path) : null;
}
private static function processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String
return Shader.processGLSLText(_processGLSLText(source, glVersion, isFragment, pragmas), glVersion, isFragment);
private static function _processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String {
if (pragmas != null) {
final pragmaKeyword = ~/#pragma\s+(\w+)/g;
source = pragmaKeyword.map(source, (_) -> {
var name = pragmaKeyword.matched(1), pragma:String;
if (pragmas.exists(name)) pragma = pragmas.get(name);
else {
if (name != "header" && name != "body") return '#pragma $name';
pragma = "";
}
return _processGLSLText(pragma, glVersion, isFragment, pragmas);
});
}
inline function tryGetShaderCode(key:String) {
final s = getShaderCode(key, isFragment);
if (s == null) {
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader $key', RED),
]);
return "";
}
return s;
}
final includeKeyword = ~/#include ['"](.+)['"]/g;
final importKeyword = ~/#import\s+<(.*)>/g;
source = importKeyword.map(source, (_) ->
return _processGLSLText(tryGetShaderCode(importKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
return source = includeKeyword.map(source, (_) ->
return _processGLSLText(tryGetShaderCode(includeKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
}
private static var __defaultsAvailable:Bool;
private static var __glFragmentSourceDefault:String;
private static var __glVertexSourceDefault:String;
private static var __glFragmentPragmasDefault:Map<String, String>;
private static var __glVertexPragmasDefault:Map<String, String>;
private static var __glFragmentExtensionsDefault:Array<ShaderExtension>;
private static var __glVertexExtensionsDefault:Array<ShaderExtension>;
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
public var fileName:String = "FunkinShader";
public var fragFileName:String = "FunkinShader";
public var vertFileName:String = "FunkinShader";
public var shaderPrefix:String = "";
public var fragmentPrefix:String = "";
public var vertexPrefix:String = "";
private var __immediate:Bool;
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String,
?fragmentExtensions:Array<ShaderExtension>, ?vertexExtensions:Array<ShaderExtension>, immediate = false
) {
if (!__defaultsAvailable) {
__glFragmentSourceDefault = __glFragmentSourceRaw;
__glVertexSourceDefault = __glVertexSourceRaw;
__glFragmentPragmasDefault = __glFragmentPragmas.copy();
__glVertexPragmasDefault = __glVertexPragmas.copy();
__glFragmentExtensionsDefault = __glFragmentExtensions ?? [];
__glVertexExtensionsDefault = __glVertexExtensions ?? [];
__defaultsAvailable = true;
}
__immediate = immediate;
if (version != null) glVersion = version;
if (vertexExtensions != null) glVertexExtensions = vertexExtensions;
if (fragmentExtensions != null) glFragmentExtensions = fragmentExtensions;
if (vertexSource != null) glVertexSource = vertexSource;
if (fragmentSource != null) glFragmentSource = fragmentSource;
super();
if (!__isGenerated) {
__isGenerated = true;
__init();
}
}
public function loadShader(name:String, ?version:String, immediate = false):FunkinShader {
final fragment = getShaderCode(name, true), vertex = getShaderCode(name, false);
glVersion = version;
glVertexSource = vertex ?? __glVertexSourceDefault;
glFragmentSource = fragment ?? __glFragmentSourceDefault;
if (immediate) __init();
return this;
}
override function __initGL():Void {
if (__immediate) {
__context = FlxG.stage.context3D;
__enable();
}
super.__initGL();
}
override function __updateGL():Void {
onGLUpdate.dispatch();
super.__updateGL();
}
public function hget(name:String):Dynamic {
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('get_${name}')) return Reflect.getProperty(this, name);
else if (!Reflect.hasField(__data, name)) return null;
final field:Dynamic = Reflect.field(__data, name);
var cl:String = Type.getClassName(Type.getClass(field));
// little problem we are facing boys...
// cant do "field is ShaderInput" because ShaderInput has the @:generic metadata
// aka instead of ShaderInput<Float> it gets built as ShaderInput_Float
// this should be fine tho because we check the class, and the fields don't vary based on the type
// thanks for looking in the code cne fans :D!! -lunar
if (cl.startsWith("openfl.display.ShaderParameter"))
return (field.__length > 1) ? field.value : field.value[0];
else if (cl.startsWith("openfl.display.ShaderInput"))
return field.input;
return field;
}
public function hset(name:String, val:Dynamic):Dynamic {
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('set_${name}')) {
Reflect.setProperty(this, name, val);
return val;
}
else if (!Reflect.hasField(__data, name)) {
// ??? huh
Reflect.setField(__data, name, val);
return val;
}
var field = Reflect.field(__data, name);
var cl = Type.getClassName(Type.getClass(field));
var isNotNull = val != null;
// cant do "field is ShaderInput" for some reason
if (cl.startsWith("openfl.display.ShaderParameter")) {
if (field.__length <= 1) {
// that means we wait for a single number, instead of an array
if (field.__isInt && isNotNull && !(val is Int)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Int');
return null;
} else
if (field.__isBool && isNotNull && !(val is Bool)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Bool');
return null;
} else
if (field.__isFloat && isNotNull && !(val is Float)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Float');
return null;
}
return field.value = isNotNull ? [val] : null;
} else {
if (isNotNull && !(val is Array)) {
throw new ShaderTypeException(name, Type.getClass(val), Array);
return null;
}
return field.value = val;
}
} else if (cl.startsWith("openfl.display.ShaderInput")) {
// shader input!!
var bitmap:BitmapData;
if (!isNotNull) bitmap = null;
else if (val is BitmapData) bitmap = val;
else if (val is FlxGraphic) bitmap = val.bitmap;
else {
throw new ShaderTypeException(name, Type.getClass(val), BitmapData);
return null;
}
field.input = bitmap;
}
return val;
}
override function __buildSourcePrefix(isFragment:Bool):String {
var result = super.__buildSourcePrefix(isFragment) + '\n$shaderPrefix';
return isFragment ? result + '\n$fragmentPrefix' : result + '\n$vertexPrefix';
}
override function set_glFragmentExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glFragmentExtensionsDefault;
if (value != __glFragmentExtensions) __glSourceDirty = true;
return __glFragmentExtensions = value;
}
override function set_glVertexExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glVertexExtensionsDefault;
if (value != __glVertexExtensions) __glSourceDirty = true;
return __glVertexExtensions = value;
}
override function set_glVersion(value:Null<String>):String {
if (value == null || value == "") value = Flags.DEFAULT_GLSL_VERSION;
if ((__glVersionRaw = value) != __glVersion) {
__glSourceDirty = true;
if (__glVertexSourceRaw != null) __glVertexSource = processGLSLText(__glVertexSourceRaw, value, false, __glVertexPragmas);
if (__glFragmentSourceRaw != null) __glFragmentSource = processGLSLText(__glFragmentSourceRaw, value, true, __glFragmentPragmas);
}
return __glVersion = value;
}
override function set_glFragmentSource(value:String):String {
if (value == null || value == "") value = __glFragmentSourceDefault;
if ((__glFragmentSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, true, __glFragmentPragmas);
}
if (value != __glFragmentSource) __glSourceDirty = true;
return __glFragmentSource = value;
}
override function set_glVertexSource(value:String):String {
if (value == null || value == "") value = __glVertexSourceDefault;
if ((__glVertexSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, false, __glVertexPragmas);
}
if (value != __glVertexSource) __glSourceDirty = true;
return __glVertexSource = value;
}
override function set_glFragmentPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glFragmentPragmasDefault;
if (value != __glFragmentPragmas)
__glSourceDirty = true;
return __glFragmentPragmas = value;
}
override function set_glVertexPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glVertexPragmasDefault;
if (value != __glVertexPragmas)
__glSourceDirty = true;
return __glVertexPragmas = value;
}
function registerParameter(name:String, type:String, isUniform:Bool):Void {
__registerParameter(name, Program3D.getParameterTypeFromGLString(type, 1), 1, -1, isUniform, false, null);
}
public function toString():String
return FlxStringUtil.getDebugString([for (field in Reflect.fields(data)) LabelValuePair.weak(field, Reflect.field(data, field))]);
}
class ShaderTemplates {
#if REGION /* Backward Compatibility */
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
attribute float alpha;
attribute vec4 colorMultiplier;
attribute vec4 colorOffset;
uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
if (hasColorTransform) {
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
}
}
else {
openfl_Alphav = openfl_Alpha * alpha;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
openfl_ColorMultiplierv = openfl_ColorMultiplier;
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(1.0);
}
}";
public static final fragHeader:String = "varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
vec4 apply_flixel_transform(vec4 color) {
if (!hasTransform) return color;
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
color.rgb /= color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
#define applyFlixelEffects(color) apply_flixel_transform(color)
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
return apply_flixel_transform(texture2D(bitmap, coord));
}
uniform vec4 _camSize;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
vec2 getCamPos(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
}
vec2 camToOg(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
}
vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
if (gl_FragColor.a == 0.0) discard;";
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;";
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
}
gl_Position = openfl_Matrix * openfl_Position;";
#end
}
class ShaderTypeException extends Exception {
var has:Class<Dynamic>;
var want:Class<Dynamic>;
var name:String;
public function new(name:String, has:Class<Dynamic>, want:Dynamic) {
this.has = has;
this.want = want;
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
}
@@ -13,8 +13,13 @@ class CodenameBuildField extends TextField {
}
public function reload() {
#if COMPILE_EXPERIMENTAL
text = '${Flags.VERSION_MESSAGE} (Experimental Build)';
#else
text = '${Flags.VERSION_MESSAGE}';
#if debug
#end
#if (debug || COMPILE_EXPERIMENTAL)
text += '\n${Flags.COMMIT_MESSAGE}';
#end
}
+33 -1
View File
@@ -3,6 +3,8 @@ package funkin.backend.utils;
import haxe.macro.Expr;
final class MathUtil {
public static inline var EULER:Float = 2.718281828459;
/**
* Returns the maximum value in the arguments.
* @param args Array of values
@@ -151,6 +153,36 @@ final class MathUtil {
return Math.abs(a - b) > margin;
}
/**
* @param edge0 Float
* @param edge1 Float
* @param x Float
* @return Float
**/
public static function smoothStep(edge0:Float, edge1:Float, x:Float):Float {
var t = (x - edge0) / (edge1 - edge0);
var clamped = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t);
return clamped * clamped * (3.0 - 2.0 * clamped);
}
/**
* @param a Float
* @param b Float
* @param v Float
* @return Float
**/
public static function inverseLerp(a:Float, b:Float, v:Float):Float {
return (v - a) / (b - a);
}
/**
* @param v Float
* @return Float
**/
public static function fract(v:Float):Float {
return v - Math.floor(v);
}
/**
* Shortcut to `Math.max` but with infinite amount of arguments
*
@@ -199,4 +231,4 @@ final class MathUtil {
return macro $expr;
}
#end
}
}
+43 -6
View File
@@ -796,6 +796,7 @@ class Charter extends UIState {
public var mousePos:FlxPoint = new FlxPoint();
public var selectionDragging:Bool = false;
public var isSelecting:Bool = false;
public var isAltCopyDrag:Bool = false;
public function updateSelectionLogic() {
function select(s:ICharterSelectable) {
@@ -960,10 +961,17 @@ class Charter extends UIState {
if (!(verticalChange == 0 && horizontalChange == 0)) {
notesGroup.sortNotes();
undos.addToUndo(CChangeBundle([
CSelectionDrag(undoDrags),
updateEventsGroups(selection)
]));
var changes:Array<CharterChange> = [];
if (isAltCopyDrag) {
changes.push(CCreateSelection(selection.copy()));
isAltCopyDrag = false;
}
changes.push(CSelectionDrag(undoDrags));
changes.push(updateEventsGroups(selection));
undos.addToUndo(CChangeBundle(changes));
} else if (isAltCopyDrag) {
undos.addToUndo(CCreateSelection(selection.copy()));
isAltCopyDrag = false;
}
gridActionType = NONE;
@@ -1018,7 +1026,32 @@ class Charter extends UIState {
}
if ((Math.abs(mousePos.x - dragStartPos.x) > (noteSusDrag ? 1 : 5) || Math.abs(mousePos.y - dragStartPos.y) > (noteSusDrag ? 1 : 5))) {
if (noteHovered) gridActionType = noteHovered ? NOTE_DRAG : INVALID_DRAG;
if (noteHovered) {
if (FlxG.keys.pressed.ALT && selection.length > 0) {
var newSelection:Array<ICharterSelectable> = [];
for (s in selection) {
if (s is CharterNote) {
var n:CharterNote = cast s;
var newNote = new CharterNote();
newNote.updatePos(n.step, n.id, n.susLength, n.type, n.strumLine);
notesGroup.add(newNote);
newSelection.push(newNote);
} else if (s is CharterEvent) {
var e:CharterEvent = cast s;
var newEvent = new CharterEvent(e.step, [for (event in e.events) Reflect.copy(event)], e.global);
newEvent.refreshEventIcons();
(e.global ? rightEventsGroup : leftEventsGroup).add(newEvent);
newSelection.push(newEvent);
}
}
for (s in selection) s.selected = false;
selection = newSelection;
for (s in selection) s.selected = true;
isAltCopyDrag = true;
UIState.playEditorSound(Flags.DEFAULT_EDITOR_COPY_SOUND);
}
gridActionType = NOTE_DRAG;
}
if (noteSusDrag) gridActionType = SUSTAIN_DRAG;
}
}
@@ -1736,7 +1769,11 @@ class Charter extends UIState {
case CEditSpecNotesType(notes, oldTypes, newTypes):
for(i=>note in notes) note.updatePos(note.step, note.id, note.susLength, oldTypes[i]);
case CChangeBundle(changes):
for (change in changes) _undo(change);
var i = changes.length - 1;
while (i >= 0) {
_undo(changes[i]);
i--;
}
}
}
+21 -28
View File
@@ -1,6 +1,7 @@
package funkin.game;
import flixel.math.FlxPoint;
import flixel.math.FlxAngle;
import flixel.math.FlxRect;
import funkin.backend.chart.ChartData;
import funkin.backend.scripting.events.note.NoteCreationEvent;
@@ -243,10 +244,14 @@ class Note extends FlxSprite
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) {
frameOffset.y += __notePosFrameOffset.y * 2;
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);
frameOffset.y -= __notePosFrameOffset.y * 2;
x = xx;
} else
super.drawComplex(camera);
}
@@ -258,36 +263,24 @@ class Note extends FlxSprite
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@:privateAccess if (__strumCameras != null) FlxCamera._defaultCameras = __strumCameras;
var negativeScroll = isSustainNote && nextSustain != null && lastScrollSpeed < 0;
if (negativeScroll) offset.y *= -1;
var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0;
if (negativeScroll) y -= height;
if (__strum != null && strumRelativePos) {
var pos = __posPoint.set(x, y);
setPosition(__strum.x, __strum.y);
__notePosFrameOffset.set(pos.x / scale.x, pos.y / scale.y);
frameOffset.x -= __notePosFrameOffset.x;
frameOffset.y -= __notePosFrameOffset.y;
this.frameOffsetAngle = __noteAngle;
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)
);
super.draw();
this.frameOffsetAngle = 0;
frameOffset.x += __notePosFrameOffset.x;
frameOffset.y += __notePosFrameOffset.y;
setPosition(pos.x, pos.y);
//pos.put();
} else {
__notePosFrameOffset.set(0, 0);
super.draw();
}
if (negativeScroll) y += height;
if (negativeScroll) offset.y *= -1;
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
}
@@ -301,7 +294,7 @@ class Note extends FlxSprite
if (lastScrollSpeed != scrollSpeed) {
lastScrollSpeed = scrollSpeed;
if (nextSustain != null) {
scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight;
scale.y = (sustainLength * 0.45 * Math.abs(scrollSpeed)) / frameHeight;
updateHitbox();
scale.y += gapFix / frameHeight;
}
@@ -311,7 +304,7 @@ class Note extends FlxSprite
}
public function updateSustainClip() if (wasGoodHit && !noSustainClip) {
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
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));
}
+21 -31
View File
@@ -1,6 +1,7 @@
package funkin.game;
import flixel.math.FlxPoint;
import flixel.math.FlxAngle;
import funkin.backend.system.Conductor;
class Strum extends FlxSprite {
@@ -162,41 +163,30 @@ class Strum extends FlxSprite {
if (shouldX || shouldY) {
if (daNote.strumRelativePos) {
if (shouldX) daNote.x = (this.width - daNote.width) * 0.5;
if (shouldX) daNote.x = 0;
if (shouldY) {
daNote.y = (daNote.strumTime - Conductor.songPosition) * (0.45 * getScrollSpeed(daNote));
if (daNote.isSustainNote) daNote.y += height * 0.5;
daNote.y = ((daNote.strumTime - Conductor.songPosition) * 0.45 * getScrollSpeed(daNote));
if (daNote.isSustainNote) daNote.y += daNote.height * 0.5;
}
} else {
var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * getScrollSpeed(daNote)));
var realOffset = FlxPoint.get(0, 0);
if (daNote.isSustainNote) offset.y -= height * 0.5;
if (Std.int(daNote.__noteAngle % 360) != 0) {
var noteAngle = FlxMath.fastSinCos(daNote.__noteAngle / PIX180);
var noteAngleCos = noteAngle.cos;
var noteAngleSin = noteAngle.sin;
var aOffset:FlxPoint = FlxPoint.get(
(daNote.origin.x / daNote.scale.x) - daNote.offset.x,
(daNote.origin.y / daNote.scale.y) - daNote.offset.y
);
realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y));
realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y));
aOffset.put();
} else {
realOffset.x = offset.x;
realOffset.y = offset.y;
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;
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;
}
realOffset.y *= -1;
if (shouldX) daNote.x = x + realOffset.x;
if (shouldY) daNote.y = y + realOffset.y;
offset.put();
realOffset.put();
_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();
}
}
}