Basketball Girls (#858)

* wip

* Secretly fixed bugs in unrelated areas

* wip2

* wip3

* camera

* OK
This commit is contained in:
フマジメ
2024-04-12 10:40:54 +09:00
committed by GitHub
parent 39039b447c
commit 649eafa035
97 changed files with 32609 additions and 2 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7f5754c28d2ba9441814255c52bf93e5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,104 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_BasketballGirls
{
public class Ball : MonoBehaviour
{
public double startBeat;
[SerializeField] private Animator ballAnim;
private BasketballGirls game;
public void Init()
{
game = BasketballGirls.instance;
ballAnim.DoScaledAnimationAsync("prepare", 0.5f);
game.ScheduleInput(startBeat, 1, BasketballGirls.InputAction_Catch, JustCatch, MissCatch, Empty);
}
void JustCatch(PlayerActionEvent caller, float state)
{
game.girlRightNoBopIntervals.Add(new Interval(startBeat + 1, startBeat + 2));
if (state <= -1f || state >= 1f)
{
SoundByte.PlayOneShotGame("basketballGirls/catch");
MultiSound.Play(
new MultiSound.Sound[] {
new MultiSound.Sound("basketballGirls/throw", startBeat + 1.5),
new MultiSound.Sound("basketballGirls/6", startBeat + 2),
}
);
ballAnim.DoScaledAnimationAsync("catch", 0.5f);
game.girlLeftAnim.DoScaledAnimationAsync("pass", 0.5f);
game.girlRightAnim.DoScaledAnimationAsync("catch", 0.5f);
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(startBeat + 1.5, delegate {
ballAnim.DoScaledAnimationAsync("shootBarely", 0.5f);
game.girlRightAnim.DoScaledAnimationAsync("shoot", 0.5f);
}),
new BeatAction.Action(startBeat + 2, delegate {
ballAnim.DoScaledAnimationAsync("barely", 0.5f);
game.goalAnim.DoScaledAnimationAsync("barely", 0.5f);
}),
new BeatAction.Action(startBeat + 3, delegate {
Destroy(gameObject);
}),
});
return;
}
SoundByte.PlayOneShotGame("basketballGirls/catch");
MultiSound.Play(
new MultiSound.Sound[] {
new MultiSound.Sound("basketballGirls/throw", startBeat + 1.5),
new MultiSound.Sound("basketballGirls/dunk", startBeat + 2),
new MultiSound.Sound("basketballGirls/ok1", startBeat + 2.5),
new MultiSound.Sound("basketballGirls/ok2", startBeat + 3),
}
);
ballAnim.DoScaledAnimationAsync("catch", 0.5f);
if (!game.girlLeftNoBopIntervals.Any(x => x.Start == (startBeat + 1))) game.girlLeftAnim.DoScaledAnimationAsync("pass", 0.5f);
game.girlRightAnim.DoScaledAnimationAsync("catch", 0.5f);
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(startBeat + 1.5, delegate {
ballAnim.DoScaledAnimationAsync("shootJust", 0.5f);
game.girlRightAnim.DoScaledAnimationAsync("shoot", 0.5f);
}),
new BeatAction.Action(startBeat + 2, delegate {
ballAnim.DoScaledAnimationAsync("just", 0.5f);
game.goalAnim.DoScaledAnimationAsync("just", 0.5f);
}),
new BeatAction.Action(startBeat + 3, delegate {
Destroy(gameObject);
}),
});
}
void MissCatch(PlayerActionEvent caller)
{
SoundByte.PlayOneShotGame("basketballGirls/" + UnityEngine.Random.Range(1,2).ToString());
ballAnim.DoScaledAnimationAsync("hit", 0.5f);
game.girlLeftAnim.DoScaledAnimationAsync("shock", 0.5f);
game.girlRightAnim.DoScaledAnimationAsync("hit", 0.5f);
game.girlRightNoBopIntervals.Add(new Interval(startBeat + 1, startBeat + 2));
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(startBeat + 3, delegate {
Destroy(gameObject);
}),
});
}
void Empty(PlayerActionEvent caller) { }
}
}

View File

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

View File

