Hold notes pretty much done! yay!

This commit is contained in:
EliteMasterEric 2023-06-27 17:22:51 -04:00
parent a672db7b0e
commit 2f7708c106
7 changed files with 47 additions and 258 deletions

View file

@ -264,8 +264,6 @@ class AlphaCharacter extends FlxSprite
animation.play(letter);
updateHitbox();
FlxG.log.add('the row' + row);
y = (110 - height);
y += row * 60;
}

View file

@ -2,6 +2,7 @@ package funkin;
import flixel.FlxSprite;
import haxe.io.Path;
import flixel.graphics.frames.FlxAtlasFrames;
class NoteSplash extends FlxSprite
{
@ -9,15 +10,13 @@ class NoteSplash extends FlxSprite
{
super(x, y);
frames = Paths.getSparrowAtlas('noteSplashes');
animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false);
animation.addByPrefix('note1-0', 'note impact 1 blue', 24, false);
animation.addByPrefix('note2-0', 'note impact 1 green', 24, false);
animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false);
animation.addByPrefix('note3-0', 'note impact 1 red', 24, false);
animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false);
animation.addByPrefix('note1-1', 'note impact 2 blue', 24, false);
animation.addByPrefix('note2-1', 'note impact 2 green', 24, false);
animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false);
animation.addByPrefix('note3-1', 'note impact 2 red', 24, false);
setupNoteSplash(x, y, noteData);
@ -25,6 +24,20 @@ class NoteSplash extends FlxSprite
// alpha = 0.75;
}
public static function buildSplashFrames(force:Bool = false):FlxAtlasFrames
{
// static variables inside functions are a cool of Haxe 4.3.0.
static var splashFrames:FlxAtlasFrames = null;
if (splashFrames != null && !force) return splashFrames;
splashFrames = Paths.getSparrowAtlas('noteSplashes');
splashFrames.parent.persist = true;
return splashFrames;
}
public function setupNoteSplash(x:Float, y:Float, noteData:Int = 0)
{
setPosition(x, y);

View file

@ -1,233 +0,0 @@
package funkin.graphics.rendering;
import flixel.FlxSprite;
import flixel.graphics.FlxGraphic;
import flixel.graphics.tile.FlxDrawTrianglesItem;
import flixel.math.FlxMath;
/**
* This is based heavily on the `FlxStrip` class. It uses `drawTriangles()` to clip a sustain note
* trail at a certain time.
* The whole `FlxGraphic` is used as a texture map. See the `NOTE_hold_assets.fla` file for specifics
* on how it should be constructed.
*
* @author MtH
*/
class SustainTrail extends FlxSprite
{
/**
* Used to determine which note color/direction to draw for the sustain.
*/
public var noteData:Int = 0;
/**
* The zoom level to render the sustain at.
* Defaults to 1.0, increased to 6.0 for pixel notes.
*/
public var zoom(default, set):Float = 1;
/**
* The strumtime of the note, in milliseconds.
*/
public var strumTime:Float = 0; // millis
/**
* The sustain length of the note, in milliseconds.
*/
public var sustainLength(default, set):Float = 0; // millis
/**
* The scroll speed of the note, as a multiplier.
*/
public var scrollSpeed(default, set):Float = 1.0; // stand-in for PlayState scroll speed
/**
* Whether the note was missed.
*/
public var missed:Bool = false; // maybe BlendMode.MULTIPLY if missed somehow, drawTriangles does not support!
/**
* A `Vector` of floats where each pair of numbers is treated as a coordinate location (an x, y pair).
*/
var vertices:DrawData<Float> = new DrawData<Float>();
/**
* A `Vector` of integers or indexes, where every three indexes define a triangle.
*/
var indices:DrawData<Int> = new DrawData<Int>();
/**
* A `Vector` of normalized coordinates used to apply texture mapping.
*/
var uvtData:DrawData<Float> = new DrawData<Float>();
var processedGraphic:FlxGraphic;
/**
* What part of the trail's end actually represents the end of the note.
* This can be used to have a little bit sticking out.
*/
public var endOffset:Float = 0.5; // 0.73 is roughly the bottom of the sprite in the normal graphic!
/**
* At what point the bottom for the trail's end should be clipped off.
* Used in cases where there's an extra bit of the graphic on the bottom to avoid antialiasing issues with overflow.
*/
public var bottomClip:Float = 0.9;
/**
* Normally you would take strumTime:Float, noteData:Int, sustainLength:Float, parentNote:Note (?)
* @param NoteData
* @param SustainLength
* @param FileName
*/
public function new(NoteData:Int, SustainLength:Float, Path:String, ?Alpha:Float = 0.6, ?Pixel:Bool = false)
{
super(0, 0, Path);
// BASIC SETUP
this.sustainLength = SustainLength;
this.noteData = NoteData;
// CALCULATE SIZE
if (Pixel)
{
this.endOffset = bottomClip = 1;
this.antialiasing = false;
this.zoom = 6.0;
}
else
{
this.antialiasing = true;
this.zoom = 1.0;
}
// width = graphic.width / 8 * zoom; // amount of notes * 2
height = sustainHeight(sustainLength, scrollSpeed);
// instead of scrollSpeed, PlayState.SONG.speed
alpha = Alpha; // setting alpha calls updateColorTransform(), which initializes processedGraphic!
updateClipping();
indices = new DrawData<Int>(12, true, [0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4]);
}
/**
* Calculates height of a sustain note for a given length (milliseconds) and scroll speed.
* @param susLength The length of the sustain note in milliseconds.
* @param scroll The current scroll speed.
*/
public static inline function sustainHeight(susLength:Float, scroll:Float)
{
return (susLength * 0.45 * scroll);
}
function set_zoom(z:Float)
{
this.zoom = z;
width = graphic.width / 8 * z;
updateClipping();
return this.zoom;
}
function set_sustainLength(s:Float)
{
height = sustainHeight(s, scrollSpeed);
return sustainLength = s;
}
function set_scrollSpeed(s:Float)
{
height = sustainHeight(sustainLength, s);
return scrollSpeed = s;
}
/**
* Sets up new vertex and UV data to clip the trail.
* If flipY is true, top and bottom bounds swap places.
* @param songTime The time to clip the note at, in milliseconds.
*/
public function updateClipping(songTime:Float = 0):Void
{
var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), scrollSpeed), 0, height);
if (clipHeight == 0)
{
visible = false;
return;
}
else
visible = true;
var bottomHeight:Float = graphic.height * zoom * endOffset;
var partHeight:Float = clipHeight - bottomHeight;
// == HOLD == //
// left bound
vertices[6] = vertices[0] = 0.0;
// top bound
vertices[3] = vertices[1] = flipY ? clipHeight : height - clipHeight;
// right bound
vertices[4] = vertices[2] = width;
// bottom bound (also top bound for hold ends)
if (partHeight > 0) vertices[7] = vertices[5] = flipY ? 0.0 + bottomHeight : vertices[1] + partHeight;
else
vertices[7] = vertices[5] = vertices[1];
// same shit with da bounds, just in relation to the texture
uvtData[6] = uvtData[0] = 1 / 4 * (noteData % 4);
// height overflows past image bounds so wraps around, looping the texture
// flipY bounds are not swapped for UV data, so the graphic is actually flipped
// top bound
uvtData[3] = uvtData[1] = (-partHeight) / graphic.height / zoom;
uvtData[4] = uvtData[2] = uvtData[0] + 1 / 8; // 1
// bottom bound
uvtData[7] = uvtData[5] = 0.0;
// == HOLD ENDS == //
// left bound
vertices[14] = vertices[8] = vertices[0];
// top bound
vertices[11] = vertices[9] = vertices[5];
// right bound
vertices[12] = vertices[10] = vertices[2];
// bottom bound, mind the bottomClip because it clips off bottom of graphic!!
vertices[15] = vertices[13] = flipY ? graphic.height * (-bottomClip + endOffset) : height + graphic.height * (bottomClip - endOffset);
uvtData[14] = uvtData[8] = uvtData[2];
if (partHeight > 0) uvtData[11] = uvtData[9] = 0.0;
else
uvtData[11] = uvtData[9] = (bottomHeight - clipHeight) / zoom / graphic.height;
uvtData[12] = uvtData[10] = uvtData[8] + 1 / 8;
// again, clips off bottom !!
uvtData[15] = uvtData[13] = bottomClip;
}
@:access(flixel.FlxCamera)
override public function draw():Void
{
if (alpha == 0 || graphic == null || vertices == null) return;
for (camera in cameras)
{
if (!camera.visible || !camera.exists || !isOnScreen(camera)) continue;
getScreenPosition(_point, camera).subtractPoint(offset);
camera.drawTriangles(processedGraphic, vertices, indices, uvtData, null, _point, blend, true, antialiasing);
}
}
override public function destroy():Void
{
vertices = null;
indices = null;
uvtData = null;
processedGraphic.destroy();
super.destroy();
}
override function updateColorTransform():Void
{
super.updateColorTransform();
if (processedGraphic != null) processedGraphic.destroy();
processedGraphic = FlxGraphic.fromGraphic(graphic, true);
processedGraphic.bitmap.colorTransform(processedGraphic.bitmap.rect, colorTransform);
}
}

