mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 10:47:39 +02:00
Blue Bear Final Tweaks (#581)
* scaled animations + barely + new curves * emotion system revamped * Whiff sound!!!
This commit is contained in:
@ -27,13 +27,21 @@ namespace HeavenStudio.Games.Loaders
|
||||
function = delegate { BlueBear.instance.SpawnTreat(eventCaller.currentEntity.beat, true, eventCaller.currentEntity.beat); },
|
||||
defaultLength = 4,
|
||||
},
|
||||
new GameAction("setEmotion", "Set Emotion")
|
||||
new GameAction("setEmotion", "Emotion")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; BlueBear.instance.SetEmotion(e.beat, e.length, e["type"]); },
|
||||
defaultLength = 0.5f,
|
||||
function = delegate { var e = eventCaller.currentEntity; BlueBear.instance.SetEmotion(e["type"]); },
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("type", BlueBear.EmotionType.ClosedEyes, "Type", "Which emotion should the blue bear use?")
|
||||
new Param("type", BlueBear.EmotionType.ClosedEyes, "Emotion", "Which emotion should the blue bear use?")
|
||||
}
|
||||
},
|
||||
new GameAction("stretchEmotion", "Long Emotion")
|
||||
{
|
||||
defaultLength = 4,
|
||||
resizable = true,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("type", BlueBear.EmotionStretchType.LookUp, "Emotion", "Which emotion should the blue bear use?")
|
||||
}
|
||||
},
|
||||
new GameAction("wind", "Wind")
|
||||
@ -75,17 +83,21 @@ namespace HeavenStudio.Games
|
||||
{
|
||||
using Jukebox;
|
||||
using Scripts_BlueBear;
|
||||
|
||||
public class BlueBear : Minigame
|
||||
{
|
||||
public enum EmotionType
|
||||
{
|
||||
Neutral,
|
||||
ClosedEyes,
|
||||
LookUp,
|
||||
Smile,
|
||||
Sad,
|
||||
InstaSad,
|
||||
Sigh
|
||||
Neutral = 0,
|
||||
ClosedEyes = 1,
|
||||
Cry = 2,
|
||||
Sigh = 3
|
||||
}
|
||||
public enum EmotionStretchType
|
||||
{
|
||||
LookUp = 0,
|
||||
Smile = 1,
|
||||
StartCrying = 2,
|
||||
}
|
||||
public enum StoryType
|
||||
{
|
||||
@ -117,15 +129,9 @@ namespace HeavenStudio.Games
|
||||
static int rightCrumbAppearThreshold = 15;
|
||||
static int leftCrumbAppearThreshold = 30;
|
||||
static int eatenTreats = 0;
|
||||
double emotionStartBeat;
|
||||
float emotionLength;
|
||||
string emotionAnimName;
|
||||
bool crying;
|
||||
private List<RiqEntity> _allStoryEvents = new();
|
||||
|
||||
[Header("Curves")]
|
||||
public BezierCurve3D donutCurve;
|
||||
public BezierCurve3D cakeCurve;
|
||||
[SerializeField] private SuperCurveObject.Path[] _treatCurves;
|
||||
|
||||
[Header("Gradients")]
|
||||
public Gradient donutGradient;
|
||||
@ -190,6 +196,31 @@ namespace HeavenStudio.Games
|
||||
new("CtrBearRight", new int[] { IARight, IARight, IARight },
|
||||
IA_PadRight, IA_TouchRight, IA_BatonRight);
|
||||
|
||||
// Editor gizmo to draw trajectories
|
||||
new void OnDrawGizmos()
|
||||
{
|
||||
base.OnDrawGizmos();
|
||||
foreach (SuperCurveObject.Path path in _treatCurves)
|
||||
{
|
||||
if (path.preview)
|
||||
{
|
||||
donutBase.GetComponent<SuperCurveObject>().DrawEditorGizmo(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SuperCurveObject.Path GetPath(string name)
|
||||
{
|
||||
foreach (SuperCurveObject.Path path in _treatCurves)
|
||||
{
|
||||
if (path.name == name)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return default(SuperCurveObject.Path);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
foreach (var evt in scheduledInputs)
|
||||
@ -254,37 +285,100 @@ namespace HeavenStudio.Games
|
||||
private void Update()
|
||||
{
|
||||
headAndBodyAnim.SetBool("ShouldOpenMouth", foodHolder.childCount != 0);
|
||||
if (headAndBodyAnim.GetBool("ShouldOpenMouth"))
|
||||
{
|
||||
_emotionCancelled = true;
|
||||
}
|
||||
|
||||
if (PlayerInput.GetIsAction(InputAction_Left) && !IsExpectingInputNow(InputAction_Left.inputLockCategory))
|
||||
{
|
||||
SoundByte.PlayOneShotGame("blueBear/whiff");
|
||||
Bite(true);
|
||||
}
|
||||
else if (PlayerInput.GetIsAction(InputAction_Right) && !IsExpectingInputNow(InputAction_Right.inputLockCategory))
|
||||
{
|
||||
SoundByte.PlayOneShotGame("blueBear/whiff");
|
||||
Bite(false);
|
||||
}
|
||||
|
||||
Conductor cond = Conductor.instance;
|
||||
UpdateEmotions();
|
||||
|
||||
if (cond.isPlaying && !cond.isPaused)
|
||||
{
|
||||
float normalizedBeat = cond.GetPositionFromBeat(emotionStartBeat, emotionLength);
|
||||
if (normalizedBeat >= 0 && normalizedBeat <= 1f)
|
||||
{
|
||||
//headAndBodyAnim.DoNormalizedAnimation(emotionAnimName, normalizedBeat);
|
||||
}
|
||||
}
|
||||
UpdateStory();
|
||||
headAndBodyAnim.SetScaledAnimationSpeed();
|
||||
bagsAnim.SetScaledAnimationSpeed();
|
||||
cakeBagAnim.SetScaledAnimationSpeed();
|
||||
donutBagAnim.SetScaledAnimationSpeed();
|
||||
windAnim.SetScaledAnimationSpeed();
|
||||
}
|
||||
|
||||
private bool _emotionCancelled = false;
|
||||
private int _emotionIndex = 0;
|
||||
private List<RiqEntity> _allEmotionsStretch = new();
|
||||
private EmotionStretchType _lastEmotion = EmotionStretchType.LookUp;
|
||||
|
||||
private void UpdateEmotions()
|
||||
{
|
||||
var cond = Conductor.instance;
|
||||
if (_allEmotionsStretch.Count == 0 || _emotionIndex >= _allEmotionsStretch.Count) return;
|
||||
|
||||
var beat = cond.songPositionInBeatsAsDouble;
|
||||
|
||||
var e = _allEmotionsStretch[_emotionIndex];
|
||||
|
||||
if (beat > e.beat + e.length)
|
||||
{
|
||||
_emotionIndex++;
|
||||
_lastEmotion = (EmotionStretchType)_allEmotionsStretch[_emotionIndex - 1]["type"];
|
||||
crying = _lastEmotion == EmotionStretchType.StartCrying;
|
||||
_emotionCancelled = false;
|
||||
UpdateEmotions();
|
||||
return;
|
||||
}
|
||||
|
||||
if (beat >= e.beat && beat < e.beat + e.length && !_emotionCancelled)
|
||||
{
|
||||
_lastEmotion = (EmotionStretchType)e["type"];
|
||||
crying = _lastEmotion == EmotionStretchType.StartCrying;
|
||||
float normalizedBeat = cond.GetPositionFromBeat(e.beat, e.length);
|
||||
|
||||
string animName = (EmotionStretchType)e["type"] switch
|
||||
{
|
||||
EmotionStretchType.LookUp => "OpenEyes",
|
||||
EmotionStretchType.Smile => "Smile",
|
||||
EmotionStretchType.StartCrying => "Sad",
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
headAndBodyAnim.DoNormalizedAnimation(animName, normalizedBeat);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEmotions(double beat)
|
||||
{
|
||||
_allEmotionsStretch = EventCaller.GetAllInGameManagerList("blueBear", new string[] { "stretchEmotion" });
|
||||
if (_allEmotionsStretch.Count == 0) return;
|
||||
UpdateEmotions();
|
||||
var allEmosBeforeBeat = EventCaller.GetAllInGameManagerList("blueBear", new string[] { "stretchEmotion" }).FindAll(x => x.beat < beat);
|
||||
|
||||
if ((EmotionStretchType)allEmosBeforeBeat[^1]["type"] == EmotionStretchType.StartCrying)
|
||||
{
|
||||
headAndBodyAnim.DoScaledAnimationAsync("CryIdle", 0.5f);
|
||||
}
|
||||
else if ((EmotionStretchType)allEmosBeforeBeat[^1]["type"] == EmotionStretchType.Smile)
|
||||
{
|
||||
headAndBodyAnim.DoScaledAnimationAsync("SmileIdle", 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPlay(double beat)
|
||||
{
|
||||
HandleTreatsOnStart(beat);
|
||||
HandleEmotions(beat);
|
||||
}
|
||||
|
||||
public override void OnGameSwitch(double beat)
|
||||
{
|
||||
HandleTreatsOnStart(beat);
|
||||
HandleEmotions(beat);
|
||||
}
|
||||
|
||||
private void HandleTreatsOnStart(double gameswitchBeat)
|
||||
@ -302,18 +396,19 @@ namespace HeavenStudio.Games
|
||||
|
||||
public void Wind()
|
||||
{
|
||||
windAnim.Play("Wind", 0, 0);
|
||||
windAnim.DoScaledAnimationAsync("Wind", 0.5f);
|
||||
}
|
||||
|
||||
public void Bite(bool left)
|
||||
{
|
||||
_emotionCancelled = true;
|
||||
if (crying)
|
||||
{
|
||||
headAndBodyAnim.Play(left ? "CryBiteL" : "CryBiteR", 0, 0);
|
||||
headAndBodyAnim.DoScaledAnimationAsync(left ? "CryBiteL" : "CryBiteR", 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
headAndBodyAnim.Play(left ? "BiteL" : "BiteR", 0, 0);
|
||||
headAndBodyAnim.DoScaledAnimationAsync(left ? "BiteL" : "BiteR", 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,58 +453,31 @@ namespace HeavenStudio.Games
|
||||
if (noDonutSquash && noCakeSquash)
|
||||
{
|
||||
squashing = false;
|
||||
bagsAnim.Play("Idle", 0, 0);
|
||||
bagsAnim.DoScaledAnimationAsync("Idle", 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEmotion(double beat, float length, int emotion)
|
||||
public void SetEmotion(int emotion)
|
||||
{
|
||||
_emotionCancelled = true;
|
||||
switch (emotion)
|
||||
{
|
||||
case (int)EmotionType.Neutral:
|
||||
if (emotionAnimName == "Smile")
|
||||
{
|
||||
headAndBodyAnim.Play("StopSmile", 0, 0);
|
||||
emotionAnimName = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
headAndBodyAnim.Play("Idle", 0, 0);
|
||||
}
|
||||
//check if smiling then play "StopSmile"
|
||||
headAndBodyAnim.DoScaledAnimationAsync("Idle", 0.5f);
|
||||
crying = false;
|
||||
break;
|
||||
case (int)EmotionType.ClosedEyes:
|
||||
headAndBodyAnim.Play("EyesClosed", 0, 0);
|
||||
headAndBodyAnim.DoScaledAnimationAsync("EyesClosed", 0.5f);
|
||||
crying = false;
|
||||
break;
|
||||
case (int)EmotionType.LookUp:
|
||||
emotionStartBeat = beat;
|
||||
emotionLength = length;
|
||||
emotionAnimName = "OpenEyes";
|
||||
headAndBodyAnim.Play(emotionAnimName, 0, 0);
|
||||
crying = false;
|
||||
break;
|
||||
case (int)EmotionType.Smile:
|
||||
emotionStartBeat = beat;
|
||||
emotionLength = length;
|
||||
emotionAnimName = "Smile";
|
||||
headAndBodyAnim.Play(emotionAnimName, 0, 0);
|
||||
crying = false;
|
||||
break;
|
||||
case (int)EmotionType.Sad:
|
||||
emotionStartBeat = beat;
|
||||
emotionLength = length;
|
||||
emotionAnimName = "Sad";
|
||||
headAndBodyAnim.Play(emotionAnimName, 0, 0);
|
||||
crying = true;
|
||||
break;
|
||||
case (int)EmotionType.InstaSad:
|
||||
headAndBodyAnim.Play("CryIdle", 0, 0);
|
||||
case (int)EmotionType.Cry:
|
||||
headAndBodyAnim.DoScaledAnimationAsync("CryIdle", 0.5f);
|
||||
crying = true;
|
||||
break;
|
||||
case (int)EmotionType.Sigh:
|
||||
headAndBodyAnim.Play("Sigh", 0, 0);
|
||||
headAndBodyAnim.DoScaledAnimationAsync("Sigh", 0.5f);
|
||||
crying = false;
|
||||
break;
|
||||
default:
|
||||
@ -424,7 +492,6 @@ namespace HeavenStudio.Games
|
||||
|
||||
var treatComp = newTreat.GetComponent<Treat>();
|
||||
treatComp.startBeat = beat;
|
||||
treatComp.curve = isCake ? cakeCurve : donutCurve;
|
||||
|
||||
newTreat.SetActive(true);
|
||||
|
||||
@ -439,17 +506,17 @@ namespace HeavenStudio.Games
|
||||
public void SquashBag(bool isCake)
|
||||
{
|
||||
squashing = true;
|
||||
bagsAnim.Play("Squashing", 0, 0);
|
||||
bagsAnim.DoScaledAnimationAsync("Squashing", 0.5f);
|
||||
|
||||
individualBagHolder.SetActive(true);
|
||||
|
||||
if (isCake)
|
||||
{
|
||||
cakeBagAnim.Play("CakeSquash", 0, 0);
|
||||
cakeBagAnim.DoScaledAnimationAsync("CakeSquash", 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
donutBagAnim.Play("DonutSquash", 0, 0);
|
||||
donutBagAnim.DoScaledAnimationAsync("DonutSquash", 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,18 @@ using HeavenStudio.Util;
|
||||
|
||||
namespace HeavenStudio.Games.Scripts_BlueBear
|
||||
{
|
||||
public class Treat : MonoBehaviour
|
||||
public class Treat : SuperCurveObject
|
||||
{
|
||||
const float rotSpeed = 360f;
|
||||
const float barelyDistX = 1.5f;
|
||||
const float barelyDistY = -6f;
|
||||
const float barelyHeight = 4f;
|
||||
const float rotSpeed = 360f * 3;
|
||||
|
||||
public bool isCake;
|
||||
public double startBeat;
|
||||
|
||||
bool flying = true;
|
||||
double flyBeats;
|
||||
|
||||
[NonSerialized] public BezierCurve3D curve;
|
||||
private Path path;
|
||||
|
||||
private BlueBear game;
|
||||
|
||||
@ -30,33 +31,34 @@ namespace HeavenStudio.Games.Scripts_BlueBear
|
||||
private void Start()
|
||||
{
|
||||
flyBeats = isCake ? 3f : 2f;
|
||||
Path pathToCopy = isCake ? game.GetPath("Cake") : game.GetPath("Donut");
|
||||
path = new();
|
||||
path.positions = new PathPos[2];
|
||||
path.positions[0].pos = pathToCopy.positions[0].pos;
|
||||
path.positions[0].duration = pathToCopy.positions[0].duration;
|
||||
path.positions[0].height = pathToCopy.positions[0].height;
|
||||
path.positions[1].pos = pathToCopy.positions[1].pos;
|
||||
game.ScheduleInput(startBeat, flyBeats, isCake ? BlueBear.InputAction_Left : BlueBear.InputAction_Right, Just, Out, Out);
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (flying)
|
||||
var cond = Conductor.instance;
|
||||
transform.localPosition = GetPathPositionFromBeat(path, cond.songPositionInBeatsAsDouble, startBeat);
|
||||
|
||||
float flyPos = cond.GetPositionFromBeat(startBeat, flyBeats);
|
||||
if (flyPos > 2f)
|
||||
{
|
||||
var cond = Conductor.instance;
|
||||
|
||||
float flyPos = cond.GetPositionFromBeat(startBeat, flyBeats);
|
||||
flyPos *= isCake ? 0.75f : 0.6f;
|
||||
transform.position = curve.GetPoint(flyPos);
|
||||
|
||||
if (flyPos > 1f)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
float rot = isCake ? rotSpeed : -rotSpeed;
|
||||
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (rot * Time.deltaTime));
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
float rot = isCake ? rotSpeed : -rotSpeed;
|
||||
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (rot * Time.deltaTime * cond.pitchedSecPerBeat));
|
||||
}
|
||||
void EatFood()
|
||||
{
|
||||
flying = false;
|
||||
|
||||
if (isCake)
|
||||
{
|
||||
SoundByte.PlayOneShotGame("blueBear/chompCake");
|
||||
@ -71,21 +73,28 @@ namespace HeavenStudio.Games.Scripts_BlueBear
|
||||
|
||||
SpawnCrumbs();
|
||||
|
||||
GameObject.Destroy(gameObject);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void Just(PlayerActionEvent caller, float state)
|
||||
{
|
||||
if (state >= 1f || state <= -1f)
|
||||
{ //todo: proper near miss feedback
|
||||
{
|
||||
SoundByte.PlayOneShot("miss");
|
||||
if (isCake)
|
||||
{
|
||||
game.headAndBodyAnim.Play("BiteL", 0, 0);
|
||||
game.headAndBodyAnim.DoScaledAnimationAsync("BiteL", 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
game.headAndBodyAnim.Play("BiteR", 0, 0);
|
||||
game.headAndBodyAnim.DoScaledAnimationAsync("BiteR", 0, 0);
|
||||
}
|
||||
path.positions[0].pos = transform.localPosition;
|
||||
path.positions[0].height = barelyHeight;
|
||||
path.positions[0].duration = 1;
|
||||
path.positions[1].pos = new Vector3(path.positions[0].pos.x + (isCake ? -barelyDistX : barelyDistX), path.positions[0].pos.y + barelyDistY);
|
||||
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
|
||||
Update();
|
||||
return;
|
||||
}
|
||||
EatFood();
|
||||
@ -104,7 +113,7 @@ namespace HeavenStudio.Games.Scripts_BlueBear
|
||||
var newGradient = new ParticleSystem.MinMaxGradient(isCake ? game.cakeGradient : game.donutGradient);
|
||||
newGradient.mode = ParticleSystemGradientMode.RandomColor;
|
||||
main.startColor = newGradient;
|
||||
ps.Play();
|
||||
ps.PlayScaledAsync(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,11 @@ namespace HeavenStudio.Util
|
||||
anim.speed = (1f / Conductor.instance.pitchedSecPerBeat) * timeScale;
|
||||
}
|
||||
|
||||
public static void SetScaledAnimationSpeed(this Animator anim, float timeScale = 0.5f)
|
||||
{
|
||||
anim.speed = (1f / Conductor.instance.pitchedSecPerBeat) * timeScale;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays animation on animator, at default speed
|
||||
/// this is the least nessecary function here lol
|
||||
|
Reference in New Issue
Block a user