HeavenStudio/Assets/Scripts/Games/SpaceSoccer/SpaceSoccer.cs
2023-05-18 20:12:06 +00:00

515 lines
23 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrSoccerLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("spaceSoccer", "Space Soccer", "ff7d27", false, false, new List<GameAction>()
{
new GameAction("ball dispense", "Ball Dispense")
{
function = delegate { SpaceSoccer.instance.Dispense(eventCaller.currentEntity.beat, !eventCaller.currentEntity["toggle"], false, eventCaller.currentEntity["down"]); },
defaultLength = 2f,
parameters = new List<Param>()
{
new Param("toggle", false, "Disable Sound", "Disables the dispense sound"),
new Param("down", false, "Down Sound", "Will the Down sound be played?")
},
inactiveFunction = delegate
{
if (!eventCaller.currentEntity["toggle"]) { SpaceSoccer.DispenseSound(eventCaller.currentEntity.beat, eventCaller.currentEntity["down"]);}
}
},
new GameAction("high kick-toe!", "High Kick-Toe!")
{
defaultLength = 3f,
parameters = new List<Param>()
{
new Param("swing", new EntityTypes.Float(0, 1, 0.5f), "Swing", "The amount of swing")
}
},
new GameAction("npc kickers enter or exit", "NPC Kickers Enter or Exit")
{
function = delegate { var e = eventCaller.currentEntity; SpaceSoccer.instance.NPCKickersEnterOrExit(e.beat, e.length, e["choice"], e["ease"], e["amount"], e["x"], e["y"], e["z"], e["override"], e["preset"]); },
defaultLength = 4f,
parameters = new List<Param>()
{
new Param("preset", SpaceSoccer.EnterExitPresets.FiveKickers, "Preset", "Which preset should be used?"),
new Param("choice", SpaceSoccer.AnimationToPlay.Enter, "Enter Or Exit", "Whether the kickers should exit or enter."),
new Param("ease", EasingFunction.Ease.Linear, "Ease", "The Ease of the entering or exiting."),
new Param("amount", new EntityTypes.Integer(2, 30, 5), "Amount", "Amount of Space Kickers."),
new Param("x", new EntityTypes.Float(-30, 30, 2f), "X Distance", "How much distance should there be between the space kickers on the x axis?"),
new Param("y", new EntityTypes.Float(-30, 30, -0.5f), "Y Distance", "How much distance should there be between the space kickers on the y axis?"),
new Param("z", new EntityTypes.Float(-30, 30, 1.25f), "Z Distance", "How much distance should there be between the space kickers on the z axis?"),
new Param("override", true, "Override Easing", "Should this block override the easing of the space kickers' positions?")
},
resizable = true
},
new GameAction("easePos", "Ease NPC Space Kicker Distances")
{
function = delegate {var e = eventCaller.currentEntity; SpaceSoccer.instance.EaseSpaceKickersPositions(e.beat, e.length, e["ease"], e["x"], e["y"], e["z"]); },
defaultLength = 4f,
resizable = true,
parameters = new List<Param>()
{
new Param("x", new EntityTypes.Float(-30, 30, 2f), "X Distance", "How much distance should there be between the space kickers on the x axis?"),
new Param("y", new EntityTypes.Float(-30, 30, -0.5f), "Y Distance", "How much distance should there be between the space kickers on the y axis?"),
new Param("z", new EntityTypes.Float(-30, 30, 1.25f), "Z Distance", "How much distance should there be between the space kickers on the z axis?"),
new Param("ease", EasingFunction.Ease.Linear, "Ease", "The Ease of the space kickers moving."),
}
},
new GameAction("pMove", "Move Player")
{
function = delegate {var e = eventCaller.currentEntity; SpaceSoccer.instance.MovePlayerKicker(e.beat, e.length, e["ease"], e["x"], e["y"], e["z"], e["sound"], e["preset"]); },
defaultLength = 4f,
resizable = true,
parameters = new List<Param>()
{
new Param("preset", SpaceSoccer.PlayerPresets.LaunchStart, "Preset", "Which preset should be used?"),
new Param("x", new EntityTypes.Float(-30, 30, 0f), "X Pos", "Which position should the player move to on the x axis?"),
new Param("y", new EntityTypes.Float(-30, 30, 0f), "Y Pos", "Which position should the player move to on the y axis?"),
new Param("z", new EntityTypes.Float(-30, 30, 0f), "Z Pos", "Which position should the player move to on the z axis?"),
new Param("ease", EasingFunction.Ease.Linear, "Ease", "The Ease of the space kickers moving."),
new Param("sound", SpaceSoccer.LaunchSoundToPlay.None, "Sound", "Which launch sound should be played at the start of this block?")
}
},
new GameAction("changeBG", "Change Background Color")
{
function = delegate {var e = eventCaller.currentEntity; SpaceSoccer.instance.FadeBackgroundColor(e["start"], e["end"], e["startDots"], e["endDots"], e.length, e["toggle"]); },
defaultLength = 1f,
resizable = true,
parameters = new List<Param>()
{
new Param("start", SpaceSoccer.defaultBGColor, "Start Color", "The start color for the fade or the color that will be switched to if -instant- is ticked on."),
new Param("end", SpaceSoccer.defaultBGColor, "End Color", "The end color for the fade."),
new Param("startDots", Color.white, "Start Color (Dots)", "The start color for the fade or the color that will be switched to if -instant- is ticked on."),
new Param("endDots", Color.white, "End Color (Dots)", "The end color for the fade."),
new Param("toggle", false, "Instant", "Should the background instantly change color?")
}
},
new GameAction("scroll", "Scrolling Background")
{
function = delegate { var e = eventCaller.currentEntity; SpaceSoccer.instance.UpdateScrollSpeed(e["x"], e["y"]); },
defaultLength = 1f,
parameters = new List<Param>() {
new Param("x", new EntityTypes.Float(-5f, 5f, 0.09f), "Horizontal", "How fast does the background move horizontally?"),
new Param("y", new EntityTypes.Float(-5f, 5f, 0.32f), "Vertical", "How fast does the background move vertically?"),
}
},
new GameAction("stopBall", "Stop Ball")
{
function = delegate { SpaceSoccer.instance.StopBall(eventCaller.currentEntity["toggle"]); },
parameters = new List<Param>()
{
new Param("toggle", true, "Stop ball?", "Should the ball be stopped? If ticked off the kickers will regain their ability to use the ball.")
}
},
// This is still here for "backwards-compatibility" but is hidden in the editor (it does absolutely nothing however)
new GameAction("keep-up", "")
{
defaultLength = 4f,
resizable = true,
hidden = true
},
new GameAction("npc kickers instant enter or exit", "NPC Kickers Instant Enter or Exit")
{
function = delegate
{
var e = eventCaller.currentEntity;
int choice;
if (e["toggle"])
{
choice = (int)SpaceSoccer.AnimationToPlay.Exit;
}
else
{
choice = (int)SpaceSoccer.AnimationToPlay.Enter;
}
SpaceSoccer.instance.NPCKickersEnterOrExit(e.beat, e.length, choice, (int)EasingFunction.Ease.Instant, 5, 1.75f, 0.25f, 0.75f, true, (int)SpaceSoccer.EnterExitPresets.Custom);
},
defaultLength = 0.5f,
parameters = new List<Param>()
{
new Param("toggle", false, "Should Exit?", "Whether the kickers should be exited or entered.")
},
hidden = true
},
});
}
}
}
namespace HeavenStudio.Games
{
using Scripts_SpaceSoccer;
using HeavenStudio.Common;
using UnityEngine.Rendering;
public class SpaceSoccer : Minigame
{
public enum EnterExitPresets
{
FiveKickers,
DuoKickers,
Custom
}
public enum PlayerPresets
{
LaunchStart = 0,
LaunchEnd = 1,
Custom = 2
}
public enum LaunchSoundToPlay
{
None = 0,
LaunchStart = 1,
LaunchEnd = 2
}
public enum AnimationToPlay
{
Enter = 0,
Exit = 1
}
private static Color _defaultBGColor;
public static Color defaultBGColor
{
get
{
ColorUtility.TryParseHtmlString("#FF7D27", out _defaultBGColor);
return _defaultBGColor;
}
}
[Header("Components")]
[SerializeField] private GameObject kickerPrefab;
[SerializeField] private GameObject ballRef;
[SerializeField] private List<Kicker> kickers;
[SerializeField] private SuperScroll backgroundSprite;
[SerializeField] private SpriteRenderer bg;
[Header("Properties")]
[SerializeField] SuperCurveObject.Path[] ballPaths;
public bool ballDispensed;
float lastDispensedBeat;
float scrollBeat;
float scrollOffsetX;
float scrollOffsetY;
float currentScrollLengthX = 0.09f;
float currentScrollLengthY = 0.32f;
Tween bgColorTween;
Tween dotColorTween;
#region Space Kicker Position Easing
float easeBeat;
float easeLength;
EasingFunction.Ease lastEase;
Vector3 lastPos = new Vector3();
Vector3 currentPos = new Vector3();
float easeBeatP;
float easeLengthP;
EasingFunction.Ease lastEaseP;
Vector3 lastPosP = new Vector3();
Vector3 currentPosP = new Vector3();
#endregion
public static SpaceSoccer instance { get; private set; }
private void Awake()
{
instance = this;
}
new void OnDrawGizmos()
{
base.OnDrawGizmos();
foreach (SuperCurveObject.Path path in ballPaths)
{
if (path.preview)
{
ballRef.GetComponent<Ball>().DrawEditorGizmo(path);
}
}
}
private void Update()
{
var cond = Conductor.instance;
float normalizedX = (Time.realtimeSinceStartup - scrollBeat) * currentScrollLengthX;
float normalizedY = (Time.realtimeSinceStartup - scrollBeat) * currentScrollLengthY;
backgroundSprite.NormalizedX = -scrollOffsetX - normalizedX;
backgroundSprite.NormalizedY = -scrollOffsetY - normalizedY;
float normalizedEaseBeat = cond.GetPositionFromBeat(easeBeat, easeLength);
if (normalizedEaseBeat <= 1 && normalizedEaseBeat > 0)
{
EasingFunction.Function func = EasingFunction.GetEasingFunction(lastEase);
float newPosX = func(lastPos.x, currentPos.x, normalizedEaseBeat);
float newPosY = func(lastPos.y, currentPos.y, normalizedEaseBeat);
float newPosZ = func(lastPos.z, currentPos.z, normalizedEaseBeat);
UpdateKickersPositions(newPosX, newPosY, newPosZ);
}
float normalizedPBeat = cond.GetPositionFromBeat(easeBeatP, easeLengthP);
if (normalizedPBeat <= 1 && normalizedPBeat > 0)
{
EasingFunction.Function func = EasingFunction.GetEasingFunction(lastEaseP);
float newPosX = func(lastPosP.x, currentPosP.x, normalizedPBeat);
float newPosY = func(lastPosP.y, currentPosP.y, normalizedPBeat);
float newPosZ = func(lastPosP.z, currentPosP.z, normalizedPBeat);
kickers[0].transform.parent.position = new Vector3(3.384f - newPosX, newPosY, newPosZ);
}
}
public void StopBall(bool stop)
{
foreach (var kicker in kickers)
{
kicker.StopBall(stop);
}
}
public void NPCKickersEnterOrExit(float beat, float length, int animToPut, int easeToPut, int amount, float xDistance, float yDistance, float zDistance, bool overrideEasing, int preset)
{
switch (preset)
{
case (int)EnterExitPresets.Custom:
UpdateSpaceKickers(amount, xDistance, yDistance, zDistance, overrideEasing);
break;
case (int)EnterExitPresets.DuoKickers:
UpdateSpaceKickers(2, 7, -6, 10, overrideEasing);
break;
case (int)EnterExitPresets.FiveKickers:
UpdateSpaceKickers(5, 2, -0.5f, 1.25f, overrideEasing);
break;
}
string animName = "Enter";
switch (animToPut)
{
case (int)AnimationToPlay.Enter:
animName = "Enter";
break;
case (int)AnimationToPlay.Exit:
animName = "Exit";
break;
}
foreach (var kicker in kickers)
{
if (kicker.player) continue;
kicker.SetAnimParams(beat, length, animName, easeToPut);
}
}
public override void OnGameSwitch(float beat)
{
foreach(var entity in GameManager.instance.Beatmap.entities)
{
if(entity.beat > beat) //the list is sorted based on the beat of the entity, so this should work fine.
{
break;
}
if(entity.datamodel != "spaceSoccer/ball dispense" || entity.beat + entity.length <= beat) //check for dispenses that happen right before the switch
{
continue;
}
Dispense(entity.beat, false);
break;
}
}
public SuperCurveObject.Path GetPath(string name)
{
foreach (SuperCurveObject.Path path in ballPaths)
{
if (path.name == name)
{
return path;
}
}
return default(SuperCurveObject.Path);
}
public void UpdateScrollSpeed(float scrollSpeedX, float scrollSpeedY)
{
scrollOffsetX = (Time.realtimeSinceStartup - scrollBeat) * currentScrollLengthX;
scrollOffsetY = (Time.realtimeSinceStartup - scrollBeat) * currentScrollLengthY;
currentScrollLengthX = scrollSpeedX;
currentScrollLengthY = scrollSpeedY;
scrollBeat = Time.realtimeSinceStartup;
}
public void EaseSpaceKickersPositions(float beat, float length, int ease, float xDistance, float yDistance, float zDistance)
{
easeBeat = beat;
easeLength = length;
lastEase = (EasingFunction.Ease)ease;
lastPos = currentPos;
currentPos = new Vector3(xDistance, yDistance, zDistance);
}
public void UpdateKickersPositions(float xDistance, float yDistance, float zDistance)
{
for (int i = 1; i < kickers.Count; i++)
{
kickers[i].transform.parent.position = new Vector3(3.384f - xDistance * i, -yDistance * i, zDistance * i);
CircularMotion circularMotion = kickers[i].GetComponent<CircularMotion>();
circularMotion.width = 0.85f - Mathf.Pow(zDistance * 10f, -1f);
circularMotion.height = 0.5f - Mathf.Pow(zDistance * 10f, -1f);
}
}
public void MovePlayerKicker(float beat, float length, int ease, float xPos, float yPos, float zPos, int soundToPlay, int preset)
{
switch (preset)
{
case (int)PlayerPresets.Custom:
break;
case (int)PlayerPresets.LaunchStart:
lastEaseP = EasingFunction.Ease.EaseInOutCubic;
xPos = -6;
yPos = 15;
zPos = 0;
soundToPlay = (int)LaunchSoundToPlay.LaunchStart;
break;
case (int)PlayerPresets.LaunchEnd:
lastEaseP = EasingFunction.Ease.EaseInOutQuint;
xPos = -4;
yPos = 15;
zPos = 0;
soundToPlay = (int)LaunchSoundToPlay.LaunchEnd;
break;
}
easeBeatP = beat;
easeLengthP = length;
lastEaseP = (EasingFunction.Ease)ease;
lastPosP = currentPosP;
currentPosP = new Vector3(-xPos, yPos, -zPos);
switch (soundToPlay)
{
case (int)LaunchSoundToPlay.None:
break;
case (int)LaunchSoundToPlay.LaunchStart:
Jukebox.PlayOneShotGame("spaceSoccer/jet1");
break;
case (int)LaunchSoundToPlay.LaunchEnd:
Jukebox.PlayOneShotGame("spaceSoccer/jet2");
break;
}
}
public void UpdateSpaceKickers(int amount, float xDistance = 1.75f, float yDistance = 0.25f, float zDistance = 0.75f, bool overrideEasing = true)
{
for (int i = kickers.Count - 1; i > 0; i--)
{
if (i >= amount)
{
Kicker kickerToDestroy = kickers[i];
kickers.Remove(kickerToDestroy);
Destroy(kickerToDestroy.transform.parent.gameObject);
}
}
if (overrideEasing)
{
UpdateKickersPositions(xDistance, yDistance, zDistance);
currentPos = new Vector3(xDistance, yDistance, zDistance);
}
for (int i = kickers.Count; i < amount; i++)
{
Transform kickerHolder = Instantiate(kickerPrefab, transform).transform;
kickerHolder.transform.position = new Vector3(kickerHolder.transform.position.x - xDistance * i, kickerHolder.transform.position.y - yDistance * i, kickerHolder.transform.position.z + zDistance * i);
Kicker spawnedKicker = kickerHolder.GetChild(0).GetComponent<Kicker>();
CircularMotion circularMotion = spawnedKicker.GetComponent<CircularMotion>();
circularMotion.width = 0.85f - Mathf.Pow(zDistance * 10f, -1f);
circularMotion.height = 0.5f - Mathf.Pow(zDistance * 10f, -1f);
circularMotion.timeOffset = kickers[0].GetComponent<CircularMotion>().timeCounter;
if (0 > zDistance)
{
spawnedKicker.GetComponent<SortingGroup>().sortingOrder = i;
}
else
{
spawnedKicker.GetComponent<SortingGroup>().sortingOrder = -i;
}
kickers.Add(spawnedKicker);
kickerHolder.gameObject.SetActive(true);
}
if (ballDispensed) Dispense(lastDispensedBeat, false, true);
}
public void Dispense(float beat, bool playSound = true, bool ignorePlayer = false, bool playDown = false)
{
if (!ballDispensed) lastDispensedBeat = beat;
ballDispensed = true;
for (int i = 0; i < kickers.Count; i++)
{
Kicker kicker = kickers[i];
if (i == 0) kicker.player = true;
if (kicker.ball != null || (ignorePlayer && i == 0)) continue;
GameObject ball = Instantiate(ballRef, kicker.transform.GetChild(0));
ball.SetActive(true);
Ball ball_ = ball.GetComponent<Ball>();
ball_.Init(kicker, beat);
if (kicker.player && playSound)
{
DispenseSound(beat, playDown);
}
kicker.DispenseBall(beat);
kicker.canKick = true;
}
}
public static void DispenseSound(float beat, bool playDown)
{
if (playDown) Jukebox.PlayOneShot("games/spaceSoccer/down", beat);
MultiSound.Play(new MultiSound.Sound[]
{
new MultiSound.Sound("spaceSoccer/dispenseNoise", beat),
new MultiSound.Sound("spaceSoccer/dispenseTumble1", beat),
new MultiSound.Sound("spaceSoccer/dispenseTumble2", beat + 0.25f),
new MultiSound.Sound("spaceSoccer/dispenseTumble2B",beat + 0.25f),
new MultiSound.Sound("spaceSoccer/dispenseTumble3", beat + 0.75f),
new MultiSound.Sound("spaceSoccer/dispenseTumble4", beat + 1f),
new MultiSound.Sound("spaceSoccer/dispenseTumble5", beat + 1.25f),
new MultiSound.Sound("spaceSoccer/dispenseTumble6", beat + 1.5f),
new MultiSound.Sound("spaceSoccer/dispenseTumble6B",beat + 1.75f),
}, forcePlay:true);
}
public void ChangeBackgroundColor(Color color, Color dotColor, float beats)
{
var seconds = Conductor.instance.secPerBeat * beats;
if (bgColorTween != null)
bgColorTween.Kill(true);
if (dotColorTween != null)
dotColorTween.Kill(true);
if (seconds == 0)
{
bg.color = color;
backgroundSprite.Material.SetColor("_Color", dotColor);
}
else
{
bgColorTween = bg.DOColor(color, seconds);
dotColorTween = backgroundSprite.Material.DOColor(dotColor, seconds);
}
}
public void FadeBackgroundColor(Color start, Color end, Color startDot, Color endDot, float beats, bool instant)
{
ChangeBackgroundColor(start, startDot, 0f);
if (!instant) ChangeBackgroundColor(end, endDot, beats);
}
}
}