View file

@ -836,7 +836,7 @@ class PlayState extends MusicBeatState
if (isInCutscene && !disableKeys) handleCutsceneKeys(elapsed);
// Moving notes into position is now done by Strumline.update().
processNotes();
processNotes(elapsed);
// Dispatch the onUpdate event to scripted elements.
dispatchEvent(new UpdateScriptEvent(elapsed));
@ -1378,10 +1378,6 @@ class PlayState extends MusicBeatState
if (!PlayStatePlaylist.isStoryMode)
{
playerStrumline.fadeInArrows();
}
if (!PlayStatePlaylist.isStoryMode)
{
opponentStrumline.fadeInArrows();
}
@ -1629,7 +1625,7 @@ class PlayState extends MusicBeatState
/**
* Handles opponent note hits and player note misses.
*/
function processNotes():Void
function processNotes(elapsed:Float):Void
{
// Process notes on the opponent's side.
for (note in opponentStrumline.notes.members)
@ -1730,6 +1726,15 @@ class PlayState extends MusicBeatState
// Process hold notes on the player's side.
// This handles scoring so we don't need it on the opponent's side.
for (holdNote in playerStrumline.holdNotes.members)
{
// While the hold note is being hit, and there is length on the hold note...
if (holdNote.hitNote && holdNote.sustainLength > 0)
{
// Grant the player health.
health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed;
}
}
}
/**

View file

@ -588,18 +588,18 @@ class Strumline extends FlxSpriteGroup
* @param arrow The arrow to animate.
* @param index The index of the arrow in the strumline.
*/
function fadeInArrow(arrow:StrumlineNote):Void
function fadeInArrow(index:Int, arrow:StrumlineNote):Void
{
arrow.y -= 10;
arrow.alpha = 0;
FlxTween.tween(arrow, {y: arrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * arrow.ID)});
arrow.alpha = 0.0;
FlxTween.tween(arrow, {y: arrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * index)});
}
public function fadeInArrows():Void
{
for (arrow in this.strumlineNotes)
for (index => arrow in this.strumlineNotes.members.keyValueIterator())
{
fadeInArrow(arrow);
fadeInArrow(index, arrow);
}
}

