note splashes
This commit is contained in:
@@ -45,6 +45,11 @@ class Note extends FlxSprite
|
||||
*/
|
||||
public var nextSustain:Note;
|
||||
|
||||
/**
|
||||
* Name of the splash.
|
||||
*/
|
||||
public var splash:String = "default";
|
||||
|
||||
public var strumID(get, never):Int;
|
||||
private function get_strumID() {
|
||||
var id = noteData % 4;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.game;
|
||||
|
||||
import funkin.game.SplashHandler;
|
||||
import funkin.editors.CharacterEditor;
|
||||
import funkin.scripting.DummyScript;
|
||||
import funkin.menus.StoryMenuState.WeekData;
|
||||
@@ -190,6 +191,11 @@ class PlayState extends MusicBeatState
|
||||
*/
|
||||
public var cpuStrums:FlxTypedGroup<Strum>;
|
||||
|
||||
/**
|
||||
* Note splashes container
|
||||
*/
|
||||
public var splashHandler:SplashHandler;
|
||||
|
||||
/**
|
||||
* Whenever the vocals should be muted when a note is missed.
|
||||
*/
|
||||
@@ -581,6 +587,9 @@ class PlayState extends MusicBeatState
|
||||
cpuStrums = new FlxTypedGroup<Strum>();
|
||||
add(strumLineNotes);
|
||||
|
||||
splashHandler = new SplashHandler();
|
||||
add(splashHandler);
|
||||
|
||||
generateSong(SONG);
|
||||
|
||||
if (prevCamFollow != null)
|
||||
@@ -868,6 +877,8 @@ class PlayState extends MusicBeatState
|
||||
swagNote.stepLength = stepCrochet;
|
||||
notes.add(swagNote);
|
||||
}
|
||||
|
||||
splashHandler.getSplashGroup(swagNote.splash);
|
||||
}
|
||||
daBeats += 1;
|
||||
}
|
||||
@@ -1450,43 +1461,40 @@ class PlayState extends MusicBeatState
|
||||
|
||||
function noteMiss(note:Note):Void
|
||||
{
|
||||
if (!boyfriend.stunned)
|
||||
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, [boyfriend], true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit"));
|
||||
|
||||
if (event.cancelled) return;
|
||||
|
||||
health += event.healthGain;
|
||||
if (gf != null && combo > 5 && gf.animOffsets.exists('sad'))
|
||||
{
|
||||
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, [boyfriend], true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit"));
|
||||
|
||||
if (event.cancelled) return;
|
||||
|
||||
health += event.healthGain;
|
||||
if (gf != null && combo > 5 && gf.animOffsets.exists('sad'))
|
||||
{
|
||||
gf.playAnim('sad', true, MISS);
|
||||
}
|
||||
combo = 0;
|
||||
|
||||
songScore -= 10;
|
||||
misses++;
|
||||
|
||||
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
||||
|
||||
if (muteVocalsOnMiss) vocals.volume = 0;
|
||||
|
||||
if (event.accuracy != null) {
|
||||
accuracyPressedNotes++;
|
||||
totalAccuracyAmount += event.accuracy;
|
||||
|
||||
updateRating();
|
||||
}
|
||||
|
||||
for(char in event.characters) {
|
||||
if (char == null) continue;
|
||||
|
||||
char.stunned = true;
|
||||
char.playSingAnim(note.strumID, "miss", MISS);
|
||||
}
|
||||
// boyfriend.stunned = true;
|
||||
|
||||
deleteNote(note);
|
||||
gf.playAnim('sad', true, MISS);
|
||||
}
|
||||
combo = 0;
|
||||
|
||||
songScore -= 10;
|
||||
misses++;
|
||||
|
||||
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
||||
|
||||
if (muteVocalsOnMiss) vocals.volume = 0;
|
||||
|
||||
if (event.accuracy != null) {
|
||||
accuracyPressedNotes++;
|
||||
totalAccuracyAmount += event.accuracy;
|
||||
|
||||
updateRating();
|
||||
}
|
||||
|
||||
for(char in event.characters) {
|
||||
if (char == null) continue;
|
||||
|
||||
char.stunned = true;
|
||||
char.playSingAnim(note.strumID, "miss", MISS);
|
||||
}
|
||||
// boyfriend.stunned = true;
|
||||
|
||||
deleteNote(note);
|
||||
}
|
||||
|
||||
public function getNoteType(id:Int):String {
|
||||
@@ -1529,9 +1537,9 @@ class PlayState extends MusicBeatState
|
||||
var event:NoteHitEvent;
|
||||
if (note.mustPress)
|
||||
// event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(note, [boyfriend], true, note.noteType, note.strumID, note.noteData > 0 ? 0.023 : 0.004, score, note.animSuffix, daRating, note.isSustainNote ? null : accuracy, "game/score/", ''));
|
||||
event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, [boyfriend], true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating));
|
||||
event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, [boyfriend], true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, daRating == "sick"));
|
||||
else
|
||||
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, [dad], false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating));
|
||||
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, [dad], false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating, false));
|
||||
|
||||
if (!event.cancelled) {
|
||||
if (event.accuracy != null) {
|
||||
@@ -1625,9 +1633,10 @@ class PlayState extends MusicBeatState
|
||||
if (char != null)
|
||||
char.playSingAnim(event.direction, event.animSuffix);
|
||||
|
||||
if (!event.strumGlowCancelled) (event.player ? playerStrums : cpuStrums).forEach(function(str:Strum) {
|
||||
(event.player ? playerStrums : cpuStrums).forEach(function(str:Strum) {
|
||||
if (str.ID == Math.abs(note.strumID)) {
|
||||
str.press(note.strumTime);
|
||||
if (!event.strumGlowCancelled) str.press(note.strumTime);
|
||||
if (event.showSplash) splashHandler.showSplash(note.splash, str);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package funkin.game;
|
||||
|
||||
import flixel.FlxG;
|
||||
import openfl.utils.Assets;
|
||||
import haxe.xml.Access;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
|
||||
class SplashGroup extends FlxTypedGroup<FunkinSprite> {
|
||||
/**
|
||||
* Whenever the splash group has successfully loaded or not.
|
||||
*/
|
||||
public var valid:Bool = true;
|
||||
|
||||
/**
|
||||
* XML data for the note splashes.
|
||||
*/
|
||||
public var xml:Access;
|
||||
|
||||
/**
|
||||
* Animation names sorted by strum IDs.
|
||||
* Use `getSplashAnim` to get one.
|
||||
*/
|
||||
public var animationNames:Array<Array<String>> = [];
|
||||
|
||||
/**
|
||||
* Creates a new Splash group
|
||||
* @param path Path to the splash data (xml)
|
||||
*/
|
||||
public function new(path) {
|
||||
super();
|
||||
|
||||
try {
|
||||
xml = new Access(Xml.parse(Assets.getText(path)).firstElement());
|
||||
|
||||
if (!xml.has.sprite) throw "The <splash> element requires a sprite attribute.";
|
||||
|
||||
var splashSprite = new FunkinSprite();
|
||||
splashSprite.antialiasing = true;
|
||||
splashSprite.active = splashSprite.visible = false;
|
||||
splashSprite.loadSprite(Paths.image(xml.att.sprite));
|
||||
|
||||
/**
|
||||
* ANIMATIONS
|
||||
*/
|
||||
for(strum in xml.nodes.strum) {
|
||||
var id:Null<Int> = Std.parseInt(strum.att.id);
|
||||
if (id != null) {
|
||||
animationNames[id] = [];
|
||||
for(anim in strum.nodes.anim) {
|
||||
if (!anim.has.name) continue;
|
||||
XMLUtil.addXMLAnimation(splashSprite, anim, false);
|
||||
animationNames[id].push(anim.att.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animationNames.length <= 0)
|
||||
animationNames.push([]);
|
||||
for(anim in xml.nodes.anim) {
|
||||
if (!anim.has.name) continue;
|
||||
XMLUtil.addXMLAnimation(splashSprite, anim, false);
|
||||
for(a in animationNames) {
|
||||
if (a == null) continue;
|
||||
a.push(anim.att.name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* END OF ANIMATIONS
|
||||
*/
|
||||
splashSprite.animation.finishCallback = function(name) {
|
||||
splashSprite.active = splashSprite.visible = false;
|
||||
};
|
||||
|
||||
if (xml.has.scale) splashSprite.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1));
|
||||
if (xml.has.alpha) splashSprite.alpha = Std.parseFloat(xml.att.alpha).getDefault(1);
|
||||
if (xml.has.antialiasing) splashSprite.antialiasing = xml.att.antialiasing == "true";
|
||||
|
||||
add(splashSprite);
|
||||
|
||||
for (i in 0...7) {
|
||||
// make 7 additional splashes
|
||||
var spr = FunkinSprite.copyFrom(splashSprite);
|
||||
spr.animation.finishCallback = function(name) {
|
||||
spr.active = spr.visible = false;
|
||||
};
|
||||
add(spr);
|
||||
}
|
||||
|
||||
// immediatly draw once and put image in GPU to prevent freezes
|
||||
splashSprite.draw();
|
||||
} catch(e) {
|
||||
Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
maxSize = 8;
|
||||
}
|
||||
|
||||
public function getSplashAnim(id:Int):String {
|
||||
if (animationNames.length <= 0) return null;
|
||||
id %= animationNames.length;
|
||||
if (animationNames[id] == null) return null;
|
||||
if (animationNames[id].length <= 0) return null;
|
||||
return animationNames[id][FlxG.random.int(0, animationNames[id].length-1)];
|
||||
}
|
||||
|
||||
public function showOnStrum(strum:Strum) {
|
||||
if (!valid) return null;
|
||||
var splash = recycle();
|
||||
|
||||
splash.cameras = strum.lastDrawCameras;
|
||||
splash.setPosition(strum.x + ((strum.width - splash.width) / 2), strum.y + ((strum.height - splash.height) / 2));
|
||||
splash.active = splash.visible = true;
|
||||
splash.playAnim(getSplashAnim(strum.ID), true);
|
||||
|
||||
return splash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package funkin.game;
|
||||
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
|
||||
class SplashHandler extends FlxTypedGroup<FunkinSprite> {
|
||||
/**
|
||||
* Map containing all of the splashes group.
|
||||
*/
|
||||
public var grpMap:Map<String, SplashGroup> = [];
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a group of splashes, and creates it if it doesn't exist.
|
||||
* @param path Path to the splashes XML (`Paths.xml('splashes/splash')`)
|
||||
*/
|
||||
public function getSplashGroup(name:String) {
|
||||
if (!grpMap.exists(name)) {
|
||||
var grp = new SplashGroup(Paths.xml('splashes/$name'));
|
||||
grpMap.set(name, grp);
|
||||
}
|
||||
return grpMap.get(name);
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
for(grp in grpMap)
|
||||
grp.destroy();
|
||||
grpMap = null;
|
||||
}
|
||||
|
||||
public function showSplash(name:String, strum:Strum) {
|
||||
var grp = getSplashGroup(name);
|
||||
add(grp.showOnStrum(strum));
|
||||
|
||||
// max 8 rendered splashes
|
||||
while(members.length > 8)
|
||||
remove(members[0]);
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,10 @@ class NoteHitEvent extends CancellableEvent {
|
||||
* Rating name. Defaults to "sick", "good", "bad" and "shit". Customisable.
|
||||
*/
|
||||
public var rating:String = "sick";
|
||||
/**
|
||||
* Whenever a splash should be shown when the note is hit.
|
||||
*/
|
||||
public var showSplash:Bool = false;
|
||||
/**
|
||||
* Scale of combo numbers.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,18 @@ class FunkinSprite extends FlxSprite implements IBeatReceiver implements IOffset
|
||||
@:noCompletion public var atlasPlayingAnim:String;
|
||||
@:noCompletion public var atlasPath:String;
|
||||
|
||||
public static function copyFrom(source:FunkinSprite) {
|
||||
var spr = new FunkinSprite();
|
||||
spr.setPosition(source.x, source.y);
|
||||
spr.frames = source.frames;
|
||||
if (source.animateAtlas != null && source.atlasPath != null)
|
||||
spr.loadSprite(source.atlasPath);
|
||||
spr.animation.copyFrom(source.animation);
|
||||
spr.visible = source.visible;
|
||||
spr.alpha = source.alpha;
|
||||
return spr;
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
if (animateAtlas != null)
|
||||
|
||||
Reference in New Issue
Block a user