spawning logic overhaul

also fixed issue where sweets would be hittable if a nail could be instead
cues at full speed for testing need to halve the speed of everything later
This commit is contained in:
minenice55 2024-03-07 01:58:51 -05:00
parent b780c112bd
commit 8d5609a065
5 changed files with 370 additions and 233 deletions

View file

@ -634,6 +634,50 @@ MonoBehaviour:
m_EditorClassIdentifier:
SoundSequences: []
scheduledInputs: []
puddingPattern:
- beat: 0
type: 2
- beat: 0.5
type: 0
- beat: 1
type: 8
cherryPattern:
- beat: 0
type: 2
- beat: 0.5
type: 0
- beat: 1
type: 0
- beat: 1.5
type: 0
- beat: 2
type: 8
cakePattern:
- beat: 0
type: 2
- beat: 0.5
type: 0
- beat: 1
type: 3
- beat: 1.25
type: 0
- beat: 1.75
type: 0
- beat: 2
type: 8
cakeLongPattern:
- beat: 0
type: 2
- beat: 0.5
type: 0
- beat: 1
type: 9
- beat: 1.5
type: 1
- beat: 2
type: 8
scrollMetresPerBeat: -4.5
boardWidth: 19.2
baseNail: {fileID: 7504610799131467556}
baseLongNail: {fileID: 4122843866948130824}
baseSweet: {fileID: 7846700753925185796}
@ -1168,6 +1212,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
targetBeat: 0
targetX: 0
metresPerSecond: 0
nailAnim: {fileID: 3330987451715863783}
--- !u!1 &4314335590168154470
GameObject:
@ -1899,6 +1945,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
targetBeat: 0
targetX: 0
metresPerSecond: 0
nailAnim: {fileID: 845294389825628466}
--- !u!1 &7846700753925185796
GameObject:
@ -1946,6 +1994,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
targetBeat: 0
targetX: 0
metresPerSecond: 0
sweetType: 0
sweetAnim: {fileID: 4107796134930477793}
--- !u!1 &7940810347463623349
@ -2174,7 +2224,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8791741134951954224}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 2.635, y: 0, z: 0}
m_LocalPosition: {x: 1.9, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []

View file

@ -13,6 +13,8 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
public class LongNail : MonoBehaviour
{
public double targetBeat;
public float targetX;
public float metresPerSecond;
public Animator nailAnim;
private NailCarpenter game;
@ -20,13 +22,14 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
public void Init()
{
game = NailCarpenter.instance;
game.ScheduleInput(targetBeat, 1f, NailCarpenter.InputAction_AltStart, HammmerJust, HammmerMiss, Empty);
game.ScheduleInput(targetBeat, 0, NailCarpenter.InputAction_AltPress, HammmerJust, HammmerMiss, null);
// wrongInput
if (PlayerInput.CurrentControlStyle != InputController.ControlStyles.Touch)
{
game.ScheduleUserInput(targetBeat, 1f, NailCarpenter.InputAction_RegPress, weakHammmerJust, Empty, Empty);
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_RegPress, WeakHammmerJust, null, null);
}
Update();
}
private void HammmerJust(PlayerActionEvent caller, float state)
@ -44,7 +47,7 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
game.EyeAnim.DoScaledAnimationAsync("eyeSmile", 0.25f);
}
private void weakHammmerJust(PlayerActionEvent caller, float state)
private void WeakHammmerJust(PlayerActionEvent caller, float state)
{
game.ScoreMiss();
game.Carpenter.DoScaledAnimationAsync("carpenterHit", 0.25f);
@ -64,8 +67,6 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
game.EyeAnim.DoScaledAnimationAsync("eyeBlink", 0.25f);
}
private void Empty(PlayerActionEvent caller) { }
private void Update()
{
var cond = Conductor.instance;
@ -73,7 +74,10 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
if (cond.isPlaying && !cond.isPaused)
{
double beat = cond.songPositionInBeats;
if (targetBeat != double.MinValue)
Vector3 pos = transform.position;
pos.x = targetX + (float)((beat - targetBeat) * metresPerSecond);
transform.position = pos;
if (targetBeat != double.MinValue)
{
if (beat >= targetBeat + 9) Destroy(gameObject);
}

View file

@ -13,6 +13,8 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
public class Nail : MonoBehaviour
{
public double targetBeat;
public float targetX;
public float metresPerSecond;
public Animator nailAnim;
private NailCarpenter game;
@ -20,13 +22,14 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
public void Init()
{
game = NailCarpenter.instance;
game.ScheduleInput(targetBeat, 0, NailCarpenter.InputAction_RegPress, HammmerJust, HammmerMiss, Empty);
game.ScheduleInput(targetBeat, 0, NailCarpenter.InputAction_RegPress, HammmerJust, HammmerMiss, null);
//wrong input
if (PlayerInput.CurrentControlStyle != InputController.ControlStyles.Touch)
{
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_AltStart, strongHammmerJust, Empty, Empty);
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_AltPress, strongHammmerJust, null, null);
}
Update();
}
private void HammmerJust(PlayerActionEvent caller, float state)
@ -62,8 +65,6 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
game.EyeAnim.DoScaledAnimationAsync("eyeBlink", 0.25f);
}
private void Empty(PlayerActionEvent caller) { }
private void Update()
{
var cond = Conductor.instance;
@ -71,7 +72,10 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
if (cond.isPlaying && !cond.isPaused)
{
double beat = cond.songPositionInBeats;
if (targetBeat != double.MinValue)
Vector3 pos = transform.position;
pos.x = targetX + (float)((beat - targetBeat) * metresPerSecond);
transform.position = pos;
if (targetBeat != double.MinValue)
{
if (beat >= targetBeat + 9) Destroy(gameObject);
}

View file

@ -16,33 +16,29 @@ namespace HeavenStudio.Games.Loaders
{
new GameAction("puddingNail", "Pudding Nail")
{
function = delegate {NailCarpenter.instance.PlaySound();},
defaultLength = 8f,
resizable = true
},
new GameAction("cherryNail", "Cherry Nail")
{
function = delegate {NailCarpenter.instance.PlaySound();},
defaultLength = 4f,
resizable = true
},
new GameAction("cakeNail", "Cake Nail")
{
function = delegate {NailCarpenter.instance.PlaySound();},
defaultLength = 4f,
resizable = true
},
new GameAction("cakeLongNail", "Cake Long Nail")
{
function = delegate {NailCarpenter.instance.PlaySound();},
defaultLength = 4f,
resizable = true
},
new GameAction("slideFusuma", "Slide Shoji")
{
function = delegate {
var e = eventCaller.currentEntity;
NailCarpenter.instance.SlideShoji(e.beat, e.length, e["fillRatio"], e["ease"], e["mute"]);
var e = eventCaller.currentEntity;
NailCarpenter.instance.SlideShoji(e.beat, e.length, e["fillRatio"], e["ease"], e["mute"]);
},
defaultLength = 1f,
resizable = true,
@ -53,7 +49,7 @@ namespace HeavenStudio.Games.Loaders
new Param("mute", false, "Mute", "Toggle if the cue should be muted.")
}
},
},
new List<string>() { "pco", "normal" },
"pconail", "en",
@ -65,10 +61,59 @@ namespace HeavenStudio.Games.Loaders
namespace HeavenStudio.Games
{
using System.Diagnostics;
using System.Linq;
using Scripts_NailCarpenter;
public class NailCarpenter : Minigame
{
const double PATTERN_SEEK_TIME = 8.0;
[Serializable]
public struct ObjectPatternItem
{
public double beat;
public ObjectType type;
}
public enum ObjectType
{
Nail,
LongNail,
Sweet,
ForceCherry,
ForcePudding,
ForceCherryPudding,
ForceShortCake,
ForceLayerCake,
None,
LongCharge
}
struct ScheduledPattern
{
public double beat;
public double length;
public PatternType type;
}
enum PatternType
{
Pudding,
Cherry,
Cake,
CakeLong,
None
}
[SerializeField] ObjectPatternItem[] puddingPattern;
[SerializeField] ObjectPatternItem[] cherryPattern;
[SerializeField] ObjectPatternItem[] cakePattern;
[SerializeField] ObjectPatternItem[] cakeLongPattern;
[SerializeField] float scrollMetresPerBeat = 4f;
[SerializeField] float boardWidth = 19.2f;
public GameObject baseNail;
public GameObject baseLongNail;
public GameObject baseSweet;
@ -81,15 +126,12 @@ namespace HeavenStudio.Games
public Transform nailHolder;
public Transform boardTrans;
public Transform shojiTrans;
const float nailDistance = -4f;
const float boardWidth = 19.2f;
float scrollRate => nailDistance / (Conductor.instance.pitchedSecPerBeat * 2f);
private bool missed;
private bool hasSlurped;
const int IAAltDownCat = IAMAXCAT;
const int IAAltUpCat = IAMAXCAT + 1;
const int IASweetsCat = IAMAXCAT + 1;
protected static bool IA_PadAltPress(out double dt)
{
@ -102,37 +144,43 @@ namespace HeavenStudio.Games
protected static bool IA_TouchRegularPress(out double dt)
{
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Tap, out dt);
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Tap, out dt)
&& !instance.IsExpectingInputNow(InputAction_AltPress);
}
protected static bool IA_TouchAltPress(out double dt)
{
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Tap, out dt)
&& instance.IsExpectingInputNow(InputAction_AltStart)
&& instance.IsExpectingInputNow(InputAction_AltPress)
&& !instance.IsExpectingInputNow(InputAction_RegPress);
}
protected static bool IA_PadAltRelease(out double dt)
protected static bool IA_PadSweetsCheck(out double dt)
{
return PlayerInput.GetPadUp(InputController.ActionsPad.South, out dt);
return (PlayerInput.GetPadDown(InputController.ActionsPad.South, out dt)
|| PlayerInput.GetPadDown(InputController.ActionsPad.East, out dt))
&& !(instance.IsExpectingInputNow(InputAction_RegPress) || instance.IsExpectingInputNow(InputAction_AltPress));
}
protected static bool IA_BatonAltRelease(out double dt)
protected static bool IA_BatonSweetsCheck(out double dt)
{
return PlayerInput.GetSqueezeUp(out dt);
return (PlayerInput.GetBatonDown(InputController.ActionsBaton.Face, out dt)
|| PlayerInput.GetSqueezeDown(out dt))
&& !(instance.IsExpectingInputNow(InputAction_RegPress) || instance.IsExpectingInputNow(InputAction_AltPress));
}
protected static bool IA_TouchSweetsCheck(out double dt)
{
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Tap, out dt)
&& !(instance.IsExpectingInputNow(InputAction_RegPress) || instance.IsExpectingInputNow(InputAction_AltPress));
}
public static PlayerInput.InputAction InputAction_RegPress =
new("PcoNailRegStart", new int[] { IAPressCat, IAPressCat, IAPressCat },
new("PcoNailRegStart", new int[] { IAPressCat, IAPressCat, IAPressCat },
IA_PadBasicPress, IA_TouchRegularPress, IA_BatonBasicPress);
public static PlayerInput.InputAction InputAction_AltStart =
public static PlayerInput.InputAction InputAction_AltPress =
new("PcoNailAltStart", new int[] { IAAltDownCat, IAAltDownCat, IAAltDownCat },
IA_PadAltPress, IA_TouchAltPress, IA_BatonAltPress);
public static PlayerInput.InputAction InputAction_AltFinish =
new("PcoNailAltFinish", new int[] { IAAltUpCat, IAFlickCat, IAAltUpCat },
IA_PadAltRelease, IA_TouchFlick, IA_BatonAltRelease);
public static PlayerInput.InputAction InputAction_TouchRelease =
new("PcoNailTouchRelease", new int[] { IAEmptyCat, IAReleaseCat, IAEmptyCat },
IA_Empty, IA_TouchBasicRelease, IA_Empty);
public static PlayerInput.InputAction InputAction_SweetsHit =
new("PcoNailSweetsHit", new int[] { IASweetsCat, IASweetsCat, IASweetsCat },
IA_PadSweetsCheck, IA_TouchSweetsCheck, IA_BatonSweetsCheck);
public static NailCarpenter instance;
@ -142,185 +190,89 @@ namespace HeavenStudio.Games
instance = this;
}
List<ScheduledPattern> scheduledPatterns = new List<ScheduledPattern>();
double patternStartBeat, gameStartBeat;
PatternType patternType, lastPatternType;
int patternIndex;
double slideBeat = double.MaxValue;
double slideLength;
double cachedPatternLengthPudding, cachedPatternLengthCherry, cachedPatternLengthCake, cachedPatternLengthCakeLong;
Util.EasingFunction.Ease slideEase;
float slideRatioLast = 0, slideRatioNext = 0;
void Start()
{
if (!conductor.isPlaying) return;
UpdatePatterns();
}
void Update()
{
var cond = Conductor.instance;
var currentBeat = cond.songPositionInBeatsAsDouble;
var currentBeat = conductor.songPositionInBeatsAsDouble;
if (!cond.isPlaying) return;
// Debug.Log(newBeat);
if (!conductor.isPlaying) return;
if (PlayerInput.GetIsAction(InputAction_RegPress) && !IsExpectingInputNow(InputAction_RegPress))
{
ScoreMiss();
SoundByte.PlayOneShot("miss");
Carpenter.DoScaledAnimationAsync("carpenterHit", 0.25f);
hasSlurped = false;
// ScoreMiss();
}
if (PlayerInput.GetIsAction(InputAction_AltStart) && !IsExpectingInputNow(InputAction_AltStart))
if (PlayerInput.GetIsAction(InputAction_AltPress) && !IsExpectingInputNow(InputAction_AltPress))
{
ScoreMiss();
SoundByte.PlayOneShot("miss");
Carpenter.DoScaledAnimationAsync("carpenterHit", 0.25f);
hasSlurped = false;
// ScoreMiss();
}
// Object scroll.
var scrollPos = scrollingHolder.localPosition;
var newScrollX = scrollPos.x + (scrollRate * Time.deltaTime);
scrollingHolder.localPosition = new Vector3(newScrollX, scrollPos.y, scrollPos.z);
// Board scroll.
var boardPos = boardTrans.localPosition;
var newBoardX = boardPos.x + (scrollRate * Time.deltaTime);
var newBoardX = currentBeat * scrollMetresPerBeat;
newBoardX %= boardWidth;
boardTrans.localPosition = new Vector3(newBoardX, boardPos.y, boardPos.z);
boardTrans.localPosition = new Vector3((float)newBoardX, boardPos.y, boardPos.z);
UpdatePatterns();
UpdateShoji(currentBeat);
}
public override void OnGameSwitch(double beat)
{
double startBeat;
cachedPatternLengthPudding = puddingPattern[^1].beat;
cachedPatternLengthCherry = cherryPattern[^1].beat;
cachedPatternLengthCake = cakePattern[^1].beat;
cachedPatternLengthCakeLong = cakeLongPattern[^1].beat;
double endBeat = double.MaxValue;
var entities = GameManager.instance.Beatmap.Entities;
var entities = gameManager.Beatmap.Entities;
startBeat = beat;
gameStartBeat = beat;
patternStartBeat = gameStartBeat;
// find out when the next game switch (or remix end) happens
RiqEntity firstEnd = entities.Find(c => (c.datamodel.StartsWith("gameManager/switchGame") || c.datamodel.Equals("gameManager/end")) && c.beat > startBeat);
endBeat = firstEnd?.beat ?? double.MaxValue;
RiqEntity firstEnd = entities.Find(c => (c.datamodel.StartsWith("gameManager/switchGame") || c.datamodel.Equals("gameManager/end")) && c.beat > gameStartBeat);
endBeat = firstEnd?.beat ?? endBeat;
// Nail events.
List<RiqEntity> pudNailEvents = entities.FindAll(v => v.datamodel == "nailCarpenter/puddingNail");
List<RiqEntity> chrNailEvents = entities.FindAll(v => v.datamodel == "nailCarpenter/cherryNail");
List<RiqEntity> cakeNailEvents = entities.FindAll(v => v.datamodel == "nailCarpenter/cakeNail");
List<RiqEntity> cklNailEvents = entities.FindAll(v => v.datamodel == "nailCarpenter/cakeLongNail");
var cherryTargetBeats = new List<double>(){};
// Spawn cake and nail.
for (int i = 0; i < cakeNailEvents.Count; i++) {
var nailBeat = cakeNailEvents[i].beat;
var nailLength = cakeNailEvents[i].length;
// Only consider nailgie events that aren't past the start point.
if (startBeat <= nailBeat + nailLength) {
int nailInEvent = Mathf.CeilToInt(nailLength + 2) / 4;
for (int b = 0; b < nailInEvent; b++)
List<RiqEntity> events = entities.FindAll(v => (v.datamodel is "nailCarpenter/puddingNail" or "nailCarpenter/cherryNail" or "nailCarpenter/cakeNail" or "nailCarpenter/cakeLongNail") && v.beat >= gameStartBeat && v.beat < endBeat);
scheduledPatterns.Clear();
patternIndex = 0;
foreach (var evt in events)
{
var pattern = new ScheduledPattern
{
beat = evt.beat,
length = evt.length,
type = evt.datamodel switch
{
var targetNailBeat = nailBeat + (4f * b);
if (startBeat <= targetNailBeat && targetNailBeat < endBeat)
{
sounds.Add(new MultiSound.Sound("nailCarpenter/alarm", targetNailBeat));
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(targetNailBeat, delegate
{
EffectExclamRed.DoScaledAnimationAsync("exclamAppear", 0.25f);
})
});
SpawnSweet(targetNailBeat, startBeat,
(b==0 ? Sweet.sweetsType.ShortCake : Sweet.sweetsType.Cherry));
SpawnNail(targetNailBeat+1f, startBeat);
SpawnSweet(targetNailBeat+2f, startBeat, Sweet.sweetsType.Cherry);
SpawnNail(targetNailBeat+2.5f, startBeat);
SpawnNail(targetNailBeat+3.5f, startBeat);
}
"nailCarpenter/puddingNail" => PatternType.Pudding,
"nailCarpenter/cherryNail" => PatternType.Cherry,
"nailCarpenter/cakeNail" => PatternType.Cake,
"nailCarpenter/cakeLongNail" => PatternType.CakeLong,
_ => throw new NotImplementedException()
}
cherryTargetBeats.Add(nailBeat + 4f * nailInEvent);
}
}
// Spawn pudding and nail.
for (int i = 0; i < pudNailEvents.Count; i++) {
var nailBeat = pudNailEvents[i].beat;
var nailLength = pudNailEvents[i].length;
// Only consider nailgie events that aren't past the start point.
if (startBeat <= nailBeat + nailLength) {
int nailInEvent = Mathf.CeilToInt(nailLength)/2;
for (int b = 0; b < nailInEvent; b++)
{
var targetNailBeat = nailBeat + (2f * b);
if (startBeat <= targetNailBeat && targetNailBeat < endBeat)
{
sounds.Add(new MultiSound.Sound("nailCarpenter/one", targetNailBeat));
SpawnSweet(targetNailBeat, startBeat,
(IsInRange(cherryTargetBeats, targetNailBeat) ? Sweet.sweetsType.Cherry :
Sweet.sweetsType.Pudding));
SpawnNail(targetNailBeat+1f, startBeat);
}
}
}
}
// Spawn cherrypudding and nail.
for (int i = 0; i < chrNailEvents.Count; i++) {
var nailBeat = chrNailEvents[i].beat;
var nailLength = chrNailEvents[i].length;
// Only consider nailgie events that aren't past the start point.
if (startBeat <= nailBeat + nailLength) {
int nailInEvent = Mathf.CeilToInt(nailLength + 1f) / 4;
for (int b = 0; b < nailInEvent; b++)
{
var targetNailBeat = nailBeat + (4f * b);
if (startBeat <= targetNailBeat && targetNailBeat < endBeat)
{
sounds.Add(new MultiSound.Sound("nailCarpenter/three", targetNailBeat));
SpawnSweet(targetNailBeat, startBeat,
(IsInRange(cherryTargetBeats, targetNailBeat) ? Sweet.sweetsType.Cherry :
Sweet.sweetsType.CherryPudding));
SpawnNail(targetNailBeat+1f, startBeat);
SpawnNail(targetNailBeat+2f, startBeat);
SpawnNail(targetNailBeat+3f, startBeat);
}
}
}
}
// Spawn long nail.
for (int i = 0; i < cklNailEvents.Count; i++) {
var nailBeat = cklNailEvents[i].beat;
var nailLength = cklNailEvents[i].length;
// Only consider nailgie events that aren't past the start point.
if (startBeat <= nailBeat + nailLength) {
int nailInEvent = Mathf.CeilToInt(nailLength + 2) / 4;
for (int b = 0; b < nailInEvent; b++)
{
var targetNailBeat = nailBeat + (4f * b);
if (startBeat <= targetNailBeat && targetNailBeat < endBeat)
{
sounds.Add(new MultiSound.Sound("nailCarpenter/signal1", targetNailBeat));
sounds.Add(new MultiSound.Sound("nailCarpenter/signal2", targetNailBeat+2f));
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(targetNailBeat, delegate
{
EffectExclamBlue.DoScaledAnimationAsync("exclamAppear", 0.25f);
}),
new BeatAction.Action(targetNailBeat+1.5f, delegate
{
Carpenter.DoScaledAnimationAsync("carpenterArmUp", 0.25f);
}),
});
SpawnSweet(targetNailBeat, startBeat,
(IsInRange(cherryTargetBeats, targetNailBeat) ? Sweet.sweetsType.Cherry :
Sweet.sweetsType.LayerCake));
SpawnNail(targetNailBeat+1f, startBeat);
SpawnLongNail(targetNailBeat+2f, startBeat);
}
}
}
};
scheduledPatterns.Add(pattern);
}
}
@ -329,21 +281,42 @@ namespace HeavenStudio.Games
OnGameSwitch(beat);
}
void UpdatePatterns()
{
double beat = conductor.songPositionInBeatsAsDouble;
while (patternStartBeat < beat + PATTERN_SEEK_TIME)
{
if (patternIndex < scheduledPatterns.Count)
{
var pattern = scheduledPatterns[patternIndex];
if (pattern.beat + pattern.length < patternStartBeat) continue;
SpawnPattern(pattern.beat, pattern.length, pattern.type);
patternStartBeat += pattern.length;
patternIndex++;
}
else
{
break;
}
}
}
public void SlideShoji(double beat, double length, float fillRatio, int ease, bool mute)
{
if (!mute) MultiSound.Play(new MultiSound.Sound[]{ new MultiSound.Sound("nailCarpenter/open", beat)});
if (!mute) SoundByte.PlayOneShotGame("nailCarpenter/open", beat, forcePlay: true);
slideBeat = beat;
slideLength = length;
slideEase = (Util.EasingFunction.Ease)ease;
slideRatioLast = slideRatioNext;
slideRatioNext = fillRatio;
}
void UpdateShoji(double beat)
{
if (beat >= slideBeat)
{
float slideLast = 17.8f *(1-slideRatioLast);
float slideNext = 17.8f *(1-slideRatioNext);
float slideLast = 17.8f * (1 - slideRatioLast);
float slideNext = 17.8f * (1 - slideRatioNext);
Util.EasingFunction.Function func = Util.EasingFunction.GetEasingFunction(slideEase);
float slideProg = Conductor.instance.GetPositionFromBeat(slideBeat, slideLength, true);
slideProg = Mathf.Clamp01(slideProg);
@ -352,14 +325,139 @@ namespace HeavenStudio.Games
}
}
private void SpawnPattern(double beat, double length, PatternType pattern)
{
if (pattern == PatternType.None) return;
double patternLength = pattern switch
{
PatternType.Pudding => cachedPatternLengthPudding,
PatternType.Cherry => cachedPatternLengthCherry,
PatternType.Cake => cachedPatternLengthCake,
PatternType.CakeLong => cachedPatternLengthCakeLong,
_ => throw new NotImplementedException()
};
patternType = pattern;
int patternIterations = (int)Math.Ceiling(length / patternLength);
for (int i = 0; i < patternIterations; i++)
{
SpawnPatternSegment(beat + (patternLength * i), gameStartBeat, pattern switch
{
PatternType.Pudding => puddingPattern,
PatternType.Cherry => cherryPattern,
PatternType.Cake => cakePattern,
PatternType.CakeLong => cakeLongPattern,
_ => throw new NotImplementedException()
});
lastPatternType = patternType;
}
}
private void SpawnPatternSegment(double beat, double startbeat, ObjectPatternItem[] pattern)
{
foreach (var item in pattern)
{
double itemBeat = beat + item.beat;
switch (item.type)
{
case ObjectType.LongCharge:
SoundByte.PlayOneShotGame("nailCarpenter/signal2", itemBeat, forcePlay: true);
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(itemBeat, delegate
{
Carpenter.DoScaledAnimationAsync("carpenterArmUp", 0.25f);
}),
});
break;
case ObjectType.Nail:
SpawnNail(itemBeat, startbeat);
break;
case ObjectType.LongNail:
SpawnLongNail(itemBeat, startbeat);
break;
case ObjectType.Sweet:
// dynamically determine sweet based on pattern and last pattern
Sweet.sweetsType sweetType = Sweet.sweetsType.None;
switch (patternType)
{
case PatternType.Pudding:
SoundByte.PlayOneShotGame("nailCarpenter/one", itemBeat, forcePlay: true);
sweetType = Sweet.sweetsType.Pudding;
break;
case PatternType.Cherry:
SoundByte.PlayOneShotGame("nailCarpenter/three", itemBeat, forcePlay: true);
sweetType = Sweet.sweetsType.CherryPudding;
break;
case PatternType.Cake:
SoundByte.PlayOneShotGame("nailCarpenter/alarm", itemBeat, forcePlay: true);
sweetType = Sweet.sweetsType.ShortCake;
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(itemBeat, delegate
{
EffectExclamRed.DoScaledAnimationAsync("exclamAppear", 0.25f);
})
});
break;
case PatternType.CakeLong:
SoundByte.PlayOneShotGame("nailCarpenter/signal1", itemBeat, forcePlay: true);
sweetType = Sweet.sweetsType.LayerCake;
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(itemBeat, delegate
{
EffectExclamBlue.DoScaledAnimationAsync("exclamAppear", 0.25f);
}),
});
break;
default:
break;
}
if (lastPatternType == PatternType.Cake)
{
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.Cherry);
}
else if (sweetType != Sweet.sweetsType.None)
{
SpawnSweet(itemBeat, startbeat, sweetType);
}
break;
case ObjectType.ForceCherry:
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.Cherry);
break;
case ObjectType.ForcePudding:
SoundByte.PlayOneShotGame("nailCarpenter/one", itemBeat);
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.Pudding);
break;
case ObjectType.ForceCherryPudding:
SoundByte.PlayOneShotGame("nailCarpenter/three", itemBeat, forcePlay: true);
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.CherryPudding);
break;
case ObjectType.ForceShortCake:
SoundByte.PlayOneShotGame("nailCarpenter/alarm", itemBeat, forcePlay: true);
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.ShortCake);
break;
case ObjectType.ForceLayerCake:
SoundByte.PlayOneShotGame("nailCarpenter/signal1", itemBeat, forcePlay: true);
SoundByte.PlayOneShotGame("nailCarpenter/signal2", itemBeat + 1, forcePlay: true);
SpawnSweet(itemBeat, startbeat, Sweet.sweetsType.LayerCake);
break;
default:
break;
}
}
}
private void SpawnNail(double beat, double startBeat)
{
var newNail = Instantiate(baseNail, nailHolder).GetComponent<Nail>();
newNail.targetBeat = beat;
newNail.targetX = nailHolder.position.x;
newNail.metresPerSecond = scrollMetresPerBeat;
var nailX = (beat - startBeat) * -nailDistance / 2f;
newNail.transform.localPosition = new Vector3((float)nailX, 0f, 0f);
// var nailX = (beat - startBeat) * -nailDistance;
// newNail.transform.localPosition = new Vector3((float)nailX, 0f, 0f);
newNail.Init();
newNail.gameObject.SetActive(true);
}
@ -368,9 +466,11 @@ namespace HeavenStudio.Games
var newNail = Instantiate(baseLongNail, nailHolder).GetComponent<LongNail>();
newNail.targetBeat = beat;
newNail.targetX = nailHolder.position.x;
newNail.metresPerSecond = scrollMetresPerBeat;
var nailX = (beat - startBeat + 0.5f) * -nailDistance / 2f;
newNail.transform.localPosition = new Vector3((float)nailX, 0f, 0f);
// var nailX = (beat - startBeat) * -nailDistance;
// newNail.transform.localPosition = new Vector3((float)nailX, 0f, 0f);
newNail.Init();
newNail.gameObject.SetActive(true);
}
@ -380,38 +480,13 @@ namespace HeavenStudio.Games
newSweet.targetBeat = beat;
newSweet.sweetType = sweetType;
newSweet.targetX = nailHolder.position.x;
newSweet.metresPerSecond = scrollMetresPerBeat;
var sweetX = (beat - startBeat) * -nailDistance / 2f;
newSweet.transform.localPosition = new Vector3((float)sweetX, 0f, 0f);
// var sweetX = (beat - startBeat) * -nailDistance;
// newSweet.transform.localPosition = new Vector3((float)sweetX, 0f, 0f);
newSweet.gameObject.SetActive(true);
newSweet.Init();
}
bool IsInRange(List<double> list, double num)
{
foreach (double item in list)
{
if (num >= item && num <= item + .5f)
{
return true;
}
}
return false;
}
// MultiSound.Play may not work in OnPlay (OnGameSwitch?), so I play the audio using an alternative method.
List<MultiSound.Sound> sounds = new List<MultiSound.Sound>(){};
bool isPlayed = false;
public void PlaySound()
{
if (isPlayed) return;
if (sounds.Count > 0) {
MultiSound.Play(sounds.ToArray());
isPlayed = true;
sounds = null;
}
}
}
}

