2023-06-22 05:41:01 +00:00
|
|
|
package funkin.play.notes;
|
|
|
|
|
2023-09-08 21:46:44 +00:00
|
|
|
import funkin.data.song.SongData.SongNoteData;
|
2024-06-22 18:49:30 +00:00
|
|
|
import funkin.data.song.SongData.NoteParamData;
|
2023-07-14 00:27:45 +00:00
|
|
|
import funkin.play.notes.notestyle.NoteStyle;
|
2023-06-22 05:41:01 +00:00
|
|
|
import flixel.graphics.frames.FlxAtlasFrames;
|
|
|
|
import flixel.FlxSprite;
|
2024-02-22 23:55:24 +00:00
|
|
|
import funkin.graphics.FunkinSprite;
|
2024-01-16 03:10:42 +00:00
|
|
|
import funkin.graphics.shaders.HSVShader;
|
2023-06-22 05:41:01 +00:00
|
|
|
|
2024-02-22 23:55:24 +00:00
|
|
|
class NoteSprite extends FunkinSprite
|
2023-06-22 05:41:01 +00:00
|
|
|
{
|
|
|
|
static final DIRECTION_COLORS:Array<String> = ['purple', 'blue', 'green', 'red'];
|
|
|
|
|
|
|
|
public var holdNoteSprite:SustainTrail;
|
|
|
|
|
2024-01-16 03:10:42 +00:00
|
|
|
var hsvShader:HSVShader;
|
|
|
|
|
2023-06-22 05:41:01 +00:00
|
|
|
/**
|
2024-03-03 03:46:13 +00:00
|
|
|
* The strum time at which the note should be hit, in milliseconds.
|
2023-06-22 05:41:01 +00:00
|
|
|
*/
|
2024-03-03 03:46:13 +00:00
|
|
|
public var strumTime(get, set):Float;
|
|
|
|
|
|
|
|
function get_strumTime():Float
|
|
|
|
{
|
|
|
|
return this.noteData?.time ?? 0.0;
|
|
|
|
}
|
2023-06-22 05:41:01 +00:00
|
|
|
|
|
|
|
function set_strumTime(value:Float):Float
|
|
|
|
{
|
2024-03-03 03:46:13 +00:00
|
|
|
if (this.noteData == null) return value;
|
|
|
|
return this.noteData.time = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The length for which the note should be held, in milliseconds.
|
|
|
|
* Defaults to 0 for single notes.
|
|
|
|
*/
|
|
|
|
public var length(get, set):Float;
|
|
|
|
|
|
|
|
function get_length():Float
|
|
|
|
{
|
|
|
|
return this.noteData?.length ?? 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function set_length(value:Float):Float
|
|
|
|
{
|
|
|
|
if (this.noteData == null) return value;
|
|
|
|
return this.noteData.length = value;
|
2023-06-22 05:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An extra attribute for the note.
|
|
|
|
* For example, whether the note is an "alt" note, or whether it has custom behavior on hit.
|
|
|
|
*/
|
2024-03-03 03:46:13 +00:00
|
|
|
public var kind(get, set):Null<String>;
|
|
|
|
|
|
|
|
function get_kind():Null<String>
|
|
|
|
{
|
|
|
|
return this.noteData?.kind;
|
|
|
|
}
|
2023-06-22 05:41:01 +00:00
|
|
|
|
|
|
|
function set_kind(value:String):String
|
|
|
|
{
|
2024-03-03 03:46:13 +00:00
|
|
|
if (this.noteData == null) return value;
|
|
|
|
return this.noteData.kind = value;
|
2023-06-22 05:41:01 +00:00
|
|
|
}
|
|
|
|
|
2024-06-22 18:49:30 +00:00
|
|
|
/**
|
|
|
|
* An array of custom parameters for this note
|
|
|
|
*/
|
|
|
|
public var params(get, set):Array<NoteParamData>;
|
|
|
|
|
|
|
|
function get_params():Array<NoteParamData>
|
|
|
|
{
|
|
|
|
return this.noteData?.params ?? [];
|
|
|
|
}
|
|
|
|
|
|
|
|
function set_params(value:Array<NoteParamData>):Array<NoteParamData>
|
|
|
|
{
|
|
|
|
if (this.noteData == null) return value;
|
|
|
|
return this.noteData.params = value;
|
|
|
|
}
|
|
|
|
|
2023-06-22 05:41:01 +00:00
|
|
|
/**
|
|
|
|
* The data of the note (i.e. the direction.)
|
|
|
|
*/
|
|
|
|
public var direction(default, set):NoteDirection;
|
|
|
|
|
|
|
|
function set_direction(value:Int):Int
|
|
|
|
{
|
|
|
|
if (frames == null) return value;
|
|
|
|
|
|
|
|
animation.play(DIRECTION_COLORS[value] + 'Scroll');
|
|
|
|
|
|
|
|
this.direction = value;
|
|
|
|
return this.direction;
|
|
|
|
}
|
|
|
|
|
|
|
|
public var noteData:SongNoteData;
|
|
|
|
|
2023-07-06 02:11:58 +00:00
|
|
|
public var isHoldNote(get, never):Bool;
|
|
|
|
|
|
|
|
function get_isHoldNote():Bool
|
|
|
|
{
|
|
|
|
return noteData.length > 0;
|
|
|
|
}
|
2023-06-22 05:41:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Set this flag to true when hitting the note to avoid scoring it multiple times.
|
|
|
|
*/
|
|
|
|
public var hasBeenHit:Bool = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register this note as hit only after any other notes
|
|
|
|
*/
|
|
|
|
public var lowPriority:Bool = false;
|
|
|
|
|
|
|
|
/**
|
2023-06-27 17:43:42 +00:00
|
|
|
* This is true if the note is later than 10 frames within the strumline,
|
|
|
|
* and thus can't be hit by the player.
|
|
|
|
* It will be destroyed after it moves offscreen.
|
|
|
|
* Managed by PlayState.
|
2023-06-22 05:41:01 +00:00
|
|
|
*/
|
|
|
|
public var hasMissed:Bool;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is true if the note is earlier than 10 frames within the strumline.
|
|
|
|
* and thus can't be hit by the player.
|
|
|
|
* Managed by PlayState.
|
|
|
|
*/
|
|
|
|
public var tooEarly:Bool;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is true if the note is within 10 frames of the strumline,
|
|
|
|
* and thus may be hit by the player.
|
|
|
|
* Managed by PlayState.
|
|
|
|
*/
|
|
|
|
public var mayHit:Bool;
|
|
|
|
|
|
|
|
/**
|
2023-06-27 17:43:42 +00:00
|
|
|
* This is true if the PlayState has performed the logic for missing this note.
|
|
|
|
* Subtracting score, subtracting health, etc.
|
2023-06-22 05:41:01 +00:00
|
|
|
*/
|
2023-06-27 17:43:42 +00:00
|
|
|
public var handledMiss:Bool;
|
2023-06-22 05:41:01 +00:00
|
|
|
|
2024-03-03 03:46:13 +00:00
|
|
|
public function new(noteStyle:NoteStyle, direction:Int = 0)
|
2023-06-22 05:41:01 +00:00
|
|
|
{
|
|
|
|
super(0, -9999);
|
|
|
|
this.direction = direction;
|
|
|
|
|
2024-01-16 03:10:42 +00:00
|
|
|
this.hsvShader = new HSVShader();
|
|
|
|
|
2023-07-14 00:27:45 +00:00
|
|
|
setupNoteGraphic(noteStyle);
|
2023-06-22 05:41:01 +00:00
|
|
|
|
|
|
|
// Disables the update() function for performance.
|
|
|
|
this.active = false;
|
|
|
|
}
|
|
|
|
|
2024-06-01 17:47:45 +00:00
|
|
|
/**
|
|
|
|
* Creates frames and animations
|
|
|
|
* @param noteStyle The `NoteStyle` instance
|
|
|
|
*/
|
|
|
|
public function setupNoteGraphic(noteStyle:NoteStyle):Void
|
2023-06-22 05:41:01 +00:00
|
|
|
{
|
2023-07-14 00:27:45 +00:00
|
|
|
noteStyle.buildNoteSprite(this);
|
2023-06-22 05:41:01 +00:00
|
|
|
|
|
|
|
setGraphicSize(Strumline.STRUMLINE_SIZE);
|
|
|
|
updateHitbox();
|
2024-01-16 03:10:42 +00:00
|
|
|
|
|
|
|
this.shader = hsvShader;
|
|
|
|
}
|
|
|
|
|
2024-06-22 18:49:30 +00:00
|
|
|
/**
|
|
|
|
* Retrieve the value of the param with the given name
|
|
|
|
* @param name Name of the param
|
|
|
|
* @return Null<Dynamic>
|
|
|
|
*/
|
|
|
|
public function getParam(name:String):Null<Dynamic>
|
|
|
|
{
|
|
|
|
for (param in params)
|
|
|
|
{
|
|
|
|
if (param.name == name)
|
|
|
|
{
|
|
|
|
return param.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:10:42 +00:00
|
|
|
#if FLX_DEBUG
|
|
|
|
/**
|
|
|
|
* Call this to override how debug bounding boxes are drawn for this sprite.
|
|
|
|
*/
|
|
|
|
public override function drawDebugOnCamera(camera:flixel.FlxCamera):Void
|
|
|
|
{
|
|
|
|
if (!camera.visible || !camera.exists || !isOnScreen(camera)) return;
|
|
|
|
|
|
|
|
var gfx = beginDrawDebug(camera);
|
|
|
|
|
|
|
|
var rect = getBoundingBox(camera);
|
|
|
|
trace('note sprite bounding box: ' + rect.x + ', ' + rect.y + ', ' + rect.width + ', ' + rect.height);
|
|
|
|
|
|
|
|
gfx.lineStyle(2, 0xFFFF66FF, 0.5); // thickness, color, alpha
|
|
|
|
gfx.drawRect(rect.x, rect.y, rect.width, rect.height);
|
|
|
|
|
|
|
|
gfx.lineStyle(2, 0xFFFFFF66, 0.5); // thickness, color, alpha
|
|
|
|
gfx.drawRect(rect.x, rect.y + rect.height / 2, rect.width, 1);
|
|
|
|
|
|
|
|
endDrawDebug(camera);
|
|
|
|
}
|
|
|
|
#end
|
|
|
|
|
|
|
|
public function desaturate():Void
|
|
|
|
{
|
|
|
|
this.hsvShader.saturation = 0.2;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setHue(hue:Float):Void
|
|
|
|
{
|
|
|
|
this.hsvShader.hue = hue;
|
2023-06-22 05:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public override function revive():Void
|
|
|
|
{
|
|
|
|
super.revive();
|
2024-01-16 03:10:42 +00:00
|
|
|
this.visible = true;
|
|
|
|
this.alpha = 1.0;
|
2023-06-22 05:41:01 +00:00
|
|
|
this.active = false;
|
|
|
|
this.tooEarly = false;
|
|
|
|
this.hasBeenHit = false;
|
|
|
|
this.mayHit = false;
|
|
|
|
this.hasMissed = false;
|
2024-01-16 03:10:42 +00:00
|
|
|
|
|
|
|
this.hsvShader.hue = 1.0;
|
|
|
|
this.hsvShader.saturation = 1.0;
|
|
|
|
this.hsvShader.value = 1.0;
|
2023-06-22 05:41:01 +00:00
|
|
|
}
|
2023-06-22 23:28:39 +00:00
|
|
|
|
|
|
|
public override function kill():Void
|
|
|
|
{
|
|
|
|
super.kill();
|
|
|
|
}
|
|
|
|
|
|
|
|
public override function destroy():Void
|
|
|
|
{
|
|
|
|
// This function should ONLY get called as you leave PlayState entirely.
|
|
|
|
// Otherwise, we want the game to keep reusing note sprites to save memory.
|
|
|
|
super.destroy();
|
|
|
|
}
|
2023-06-22 05:41:01 +00:00
|
|
|
}
|