@ -0,0 +1,272 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
using Jukebox;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class RvlBasketLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
return new Minigame("basketballGirls", "Basketball Girls", "ffffff", false, false, new List<GameAction>()
{
new("bop", "Bop")
{
function = delegate { var e = eventCaller.currentEntity; BasketballGirls.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("ball", "Ball")
{
function = delegate {var e = eventCaller.currentEntity; BasketballGirls.instance.SpawnBall(e.beat); },
defaultLength = 2f,
},
new GameAction("zoom", "Zoom In/Out")
{
function = delegate { var e = eventCaller.currentEntity; BasketballGirls.instance.ToggleZoom(e.beat, e.length, e["ease"], e["toggle"]);},
defaultLength = 4f,
resizable = true,
parameters = new List<Param>()
{
new Param("toggle", true, "Zoom In", "Toggle if the camera should zoom in."),
new Param("ease", Util.EasingFunction.Ease.Linear, "Ease", "Set the easing of the action."),
}
},
new GameAction("background appearance", "Background Appearance")
{
function = delegate {
var e = eventCaller.currentEntity;
BasketballGirls.instance.BackgroundColorSet(e.beat, e.length, e["colorBGStart"], e["colorBGEnd"], e["ease"]);
},
defaultLength = 0.5f,
resizable = true,
parameters = new List<Param>()
{
new Param("colorBGStart", new Color(1f, 0.937f, 0.224f), "Start BG Color", "Set the color at the start of the event."),
new Param("colorBGEnd", new Color(1f, 0.937f, 0.224f), "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 List<string>() { "rvl", "normal" },
"rvlbasket", "en",
new List<string>() {},
chronologicalSortKey: 105
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_BasketballGirls;
public class BasketballGirls : Minigame
{
public Transform baseBall;
public Animator girlLeftAnim, girlRightAnim;
[NonSerialized] public List<Interval> girlLeftNoBopIntervals = new(),
girlRightNoBopIntervals = new();
public Animator goalAnim;
public Transform[] CameraPosition;
double cameraMoveBeat = double.MaxValue;
double cameraMoveLength;
Util.EasingFunction.Ease cameraMoveEase;
bool cameraMoveIn;
[SerializeField] private SpriteRenderer BGPlane;
private ColorEase bgColorEase = new(new Color(1f, 0.937f, 0.224f));
public static BasketballGirls instance;
const int IAAltDownCat = IAMAXCAT;
protected static bool IA_BatonAltPress(out double dt)
{
return PlayerInput.GetSqueezeDown(out dt);
}
public static PlayerInput.InputAction InputAction_Catch =
new("RvlBasketCatch", new int[] { IAPressCat, IAPressCat, IAAltDownCat },
IA_PadBasicPress, IA_TouchBasicPress, IA_BatonAltPress);
private void Awake()
{
instance = this;
SetupBopRegion("basketballGirls", "bop", "auto");
HandleBops();
}
public override void OnLateBeatPulse(double beat)
{
if (BeatIsInBopRegion(beat)) { Bop(beat);}
}
private void Update()
{
var cond = Conductor.instance;
if (cond.isPlaying && !cond.isPaused)
{
if (PlayerInput.GetIsAction(InputAction_Catch) && !IsExpectingInputNow(InputAction_Catch))
{
if (!girlRightAnim.IsPlayingAnimationNames("blank") && !girlRightNoBopIntervals.Any(x => x.Contains(cond.songPositionInBeatsAsDouble)))
{
SoundByte.PlayOneShotGame("basketballGirls/A");
girlRightAnim.DoScaledAnimationAsync("blank", 0.5f);
}
}
UpdateCamera(cond.songPositionInBeatsAsDouble);
UpdateBackgroundColor();
}
}
private void HandleBops()
{
List<RiqEntity> events = EventCaller.GetAllInGameManagerList("basketballGirls", new string[] { "ball" });
foreach (var e in events)
{
girlLeftNoBopIntervals.Add(new Interval(e.beat, e.beat + 2));
}
}
public void ToggleBop(double beat, float length, bool bopOrNah, bool autoBop)
{
if (bopOrNah)
{
for (int i = 0; i < length; i++)
{
var currentBeat = beat + i;
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(currentBeat, delegate { Bop(currentBeat);})
});
}
}
}
private void Bop(double beat)
{
if (!girlLeftNoBopIntervals.Any(x => x.Contains(beat)))
{
MultiSound.Play(
new MultiSound.Sound[] {
new MultiSound.Sound("basketballGirls/dribble" + UnityEngine.Random.Range(1,3).ToString(), beat),
new MultiSound.Sound("basketballGirls/dribbleEcho" + UnityEngine.Random.Range(1,4).ToString(), beat + 0.5),
}
);
girlLeftAnim.DoScaledAnimationAsync("dribble", 0.5f);
}
if (!girlRightNoBopIntervals.Any(x => x.Contains(beat)))
{
girlRightAnim.DoScaledAnimationAsync("bop", 0.5f);
}
}
public void SpawnBall(double beat)
{
var newBall = Instantiate(baseBall, transform).GetComponent<Ball>();
newBall.startBeat = beat;
SoundByte.PlayOneShotGame("basketballGirls/voice");
girlLeftAnim.DoScaledAnimationAsync("prepare", 0.5f);
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate {
newBall.gameObject.SetActive(true);
newBall.Init();
}),
new BeatAction.Action(beat+2, delegate {
}),
});
}
public void ToggleZoom(double beat, double length, int ease, bool toggle)
{
cameraMoveBeat = beat;
cameraMoveLength = length;
cameraMoveEase = (Util.EasingFunction.Ease)ease;
cameraMoveIn = toggle;
}
private void UpdateCamera(double beat)
{
Vector3 cameraPosition;
if (beat >= cameraMoveBeat)
{
Util.EasingFunction.Function func = Util.EasingFunction.GetEasingFunction(cameraMoveEase);
float prog = conductor.GetPositionFromBeat(cameraMoveBeat, cameraMoveLength, true);
prog = Mathf.Clamp01(prog);
if (cameraMoveIn)
{
cameraPosition.x = func(CameraPosition[0].position.x, CameraPosition[1].position.x, prog);
cameraPosition.y = func(CameraPosition[0].position.y, CameraPosition[1].position.y, prog);
cameraPosition.z = func(CameraPosition[0].position.z, CameraPosition[1].position.z, prog);
}
else
{
cameraPosition.x = func(CameraPosition[1].position.x, CameraPosition[0].position.x, prog);
cameraPosition.y = func(CameraPosition[1].position.y, CameraPosition[0].position.y, prog);
cameraPosition.z = func(CameraPosition[1].position.z, CameraPosition[0].position.z, prog);
}
}
else
{
if (cameraMoveIn) cameraPosition = CameraPosition[1].position;
else cameraPosition = CameraPosition[0].position;
}
GameCamera.AdditionalPosition = cameraPosition - GameCamera.defaultPosition;
}
public void BackgroundColorSet(double beat, float length, Color BGStart, Color BGEnd, int colorEaseSet)
{
bgColorEase = new(beat, length, BGStart, BGEnd, colorEaseSet);
UpdateBackgroundColor();
}
private void UpdateBackgroundColor()
{
BGPlane.color = bgColorEase.GetColor();
}
}
}
// How should Bop's on/off be managed?
namespace HeavenStudio.Games.Scripts_BasketballGirls
{
public class Interval
{
private readonly double _start;
private readonly double _end;
private readonly Func<double, double, bool> _leftComparer;
private readonly Func<double, double, bool> _rightComparer;
public double Start => _start;
public double End => _end;
public Interval(double start, double end, bool isLeftClosed = true, bool isRightClosed = false)
{
_start = start;
_end = end;
_leftComparer = isLeftClosed ? (value, boundary) => value >= boundary : (value, boundary) => value > boundary;
_rightComparer = isRightClosed ? (value, boundary) => value <= boundary : (value, boundary) => value < boundary;
}
public bool Contains(double value) => _leftComparer(value, _start) && _rightComparer(value, _end);
}
}

View File

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

View File

@ -111,6 +111,7 @@ namespace HeavenStudio.Games
void JustHold(PlayerActionEvent caller, float state)
{
var currentBeat = caller.timer + caller.startBeat;
isJust = false;
ScheduleInput(currentBeat, 1, InputAction_FlickRelease, JustJump, MissJump, Empty, CanJump);
if (state >= 1f || state <= -1f)
@ -132,6 +133,7 @@ namespace HeavenStudio.Games
void JustJump(PlayerActionEvent caller, float state)
{
var currentBeat = caller.timer + caller.startBeat;
isJust = true;
if (state >= 1f || state <= -1f)
{
@ -147,7 +149,8 @@ namespace HeavenStudio.Games
JumpMissAnim(caller.timer + caller.startBeat);
}
bool CanJump() { return isHold && !isGone;}
bool isJust = false; // not fundamental solution
bool CanJump() { return isHold && !isGone || isJust;}
void Empty(PlayerActionEvent caller) { }