View file

@ -11,17 +11,20 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
public class Sweet : MonoBehaviour
{
public double targetBeat;
public float targetX;
public float metresPerSecond;
public sweetsType sweetType;
public Animator sweetAnim;
// public SpriteRenderer sweetSprite;
public enum sweetsType
{
Pudding=0,
CherryPudding=1,
ShortCake=2,
Cherry=3,
LayerCake=4,
None = -1,
Pudding = 0,
CherryPudding = 1,
ShortCake = 2,
Cherry = 3,
LayerCake = 4,
};
private NailCarpenter game;
@ -31,12 +34,13 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
game = NailCarpenter.instance;
AwakeAnim();
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_RegPress, HammmerJust, Empty, Empty);
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_AltFinish, HammmerJust, Empty, Empty);
game.ScheduleUserInput(targetBeat, 0, NailCarpenter.InputAction_SweetsHit, HammmerJust, null, null);
Update();
}
private void AwakeAnim()
{
switch(sweetType)
switch (sweetType)
{
case sweetsType.Pudding:
sweetAnim.Play("puddingIdle", -1, 0);
@ -55,9 +59,10 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
break;
}
}
private void BreakAnim()
{
switch(sweetType)
switch (sweetType)
{
case sweetsType.Pudding:
sweetAnim.DoScaledAnimationAsync("puddingBreak", 0.25f);
@ -81,13 +86,9 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
{
game.ScoreMiss();
BreakAnim();
game.Carpenter.DoScaledAnimationAsync("carpenterHit", 0.25f);
SoundByte.PlayOneShot("miss");
game.EyeAnim.DoScaledAnimationAsync("eyeBlink", 0.25f);
}
private void Empty(PlayerActionEvent caller) { }
private void Update()
{
var cond = Conductor.instance;
@ -95,7 +96,10 @@ namespace HeavenStudio.Games.Scripts_NailCarpenter
if (cond.isPlaying && !cond.isPaused)
{
double beat = cond.songPositionInBeats;
if (targetBeat != double.MinValue)
Vector3 pos = transform.position;
pos.x = targetX + (float)((beat - targetBeat) * metresPerSecond);
transform.position = pos;
if (targetBeat != double.MinValue)
{
if (beat >= targetBeat + 9) Destroy(gameObject);
}