View file

@ -41,6 +41,7 @@ class StrumlineNote extends FlxSprite
this.animation.callback = onAnimationFrame;
this.animation.finishCallback = onAnimationFinished;
// Must be true for animations to play.
this.active = true;
}

View file

@ -147,38 +147,43 @@ class Constants
/**
* The amount of health the player gains when hitting a note with the KILLER rating.
*/
public static final HEALTH_KILLER_BONUS:Float = 2.0 / 100.0 / HEALTH_MAX; // +2.0%
public static final HEALTH_KILLER_BONUS:Float = 2.0 / 100.0 * HEALTH_MAX; // +2.0%
/**
* The amount of health the player gains when hitting a note with the SICK rating.
*/
public static final HEALTH_SICK_BONUS:Float = 1.5 / 100.0 / HEALTH_MAX; // +1.0%
public static final HEALTH_SICK_BONUS:Float = 1.5 / 100.0 * HEALTH_MAX; // +1.0%
/**
* The amount of health the player gains when hitting a note with the GOOD rating.
*/
public static final HEALTH_GOOD_BONUS:Float = 0.75 / 100.0 / HEALTH_MAX; // +0.75%
public static final HEALTH_GOOD_BONUS:Float = 0.75 / 100.0 * HEALTH_MAX; // +0.75%
/**
* The amount of health the player gains when hitting a note with the BAD rating.
*/
public static final HEALTH_BAD_BONUS:Float = 0.0 / 100.0 / HEALTH_MAX; // +0.0%
public static final HEALTH_BAD_BONUS:Float = 0.0 / 100.0 * HEALTH_MAX; // +0.0%
/**
* The amount of health the player gains when hitting a note with the SHIT rating.
* If negative, the player will actually lose health.
*/
public static final HEALTH_SHIT_BONUS:Float = -1.0 / 100.0 / HEALTH_MAX; // -1.0%
public static final HEALTH_SHIT_BONUS:Float = -1.0 / 100.0 * HEALTH_MAX; // -1.0%
/**
* The amount of health the player gains, while holding a hold note, per second.
*/
public static final HEALTH_HOLD_BONUS_PER_SECOND:Float = 7.5 / 100.0 * HEALTH_MAX; // +7.5% / second
/**
* The amount of health the player loses upon missing a note.
*/
public static final HEALTH_MISS_PENALTY:Float = 4.0 / 100.0 / HEALTH_MAX; // 4.0%
public static final HEALTH_MISS_PENALTY:Float = 4.0 / 100.0 * HEALTH_MAX; // 4.0%
/**
* The amount of health the player loses upon pressing a key when no note is there.
*/
public static final HEALTH_GHOST_MISS_PENALTY:Float = 2.0 / 100.0 / HEALTH_MAX; // 2.0%
public static final HEALTH_GHOST_MISS_PENALTY:Float = 2.0 / 100.0 * HEALTH_MAX; // 2.0%
/**
* The amount of health the player loses upon letting go of a hold note while it is still going.
@ -188,7 +193,7 @@ class Constants
/**
* The amount of health the player loses upon hitting a mine.
*/
public static final HEALTH_MINE_PENALTY:Float = 15.0 / 100.0 / HEALTH_MAX; // 15.0%
public static final HEALTH_MINE_PENALTY:Float = 15.0 / 100.0 * HEALTH_MAX; // 15.0%
/**
* If true, the player will not receive the ghost miss penalty if there are no notes within the hit window.