* basic set up

* game prefab set up

* fillboy

* Medium bot falls down from da skyyyyyy

* animations! (fillbots)

* filler whiffs

* Medium bot anims

* Bots can be filled wow

* Bots move!!!!!

* Fixed hold length

* offbeats now work

* kaboom

* barelies for medium bot

* basic fix

* beyond

* Update Sprites

* Small Medium Large

* Bot Lamp

* blackout

* yet not implemented

* Filler Animation

* Fly Animation

* Stack to Left

* Update Sprites

* Color event

* refactoring

* minor fixes

* temporary icon

* Restart the stopped conveyor

---------

Co-authored-by: Rapandrasmus <78219215+Rapandrasmus@users.noreply.github.com>
This commit is contained in:
フマジメ
2024-04-05 10:28:09 +09:00
committed by GitHub
parent 75e248c97b
commit 5377a28f5b
245 changed files with 27272 additions and 1 deletions

View File

@ -0,0 +1,553 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
using Jukebox;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrFillbotsLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
var botParams = new List<Param>()
{
new Param("practice", false, "Count-In"),
new Param("alt", false, "Alternate OK"),
new Param("type", Scripts_Fillbots.EndAnim.Both, "Success Reaction", "Set the reaction of the Robot."),
new Param("stop", false, "Stop Conveyer", "Toggle if the conveyer should be stopped when finished."),
new Param("color", false, "Custom Color", "Toggle if the robot color should be changed.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => (bool)x, new string[] { "colorFuel", "colorLampOff", "colorLampOn" }),
}),
new Param("colorFuel", new Color(1f, 0.385f, 0.385f), "Fuel Color", "Set the color of the fuel."),
new Param("colorLampOff", new Color(0.635f, 0.635f, 0.185f), "Off Lamp Color", "Set the color of the off lamp."),
new Param("colorLampOn", new Color(1f, 1f, 0.42f), "On Lamp Color", "Set the color of the on lamp."),
};
var customBotParams = new List<Param>(botParams);
customBotParams.Insert(0,
new Param("size", Scripts_Fillbots.BotSize.Medium, "Size", "Set the size of the Robot.")
);
return new Minigame("fillbots", "Fillbots", "FFFFFF", false, false, new List<GameAction>()
{
new("bop", "Bop")
{
function = delegate
{
var e = eventCaller.currentEntity;
Fillbots.instance.ToggleBop(e.beat, e.length, e["toggle"], e["auto"]);
},
resizable = true,
parameters = new()
{
new("toggle", true, "Bop"),
new("auto", false, "Bop (Auto)")
}
},
new GameAction("medium", "Medium Bot")
{
preFunction = delegate {
var e = eventCaller.currentEntity;
Fillbots.PreSpawnFillbot(e.beat, 3, (int)Scripts_Fillbots.BotSize.Medium, e["colorFuel"], e["colorLampOff"], e["colorLampOn"], e["type"], e["alt"], e["stop"], e["color"]);
if (e["practice"]) Fillbots.FillErUp(e.beat + 3);
},
defaultLength = 8f,
parameters = botParams,
},
new GameAction("large", "Large Bot")
{
preFunction = delegate {
var e = eventCaller.currentEntity;
Fillbots.PreSpawnFillbot(e.beat, 7, (int)Scripts_Fillbots.BotSize.Large, e["colorFuel"], e["colorLampOff"], e["colorLampOn"], e["type"], e["alt"], e["stop"], e["color"]);
if (e["practice"]) Fillbots.FillErUp(e.beat + 3);
},
defaultLength = 12f,
parameters = botParams,
},
new GameAction("small", "Small Bot")
{
preFunction = delegate {
var e = eventCaller.currentEntity;
Fillbots.PreSpawnFillbot(e.beat, 1, (int)Scripts_Fillbots.BotSize.Small, e["colorFuel"], e["colorLampOff"], e["colorLampOn"], e["type"], e["alt"], e["stop"], e["color"]);
if (e["practice"]) Fillbots.FillErUp(e.beat + 3);
},
defaultLength = 6f,
parameters = botParams,
},
new GameAction("custom", "Custom Bot")
{
preFunction = delegate {
var e = eventCaller.currentEntity;
Fillbots.PreSpawnFillbot(e.beat, e.length-5, e["size"], e["colorFuel"], e["colorLampOff"], e["colorLampOn"], e["type"], e["alt"], e["stop"], e["color"]);
if (e["practice"]) Fillbots.FillErUp(e.beat + 3);
},
defaultLength = 6f,
resizable = true,
parameters = customBotParams,
},
new GameAction("blackout", "Blackout")
{
function = delegate { Fillbots.instance.Blackout();},
defaultLength = 0.5f,
},
new GameAction("background appearance", "Background Appearance")
{
function = delegate {
var e = eventCaller.currentEntity;
Fillbots.instance.BackgroundColorSet(e.beat, e.length, e["colorBGStart"], e["colorBGEnd"],
e["colorMetersStart"], e["colorMeter1Start"], e["colorMeter2Start"], e["colorMeter3Start"], e["colorMeter4Start"], e["colorMeter5Start"], e["colorMeter6Start"],
e["colorMetersEnd"], e["colorMeter1End"], e["colorMeter2End"], e["colorMeter3End"], e["colorMeter4End"], e["colorMeter5End"], e["colorMeter6End"],
e["separate"], e["ease"]);
},
defaultLength = 0.5f,
resizable = true,
parameters = new List<Param>()
{
new Param("colorBGStart", Color.white, "Start BG Color", "Set the color at the start of the event."),
new Param("colorBGEnd", Color.white, "End BG Color", "Set the color at the end of the event."),
new Param("ease", Util.EasingFunction.Ease.Instant, "Ease", "Set the easing of the action."),
new Param("separate", false, "Separate Meter Color", "Toggle if the robot color should be changed.", new List<Param.CollapseParam>()
{
new Param.CollapseParam((x, _) => !(bool)x, new string[] { "colorMetersStart", "colorMetersEnd" }),
new Param.CollapseParam((x, _) => (bool)x, new string[] { "colorMeter1Start", "colorMeter2Start", "colorMeter3Start", "colorMeter4Start", "colorMeter5Start", "colorMeter6Start",
"colorMeter1End", "colorMeter2End", "colorMeter3End", "colorMeter4End", "colorMeter5End", "colorMeter6End" }),
}),
new Param("colorMetersStart", new Color(1f, 0.88f, 0.88f), "Start Meter Color", "Set the color at the start of the event."),
new Param("colorMetersEnd", new Color(1f, 0.88f, 0.88f), "End Meter Color", "Set the color at the end of the event."),
new Param("colorMeter1Start", new Color(1f, 0.88f, 0.88f), "Start 1st Meter Color", "Set the color at the start of the event."),
new Param("colorMeter1End", new Color(1f, 0.88f, 0.88f), "End 1st Meter Color", "Set the color at the end of the event."),
new Param("colorMeter2Start", new Color(1f, 0.88f, 0.88f), "Start 2nd Meter Color", "Set the color at the start of the event."),
new Param("colorMeter2End", new Color(1f, 0.88f, 0.88f), "End 2nd Meter Color", "Set the color at the end of the event."),
new Param("colorMeter3Start", new Color(1f, 0.88f, 0.88f), "Start 3rd Meter Color", "Set the color at the start of the event."),
new Param("colorMeter3End", new Color(1f, 0.88f, 0.88f), "End 3rd Meter Color", "Set the color at the end of the event."),
new Param("colorMeter4Start", new Color(1f, 0.88f, 0.88f), "Start 4th Meter Color", "Set the color at the start of the event."),
new Param("colorMeter4End", new Color(1f, 0.88f, 0.88f), "End 4th Meter Color", "Set the color at the end of the event."),
new Param("colorMeter5Start", new Color(1f, 0.88f, 0.88f), "Start 5th Meter Color", "Set the color at the start of the event."),
new Param("colorMeter5End", new Color(1f, 0.88f, 0.88f), "End 5th Meter Color", "Set the color at the end of the event."),
new Param("colorMeter6Start", new Color(1f, 0.88f, 0.88f), "Start 6th Meter Color", "Set the color at the start of the event."),
new Param("colorMeter6End", new Color(1f, 0.88f, 0.88f), "End 6th Meter Color", "Set the color at the end of the event."),
}
},
new GameAction("object appearance", "Object Appearance")
{
function = delegate {
var e = eventCaller.currentEntity;
Fillbots.instance.ObjectColorSet(e["colorFuel"], e["colorLampOff"], e["colorLampOn"], e["colorImpact"], e["colorFiller"], e["colorConveyer"]);
},
defaultLength = 0.5f,
parameters = new List<Param>()
{
new Param("colorFuel", new Color(1f, 0.385f, 0.385f), "Fuel Color", "Set the color of the fuel."),
new Param("colorLampOff", new Color(0.635f, 0.635f, 0.185f), "Off Lamp Color", "Set the color of the off lamp."),
new Param("colorLampOn", new Color(1f, 1f, 0.42f), "On Lamp Color", "Set the color of the on lamp."),
new Param("colorImpact", new Color(1f, 0.59f, 0.01f), "Impact Color", "Set the color of the impact."),
new Param("colorFiller", Color.white, "Filler Color", "Set the color of the filler."),
new Param("colorConveyer", Color.white, "Conveyer Color", "Set the color of the conveyer."),
}
},
},
new List<string>() {"ntr", "normal"},
"ntrfillbots", "en",
new List<string>() {},
chronologicalSortKey: 3
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_Fillbots;
using System;
public class Fillbots : Minigame
{
private struct QueuedFillbot
{
public double beat;
public double holdLength;
public BotSize size;
public Color fuelColor;
public Color lampColorOff;
public Color lampColorOn;
public EndAnim endAnim;
public bool altOK;
public bool stop;
public bool color;
}
private static List<QueuedFillbot> queuedBots = new List<QueuedFillbot>();
[Header("Components")]
[SerializeField] private NtrFillbot smallBot;
[SerializeField] private NtrFillbot mediumBot;
[SerializeField] private NtrFillbot largeBot;
public Animator filler;
[System.NonSerialized] public bool fillerHolding;
[SerializeField] private Transform[] gears;
[SerializeField] private Animator[] meters;
[SerializeField] private SpriteRenderer[] metersFuel;
[SerializeField] private Material impactMaterial;
[SerializeField] private Animator conveyerBelt;
[SerializeField] private GameObject blackout;
[SerializeField] private SpriteRenderer[] fillerRenderer;
[SerializeField] private SpriteRenderer[] otherRenderer;
[SerializeField] private SpriteRenderer BGPlane;
[System.NonSerialized] public BotSize fillerPosition = BotSize.Medium;
[NonSerialized] public List<NtrFillbot> currentBots = new List<NtrFillbot>();
[NonSerialized] public double conveyerStartBeat = -1;
[NonSerialized] public float conveyerNormalizedOffset;
private ColorEase[] colorEases = new ColorEase[7];
private int toggleGlobal = 0;
private Color fuelColorGlobal = new Color(1f, 0.385f, 0.385f),
lampColorOffGlobal = new Color(0.635f, 0.635f, 0.185f),
lampColorOnGlobal = new Color(1f, 1f, 0.42f);
public static Fillbots instance;
private void Awake()
{
instance = this;
SetupBopRegion("fillbots", "bop", "auto");
colorEases = new ColorEase[] {
new(Color.white),
new(new Color(1f, 0.88f, 0.88f)),
new(new Color(1f, 0.88f, 0.88f)),
new(new Color(1f, 0.88f, 0.88f)),
new(new Color(1f, 0.88f, 0.88f)),
new(new Color(1f, 0.88f, 0.88f)),
new(new Color(1f, 0.88f, 0.88f)),
};
}
public override void OnBeatPulse(double beat)
{
if (BeatIsInBopRegion(beat)) {
Bop(toggleGlobal);
toggleGlobal ^= 1;
}
}
public override void OnPlay(double beat)
{
if (queuedBots.Count > 0) queuedBots.Clear();
foreach (var evt in scheduledInputs)
{
evt.Disable();
}
}
private void OnDestroy()
{
if (queuedBots.Count > 0) queuedBots.Clear();
foreach (var evt in scheduledInputs)
{
evt.Disable();
}
}
public override void OnStop(double beat) => EntityPreCheck(beat);
void EntityPreCheck(double beat)
{
if (gameManager == null) return;
List<RiqEntity> prevEntities = gameManager.Beatmap.Entities.FindAll(c => c.datamodel.Split(0) == "fillbots");
// init colors
RiqEntity bg = prevEntities.FindLast(c => c.beat <= beat && c.datamodel == "fillbots/background appearance");
RiqEntity obj = prevEntities.FindLast(c => c.beat <= beat && c.datamodel == "fillbots/object appearance");
if (bg != null)
{
BackgroundColorSet(bg.beat, bg.length, bg["colorBGStart"], bg["colorBGEnd"],
bg["colorMetersStart"], bg["colorMeter1Start"], bg["colorMeter2Start"], bg["colorMeter3Start"], bg["colorMeter4Start"], bg["colorMeter5Start"], bg["colorMeter6Start"],
bg["colorMetersEnd"], bg["colorMeter1End"], bg["colorMeter2End"], bg["colorMeter3End"], bg["colorMeter4End"], bg["colorMeter5End"], bg["colorMeter6End"],
bg["separate"], bg["ease"]);
}
if (obj != null)
{
ObjectColorSet(obj["colorFuel"], obj["colorLampOff"], obj["colorLampOn"], obj["colorImpact"], obj["colorFiller"], obj["colorConveyer"]);
}
else
{
ObjectColorSet(new Color(1f, 0.385f, 0.385f), new Color(0.635f, 0.635f, 0.185f), new Color(1f, 1f, 0.42f), new Color(1f, 0.59f, 0.01f), Color.white, Color.white);
}
}
private void Update()
{
var cond = Conductor.instance;
if (cond.isPlaying && !cond.isPaused)
{
if (queuedBots.Count > 0)
{
foreach (var queuedBot in queuedBots)
{
SpawnFillbot(queuedBot.beat, queuedBot.holdLength, queuedBot.size, queuedBot.fuelColor, queuedBot.lampColorOff, queuedBot.lampColorOn, queuedBot.endAnim, queuedBot.altOK, queuedBot.stop, queuedBot.color);
}
queuedBots.Clear();
}
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress))
{
string sizeSuffix = fillerPosition switch
{
BotSize.Small => "Small",
BotSize.Medium => "Medium",
BotSize.Large => "Large",
_ => throw new System.NotImplementedException()
};
filler.DoScaledAnimationAsync("Hold" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armExtension");
}
if (PlayerInput.GetIsAction(InputAction_BasicRelease) && !IsExpectingInputNow(InputAction_BasicRelease))
{
string sizeSuffix = fillerPosition switch
{
BotSize.Small => "Small",
BotSize.Medium => "Medium",
BotSize.Large => "Large",
_ => throw new System.NotImplementedException()
};
filler.DoScaledAnimationAsync("ReleaseWhiff" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armRetractionWhiff");
if (fillerHolding) SoundByte.PlayOneShotGame("fillbots/armRetractionPop");
}
UpdateConveyerBelt(conveyerStartBeat, conveyerNormalizedOffset);
UpdateBackgroundColor();
}
}
public static void PreSpawnFillbot(double beat, double holdLength, int size, Color fuelColor, Color lampColorOff, Color lampColorOn, int endAnim, bool altOK, bool stop, bool color)
{
if (GameManager.instance.currentGame == "fillbots")
{
instance.SpawnFillbot(beat, holdLength, (BotSize)size, fuelColor, lampColorOff, lampColorOn, (EndAnim)endAnim, altOK, stop, color);
}
else
{
queuedBots.Add(new QueuedFillbot
{
beat = beat,
holdLength = holdLength,
size = (BotSize)size,
fuelColor = fuelColor,
lampColorOff = lampColorOff,
lampColorOn = lampColorOn,
endAnim = (EndAnim)endAnim,
altOK = altOK,
stop = stop,
color = color,
});
}
}
private void SpawnFillbot(double beat, double holdLength, BotSize size, Color fuelColor, Color lampColorOff, Color lampColorOn, EndAnim endAnim, bool altOK, bool stop, bool color)
{
NtrFillbot Bot = size switch
{
BotSize.Small => smallBot,
BotSize.Medium => mediumBot,
BotSize.Large => largeBot,
_ => throw new System.NotImplementedException()
};
NtrFillbot spawnedBot = Instantiate(Bot, transform);
if (holdLength > 0) spawnedBot.holdLength = holdLength;
spawnedBot.startBeat = beat;
spawnedBot.endAnim = endAnim;
spawnedBot.altOK = altOK;
spawnedBot.Init();
var actions = new List<BeatAction.Action>();
var fallingBots = currentBots.FindAll(x => x.startBeat < beat && x.startBeat + 3 >= beat);
if (fallingBots.Count > 0) {
actions.Add(new BeatAction.Action(beat - 0.25, delegate
{
foreach (var bot in fallingBots)
{
bot.StackToLeft(beat, 0.25);
}
if (conveyerStartBeat is -2) conveyerStartBeat = beat - 0.25;
}));
actions.Add(new BeatAction.Action(beat, delegate
{
RenewConveyerNormalizedOffset();
conveyerStartBeat = -2;
}));
} else {
actions.Add(new BeatAction.Action(beat - 0.5, delegate
{
RenewConveyerNormalizedOffset();
conveyerStartBeat = -2;
}));
}
actions.Add(new BeatAction.Action(beat, delegate
{
if (!color)
{
fuelColor = fuelColorGlobal;
lampColorOff = lampColorOffGlobal;
lampColorOn = lampColorOnGlobal;
}
spawnedBot.InitColor(fuelColor, lampColorOff, lampColorOn);
}));
actions.Add(new BeatAction.Action(beat + 3, delegate
{
if (!PlayerInput.GetIsAction(InputAction_BasicPressing) && !fillerHolding) filler.DoScaledAnimationAsync("FillerPrepare", 0.5f);
conveyerStartBeat = beat + 3;
fillerPosition = size;
}));
var remainingBots = currentBots.FindAll(x => x.conveyerRestartLength < 0);
if (stop) spawnedBot.conveyerRestartLength = -1;
actions.Add(new BeatAction.Action(beat + 3, delegate
{
foreach (var bot in remainingBots)
{
if (bot.botState is BotState.Idle) bot.conveyerRestartLength = 0.5;
if (bot.conveyerStartBeat is -2) bot.conveyerStartBeat = beat + 3;
}
}));
BeatAction.New(instance, actions);
}
public static void FillErUp(double beat)
{
MultiSound.Play(new MultiSound.Sound[]
{
new MultiSound.Sound("fillbots/fillErUp1", beat - 0.5),
new MultiSound.Sound("fillbots/fillErUp2", beat - 0.25),
new MultiSound.Sound("fillbots/fillErUp3", beat),
}, forcePlay: true);
}
public void ToggleBop(double beat, float length, bool bopOrNah, bool autoBop)
{
if (bopOrNah)
{
for (int i = 0; i < length; i++)
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat + i, delegate {
Bop(toggleGlobal);
toggleGlobal ^= 1;
})
});
}
}
}
private void Bop(int toggle)
{
toggle = (toggle != 0) ? 1 : 0;
foreach (var meter in meters)
{
meter.DoScaledAnimationAsync(toggle switch
{
0 => "Up",
1 or _ => "Down"
}, 0.5f);
toggle ^= 1;
}
var danceBots = currentBots.FindAll(x => x.botState is BotState.Dance);
foreach (var bot in danceBots)
{
bot.SuccessDance();
}
}
private void UpdateConveyerBelt(double startBeat, float offset)
{
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, 1);
float playTime = ((startBeat >= 0 && normalizedBeat >= 0) ? (normalizedBeat + offset) : offset) % 1 / 4;
conveyerBelt.Play("Move", -1, playTime);
UpdateGears((startBeat >= 0 && normalizedBeat >= 0) ? normalizedBeat + offset : offset);
}
private void UpdateGears(float beat)
{
foreach (var gear in gears)
{
gear.localEulerAngles = new Vector3(0, 0, Mathf.LerpUnclamped(0, -90, beat));
}
}
public void RenewConveyerNormalizedOffset()
{
if (conveyerStartBeat is not -1 or -2)
{
float normalizedBeat = Conductor.instance.GetPositionFromBeat(conveyerStartBeat, 1);
if (normalizedBeat >= 0) conveyerNormalizedOffset = (conveyerNormalizedOffset + normalizedBeat) % 4;
}
}
public void Blackout()
{
blackout.SetActive(!blackout.activeSelf);
}
public void BackgroundColorSet(double beat, float length, Color BGStart, Color BGEnd,
Color metersStart, Color meter1Start, Color meter2Start, Color meter3Start, Color meter4Start, Color meter5Start, Color meter6Start,
Color metersEnd, Color meter1End, Color meter2End, Color meter3End, Color meter4End, Color meter5End, Color meter6End,
bool separate, int colorEaseSet)
{
colorEases = new ColorEase[] {
new(beat, length, BGStart, BGEnd, colorEaseSet),
new(beat, length, meter1Start, meter1End, colorEaseSet),
new(beat, length, meter2Start, meter2End, colorEaseSet),
new(beat, length, meter3Start, meter3End, colorEaseSet),
new(beat, length, meter4Start, meter4End, colorEaseSet),
new(beat, length, meter5Start, meter5End, colorEaseSet),
new(beat, length, meter6Start, meter6End, colorEaseSet),
};
if (!separate)
{
for (int i = 1; i < 7; i++)
{
colorEases[i] = new(beat, length, metersStart, metersEnd, colorEaseSet);
}
}
UpdateBackgroundColor();
}
public void ObjectColorSet(Color fuelColor, Color lampColorOff, Color lampColorOn, Color impact, Color filler, Color conveyer)
{
fuelColorGlobal = fuelColor; lampColorOffGlobal = lampColorOff; lampColorOnGlobal = lampColorOn;
impactMaterial.SetColor("_ColorAlpha", impact);
this.conveyerBelt.GetComponent<SpriteRenderer>().color = conveyer;
foreach (var renderer in fillerRenderer)
{
renderer.color = filler;
}
}
private void UpdateBackgroundColor()
{
BGPlane.color = colorEases[0].GetColor();
foreach (var renderer in otherRenderer)
{
renderer.color = colorEases[0].GetColor();
}
for (int i = 0; i < metersFuel.Length; i++)
{
metersFuel[i].color = colorEases[i+1].GetColor();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 162587a8edd49aa49b795dba0ab3d1cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games.Scripts_Fillbots
{
public class FullBody : MonoBehaviour
{
[SerializeField] private SpriteMask mask;
[SerializeField] private Sprite[] sprites;
[SerializeField] private SpriteRenderer fullBody;
[System.NonSerialized] public Color lampColorOff = new Color(0.635f, 0.635f, 0.185f);
[System.NonSerialized] public Color lampColorOn = new Color(1f, 1f, 0.42f);
public enum LampState
{
Off,
On,
}
public void SetMask(int i)
{
mask.sprite = sprites[i];
}
public void SetLamp(LampState state)
{
if (state == LampState.On) fullBody.material.SetColor("_ColorAlpha", lampColorOn);
else fullBody.material.SetColor("_ColorAlpha", lampColorOff);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 272afd477a0f2014ba9a9ca4b9879869
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,517 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_Fillbots
{
public enum BotSize
{
Small,
Medium,
Large
}
public enum BotState
{
Idle,
Holding,
Ace,
Just,
Ng,
Dance,
}
public enum EndAnim
{
Both,
Ace,
Just,
}
public class NtrFillbot : MonoBehaviour
{
[Header("Properties")]
[SerializeField] private BotSize size;
public double holdLength = 4f;
[SerializeField] private float limbFallHeight = 15f;
[System.NonSerialized] public double conveyerRestartLength = 0.5;
[System.NonSerialized] public double startBeat = -1;
[System.NonSerialized] public double conveyerStartBeat = -1;
private double conveyerLength = 1;
private Vector2 startPos;
private float lerpDistance;
private float lerpIdleDistance;
[SerializeField] private float flyDistance;
[SerializeField] private float stackDistanceRate;
[Header("Body Parts")]
[SerializeField] private Animator fullBody;
private Material fullBodyMaterial;
[SerializeField] private Animator legs;
private Transform legsTrans;
[SerializeField] private Animator body;
private Transform bodyTrans;
[SerializeField] private Animator head;
private Transform headTrans;
[SerializeField] private SpriteRenderer fuelFill;
[SerializeField] private Animator fillAnim;
private float legsPosY;
private float bodyPosY;
private float headPosY;
private bool legsHaveFallen;
private bool bodyHasFallen;
private bool headHasFallen;
private Fillbots game;
private GameEvent beepEvent;
private PlayerActionEvent releaseEvent;
private Sound fillSound;
private BotState _botState = BotState.Idle;
public BotState botState { get { return _botState; }}
private bool isExplode = false;
[System.NonSerialized] public bool isStack;
private double stackBeat, stackLength;
[System.NonSerialized] public EndAnim endAnim;
[System.NonSerialized] public bool altOK;
private float normalizedFill;
private void OnDestroy()
{
fillSoundRelease();
}
private void Awake()
{
game = Fillbots.instance;
legsTrans = legs.GetComponent<Transform>();
bodyTrans = body.GetComponent<Transform>();
headTrans = head.GetComponent<Transform>();
legsPosY = legsTrans.position.y;
bodyPosY = bodyTrans.position.y;
headPosY = headTrans.position.y;
legsTrans.position = new Vector3(legsTrans.position.x, legsTrans.position.y + limbFallHeight);
bodyTrans.position = new Vector3(bodyTrans.position.x, bodyTrans.position.y + limbFallHeight);
headTrans.position = new Vector3(headTrans.position.x, headTrans.position.y + limbFallHeight);
startPos = transform.position;
lerpDistance = 0 - startPos.x;
lerpIdleDistance = lerpDistance;
}
public void MoveConveyer(float normalized, float lerpDistance, float flyDistance = 0)
{
if (_botState is BotState.Holding)
{
StopConveyer();
return;
}
transform.position = new Vector3(Mathf.LerpUnclamped(startPos.x, startPos.x + lerpDistance, normalized),
Mathf.LerpUnclamped(startPos.y, startPos.y + flyDistance, normalized));
if (normalized >= 8)
{
game.currentBots.Remove(this);
Destroy(this.gameObject);
}
}
public void StopConveyer()
{
startPos = transform.position;
lerpIdleDistance = 0 - startPos.x;
}
public void StackToLeft(double beat, double length)
{
if (conveyerLength <= stackDistanceRate) return;
isStack = true;
stackBeat = beat - length;
stackLength = length;
conveyerStartBeat += stackDistanceRate;
conveyerLength -= stackDistanceRate;
}
public void Init()
{
conveyerStartBeat = startBeat + 3;
BeatAction.New(game, new List<BeatAction.Action>()
{
new BeatAction.Action(startBeat, delegate { legs.Play("Impact", 0, 0); legsHaveFallen = true; legsTrans.position = new Vector3(legsTrans.position.x, legsPosY); }),
new BeatAction.Action(startBeat + 1, delegate { body.Play("Impact", 0, 0); bodyHasFallen = true; bodyTrans.position = new Vector3(bodyTrans.position.x, bodyPosY);}),
new BeatAction.Action(startBeat + 2, delegate { head.Play("Impact", 0, 0); headHasFallen = true; headTrans.position = new Vector3(headTrans.position.x, headPosY);}),
new BeatAction.Action(startBeat + 3, delegate
{
fullBody.gameObject.SetActive(true);
legs.gameObject.SetActive(false);
head.gameObject.SetActive(false);
body.gameObject.SetActive(false);
})
});
string sizePrefix = size switch
{
BotSize.Small => "small",
BotSize.Medium => "medium",
BotSize.Large => "big",
_ => throw new System.NotImplementedException()
};
List<MultiSound.Sound> sounds = new();
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, 1);
for (int i = (int)Mathf.Ceil(Mathf.Max(normalizedBeat-0.1f, 0)); i <= 2; i++)
{
sounds.Add(new("fillbots/" + sizePrefix + "Fall", startBeat + i));
}
if (sounds.Count > 0) MultiSound.Play(sounds.ToArray(), true, true);
game.ScheduleInput(startBeat, 4, Fillbots.InputAction_BasicPress, JustHold, Empty, Empty);
game.currentBots.Add(this);
}
public void InitColor(Color fuelColor, Color lampColorOff, Color lampColorOn)
{
fullBodyMaterial = fullBody.GetComponent<SpriteRenderer>().material;
fullBodyMaterial.SetColor("_ColorBravo", fuelColor);
fullBodyMaterial.SetColor("_ColorAlpha", lampColorOff);
Material botMaterial;
botMaterial = head.GetComponent<SpriteRenderer>().material;
botMaterial.SetColor("_ColorAlpha", lampColorOff);
fuelFill.color = fuelColor;
var full = fullBody.GetComponent<FullBody>();
full.lampColorOff = lampColorOff;
full.lampColorOn = lampColorOn;
}
private void Update()
{
var cond = Conductor.instance;
if (cond.isPlaying && !cond.isPaused)
{
if (startBeat != -1)
{
if (!legsHaveFallen) UpdateLimbPosition(cond, startBeat, legsTrans, legsPosY);
if (!bodyHasFallen) UpdateLimbPosition(cond, startBeat + 1, bodyTrans, bodyPosY);
if (!headHasFallen) UpdateLimbPosition(cond, startBeat + 2, headTrans, headPosY);
if (isStack) HandleStacking(cond);
if (headHasFallen && bodyHasFallen && legsHaveFallen) HandleConveyer(cond);
}
if (_botState is BotState.Holding)
{
HandleHolding(cond);
}
else if (fullBody.gameObject.activeSelf)
{
fillAnim.DoNormalizedAnimation("Fill", normalizedFill);
}
}
}
private void UpdateLimbPosition(Conductor cond, double targetBeat, Transform limbTrans, float limbPosY)
{
float normalizedBeat = cond.GetPositionFromBeat(targetBeat - 0.25, 0.25);
float lerpedY = Mathf.Lerp(limbPosY + limbFallHeight, limbPosY, normalizedBeat);
limbTrans.position = new Vector3(limbTrans.position.x, Mathf.Clamp(lerpedY, limbPosY, limbPosY + limbFallHeight));
}
private void HandleStacking(Conductor cond)
{
float normalizedBeat = cond.GetPositionFromBeat(stackBeat, stackLength);
if (normalizedBeat >= 0 && normalizedBeat < 1)
{
MoveConveyer(normalizedBeat, lerpDistance * stackDistanceRate);
}
else if (normalizedBeat >= 1)
{
MoveConveyer(1, lerpDistance * stackDistanceRate);
StopConveyer();
isStack = false;
}
}
private void HandleConveyer(Conductor cond)
{
if (this.conveyerStartBeat >= 0)
{
float normalizedBeat = cond.GetPositionFromBeat(this.conveyerStartBeat, conveyerLength);
if (normalizedBeat >= 0)
{
if (_botState is BotState.Ace) MoveConveyer(normalizedBeat, lerpDistance, flyDistance);
else if (_botState is BotState.Idle) MoveConveyer(normalizedBeat, lerpIdleDistance);
else MoveConveyer(normalizedBeat, lerpDistance);
}
}
else
{
StopConveyer();
}
}
private void HandleHolding(Conductor cond)
{
float normalizedBeat = cond.GetPositionFromBeat(startBeat + 4, holdLength);
float normalizedExplodeBeat = cond.GetPositionFromBeat(startBeat + 4, holdLength + 0.25);
if (!isExplode && beepEvent != null && beepEvent.enabled && ReportBeat(ref beepEvent.lastReportedBeat))
{
if (beepEvent.lastReportedBeat < beepEvent.startBeat + beepEvent.length)
{
SoundByte.PlayOneShotGame("fillbots/beep");
}
fullBody.DoScaledAnimationAsync("HoldBeat", 1f);
string sizeSuffix = game.fillerPosition switch
{
BotSize.Small => "Small",
BotSize.Medium => "Medium",
BotSize.Large => "Large",
_ => throw new System.NotImplementedException()
};
game.filler.DoScaledAnimationAsync("HoldBeat" + sizeSuffix, 1f);
}
fillAnim.DoNormalizedAnimation("Fill", Mathf.Clamp(normalizedBeat, 0, 1));
if (!isExplode && !game.IsExpectingInputNow(Fillbots.InputAction_BasicRelease) && normalizedExplodeBeat >= 1f)
{
HandleExplosion(cond);
}
else if (PlayerInput.GetIsAction(Fillbots.InputAction_BasicRelease) && !game.IsExpectingInputNow(Fillbots.InputAction_BasicRelease))
{
HandleRelease(cond, normalizedBeat);
}
}
private void HandleExplosion(Conductor cond)
{
isExplode = true;
fullBody.Play("Beyond", 0, 0);
BeatAction.New(game, new List<BeatAction.Action>()
{
new BeatAction.Action(startBeat + holdLength + 5.5, delegate {
game.fillerHolding = false;
SoundByte.PlayOneShotGame("fillbots/explosion");
fillSoundRelease();
game.currentBots.Remove(this);
Destroy(this.gameObject);
}),
});
}
private void HandleRelease(Conductor cond, float normalizedBeat)
{
if (normalizedBeat < 1)
{
fullBody.Play("Dead", 0, 0);
SoundByte.PlayOneShotGame("fillbots/miss");
}
else if (!isExplode)
{
fullBody.DoScaledAnimationAsync("ReleaseLate", 0.5f);
SoundByte.PlayOneShotGame("fillbots/miss");
}
fillSoundRelease();
beepEvent.enabled = false;
_botState = BotState.Ng;
game.fillerHolding = false;
normalizedFill = normalizedBeat;
if (conveyerRestartLength >= 0)
{
this.conveyerStartBeat = cond.songPositionInBeats + conveyerRestartLength;
if (game.conveyerStartBeat == -1) game.conveyerStartBeat = this.conveyerStartBeat;
}
else
{
this.conveyerStartBeat = -2;
game.conveyerStartBeat = -1;
}
releaseEvent.Disable();
}
private void JustHold(PlayerActionEvent caller, float state)
{
string sizeSuffix = game.fillerPosition switch
{
BotSize.Small => "Small",
BotSize.Medium => "Medium",
BotSize.Large => "Large",
_ => throw new System.NotImplementedException()
};
game.filler.DoScaledAnimationAsync("Hold" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armExtension");
if (state >= 1f || state <= -1f)
{
fullBody.Play("HoldBarely", 0, 0);
return;
}
game.RenewConveyerNormalizedOffset();
game.conveyerStartBeat = -1;
conveyerLength = 1;
transform.position = new Vector3(0, transform.position.y, 0);
_botState = BotState.Holding;
game.fillerHolding = true;
fullBody.DoScaledAnimationAsync("Hold", 1f);
SoundByte.PlayOneShotGame("fillbots/beep");
float watarPitch = 3 / (float)(holdLength + 3) + 0.5f;
fillSound = SoundByte.PlayOneShotGame("fillbots/water", -1, watarPitch, 1, true);
fillSound.BendUp((float)holdLength * Conductor.instance.pitchedSecPerBeat / 0.5f,2*watarPitch); // sorry
releaseEvent = game.ScheduleInput(startBeat + 4, holdLength, Fillbots.InputAction_BasicRelease, JustRelease, Empty, Empty);
beepEvent = new GameEvent()
{
startBeat = startBeat + 4,
lastReportedBeat = startBeat + 4,
length = (float)holdLength,
enabled = true
};
}
private void JustRelease(PlayerActionEvent caller, float state)
{
fillSoundRelease();
beepEvent.enabled = false;
if (conveyerRestartLength >= 0)
{
this.conveyerStartBeat = caller.timer + caller.startBeat + conveyerRestartLength;
game.RenewConveyerNormalizedOffset();
if (game.conveyerStartBeat is not -2) game.conveyerStartBeat = this.conveyerStartBeat;
}
else
{
this.conveyerStartBeat = -2;
game.conveyerStartBeat = -1;
}
string sizeSuffix = game.fillerPosition switch
{
BotSize.Small => "Small",
BotSize.Medium => "Medium",
BotSize.Large => "Large",
_ => throw new System.NotImplementedException()
};
if (state >= 1f)
{
_botState = BotState.Ng;
SoundByte.PlayOneShotGame("fillbots/miss");
game.filler.DoScaledAnimationAsync("ReleaseWhiff" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armRetractionPop");
fullBody.DoScaledAnimationAsync("ReleaseLate", 0.5f);
return;
}
else if (state <= -1f)
{
_botState = BotState.Ng;
SoundByte.PlayOneShotGame("fillbots/miss");
game.filler.DoScaledAnimationAsync("ReleaseWhiff" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armRetractionPop");
fullBody.DoScaledAnimationAsync("ReleaseEarly", 0.5f);
return;
}
if ( ((endAnim is EndAnim.Both && state == 0) || endAnim is EndAnim.Ace) && conveyerRestartLength >= 0 )
{
_botState = BotState.Ace;
BeatAction.New(game, new List<BeatAction.Action>()
{
new BeatAction.Action(caller.startBeat + caller.timer + 0.5, delegate {
fullBody.DoScaledAnimationAsync("Fly", 0.5f);
}),
});
}
else
{
_botState = BotState.Just;
if (size is BotSize.Small)
{
BeatAction.New(game, new List<BeatAction.Action>()
{
new BeatAction.Action(caller.startBeat + caller.timer + 1, delegate {
fullBody.DoScaledAnimationAsync("Success", 0.5f);
}),
});
}
else
{
BeatAction.New(game, new List<BeatAction.Action>()
{
new BeatAction.Action(caller.startBeat + caller.timer + 0.9, delegate {
_botState = BotState.Dance;
}),
});
}
}
game.fillerHolding = false;
game.filler.DoScaledAnimationAsync("Release" + sizeSuffix, 0.5f);
SoundByte.PlayOneShotGame("fillbots/armRetraction");
fullBody.DoScaledAnimationAsync("Release", 1f);
string sizePrefix = size switch
{
BotSize.Small => "small",
BotSize.Medium => "medium",
BotSize.Large => "big",
_ => throw new System.NotImplementedException()
};
MultiSound.Play(new MultiSound.Sound[]
{
new MultiSound.Sound("fillbots/" + sizePrefix + "Move", caller.startBeat + caller.timer + (altOK ? 0 : 0.5)),
new MultiSound.Sound("fillbots/" + sizePrefix + "OK1", caller.startBeat + caller.timer + (altOK ? 0 : 0.5)),
new MultiSound.Sound("fillbots/" + sizePrefix + "OK2", caller.startBeat + caller.timer + (altOK ? 0.5 : 1)),
});
}
private void Empty(PlayerActionEvent caller) { }
private void fillSoundRelease()
{
if (fillSound != null)
{
fillSound.KillLoop(0);
fillSound = null;
}
}
public void SuccessDance()
{
fullBody.DoScaledAnimationAsync("Success", 0.5f);
}
private bool ReportBeat(ref double lastReportedBeat)
{
var cond = Conductor.instance;
bool result = cond.songPositionInBeats >= (lastReportedBeat) + 1f;
if (result)
{
lastReportedBeat += 1f;
}
return result;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b18e15957787a94ab8387cfe9bdb536
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: