2022-01-24 02:15:23 +00:00
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
using NaughtyBezierCurves ;
2022-03-14 14:21:05 +00:00
using HeavenStudio.Util ;
2023-04-26 12:43:35 +00:00
using UnityEngine.UIElements ;
using DG.Tweening ;
2022-01-24 02:15:23 +00:00
2022-03-14 14:21:05 +00:00
namespace HeavenStudio.Games.Scripts_SpaceSoccer
2022-01-24 02:15:23 +00:00
{
2023-04-26 12:43:35 +00:00
public class Ball : SuperCurveObject
2022-01-24 02:15:23 +00:00
{
2022-03-18 01:44:58 +00:00
public enum State { None , Dispensing , Kicked , HighKicked , Toe } ;
2022-01-24 02:15:23 +00:00
[Header("Components")]
2022-02-02 08:36:20 +00:00
[HideInInspector] public Kicker kicker ;
2022-01-24 02:15:23 +00:00
[SerializeField] private GameObject holder ;
[SerializeField] private GameObject spriteHolder ;
2022-02-02 08:36:20 +00:00
[SerializeField] private GameObject kickFX ;
2022-01-24 02:15:23 +00:00
[Space(10)]
2023-04-26 12:43:35 +00:00
//[SerializeField] private BezierCurve3D dispenseCurve;
//[SerializeField] private BezierCurve3D kickCurve;
//[SerializeField] private BezierCurve3D highKickCurve;
//[SerializeField] private BezierCurve3D toeCurve;
2022-01-24 02:15:23 +00:00
[Header("Properties")]
2022-02-26 07:27:51 +00:00
public float startBeat ;
public State state ;
public float nextAnimBeat ;
2022-02-06 08:28:14 +00:00
public float highKickSwing = 0f ;
2022-01-24 02:15:23 +00:00
private float lastSpriteRot ;
2023-01-16 03:05:25 +00:00
public bool canKick ;
public bool waitKickRelease ;
2022-01-25 01:02:45 +00:00
private bool lastKickLeft ;
2023-04-26 12:43:35 +00:00
private SuperCurveObject . Path kickPath ;
private SuperCurveObject . Path dispensePath ;
private SuperCurveObject . Path highKickPath ;
private SuperCurveObject . Path toePath ;
//private float currentKickPathScale = 1;
2022-01-24 02:15:23 +00:00
2023-04-26 12:43:35 +00:00
protected override void UpdateLastRealPos ( )
{
lastRealPos = transform . localPosition ;
}
2022-02-26 07:27:51 +00:00
public void Init ( Kicker kicker , float dispensedBeat )
2022-01-24 02:15:23 +00:00
{
2022-02-26 07:27:51 +00:00
this . kicker = kicker ;
kicker . ball = this ;
kicker . dispenserBeat = dispensedBeat ;
2022-02-26 07:33:10 +00:00
float currentBeat = Conductor . instance . songPositionInBeats ;
2023-04-26 12:43:35 +00:00
kickPath = SpaceSoccer . instance . GetPath ( "Kick" ) ;
dispensePath = SpaceSoccer . instance . GetPath ( "Dispense" ) ;
highKickPath = SpaceSoccer . instance . GetPath ( "HighKick" ) ;
toePath = SpaceSoccer . instance . GetPath ( "Toe" ) ;
//holder.transform.localPosition = kicker.transform.GetChild(0).position;
2022-02-26 07:33:10 +00:00
2023-04-26 12:43:35 +00:00
if ( currentBeat - dispensedBeat < 2f ) //check if ball is currently being dispensed (should only be false if starting in the middle of the remix)
2022-02-26 07:33:10 +00:00
{
2022-02-26 23:38:27 +00:00
//Debug.Log("Dispensing");
2022-02-26 07:27:51 +00:00
state = State . Dispensing ;
startBeat = dispensedBeat ;
2022-02-26 07:33:10 +00:00
nextAnimBeat = startBeat + GetAnimLength ( State . Dispensing ) ;
2022-02-26 07:27:51 +00:00
kicker . kickTimes = 0 ;
2022-02-26 07:33:10 +00:00
return ;
}
2022-08-21 23:46:45 +00:00
var highKicks = GameManager . instance . Beatmap . entities . FindAll ( c = > c . datamodel = = "spaceSoccer/high kick-toe!" ) ;
2022-02-26 07:33:10 +00:00
int numHighKicks = 0 ;
//determine what state the ball was in for the previous kick.
for ( int i = 0 ; i < highKicks . Count ; i + + )
{
if ( highKicks [ i ] . beat + highKicks [ i ] . length < = currentBeat )
{
numHighKicks + + ;
continue ;
}
if ( highKicks [ i ] . beat > currentBeat )
{
2022-02-26 23:38:27 +00:00
//Debug.Log("Setting state to kicked");
2022-02-26 07:33:10 +00:00
state = State . Kicked ;
float relativeBeat = currentBeat - dispensedBeat ;
startBeat = dispensedBeat + ( int ) ( relativeBeat - 0.1 ) ; //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
nextAnimBeat = startBeat + GetAnimLength ( State . Kicked ) ;
kicker . kickTimes = ( int ) ( relativeBeat - 0.1 ) - numHighKicks - 1 ; //every high kick has 2 kicks in the same time a regular keep-up does 3 kicks.
break ;
}
else
{
highKickSwing = highKicks [ i ] . swing ;
2022-02-27 22:12:17 +00:00
if ( highKickSwing = = 0f )
highKickSwing = 0.5f ;
2022-02-26 07:33:10 +00:00
if ( highKicks [ i ] . beat + GetAnimLength ( State . HighKicked ) > currentBeat )
{
2022-02-26 23:38:27 +00:00
//Debug.Log("Setting state to high kick");
2022-02-26 07:33:10 +00:00
state = State . HighKicked ;
float relativeBeat = highKicks [ i ] . beat - dispensedBeat ;
startBeat = dispensedBeat + Mathf . Ceil ( relativeBeat ) ; //there is a chance this makes startBeat later than the current beat, but it shouldn't matter too much. It would only happen if the user places the high kicks incorrectly.
nextAnimBeat = startBeat + GetAnimLength ( State . HighKicked ) ;
kicker . kickTimes = Mathf . CeilToInt ( relativeBeat ) - numHighKicks - 1 ;
break ;
}
else
{
2022-02-26 23:38:27 +00:00
//Debug.Log("Setting state to toe");
2022-02-26 07:33:10 +00:00
state = State . Toe ;
float relativeBeat = Mathf . Ceil ( highKicks [ i ] . beat - dispensedBeat ) + GetAnimLength ( State . HighKicked ) ; //there is a chance this makes startBeat later than the current beat, but it shouldn't matter too much. It would only happen if the user places the high kicks incorrectly.
startBeat = dispensedBeat + relativeBeat ;
nextAnimBeat = startBeat + GetAnimLength ( State . Toe ) ;
kicker . kickTimes = ( int ) ( relativeBeat - GetAnimLength ( State . HighKicked ) ) - numHighKicks ;
break ;
}
}
}
2022-03-18 01:44:58 +00:00
if ( state = = 0 ) //if the for loop didn't set the state, i.e. all the high kicks happen before the point we start at.
2022-02-26 07:33:10 +00:00
{
2022-02-26 23:38:27 +00:00
//Debug.Log("Defaulting to kicked state");
2022-02-26 07:33:10 +00:00
state = State . Kicked ;
float relativeBeat = currentBeat - dispensedBeat ;
startBeat = dispensedBeat + ( int ) ( relativeBeat - 0.1 ) ; //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
nextAnimBeat = startBeat + GetAnimLength ( State . Kicked ) ;
kicker . kickTimes = ( int ) ( relativeBeat - 0.1 ) - numHighKicks - 1 ;
}
2022-02-26 23:38:27 +00:00
Update ( ) ; //make sure the ball is in the right place
2022-02-02 08:36:20 +00:00
}
public void Kick ( bool player )
{
if ( player )
2023-04-26 12:43:35 +00:00
Jukebox . PlayOneShotGame ( "spaceSoccer/ballHit" , - 1 , Jukebox . GetPitchFromCents ( UnityEngine . Random . Range ( - 38 , 39 ) , false ) ) ;
2022-01-25 01:02:45 +00:00
lastSpriteRot = spriteHolder . transform . eulerAngles . z ;
2022-01-24 02:15:23 +00:00
2022-02-26 07:27:51 +00:00
SetState ( State . Kicked ) ;
2022-01-24 02:15:23 +00:00
2022-01-25 01:02:45 +00:00
lastKickLeft = kicker . kickLeft ;
2023-04-26 12:43:35 +00:00
/ * if ( kicker . kickLeft )
2022-01-24 02:15:23 +00:00
{
kickCurve . transform . localScale = new Vector3 ( - 1 , 1 ) ;
2023-04-26 12:43:35 +00:00
currentKickPathScale = - 1 ;
2022-01-24 02:15:23 +00:00
}
else
{
kickCurve . transform . localScale = new Vector3 ( 1 , 1 ) ;
2023-04-26 12:43:35 +00:00
currentKickPathScale = 1 ;
} * /
//kickCurve.KeyPoints[0].transform.position = holder.transform.position;
//kickPath.positions[0].pos = holder.transform.position;
UpdateLastRealPos ( ) ;
2022-02-02 08:36:20 +00:00
HitFX ( ) ;
2022-01-24 02:15:23 +00:00
}
public void HighKick ( )
{
2022-01-24 10:13:46 +00:00
lastSpriteRot = spriteHolder . transform . eulerAngles . z ;
2022-02-26 07:27:51 +00:00
SetState ( State . HighKicked ) ;
2022-01-24 02:15:23 +00:00
2023-04-26 12:43:35 +00:00
//highKickCurve.KeyPoints[0].transform.position = holder.transform.position;
//highKickPath.positions[0].pos = holder.transform.position;
UpdateLastRealPos ( ) ;
2022-02-02 08:36:20 +00:00
HitFX ( ) ;
2022-01-24 02:15:23 +00:00
}
public void Toe ( )
{
2022-01-26 22:23:18 +00:00
2022-01-24 10:13:46 +00:00
lastSpriteRot = spriteHolder . transform . eulerAngles . z ;
2022-02-26 07:27:51 +00:00
SetState ( State . Toe ) ;
2022-02-02 08:36:20 +00:00
2023-04-26 12:43:35 +00:00
//toeCurve.KeyPoints[0].transform.position = holder.transform.position;
//toePath.positions[0].pos = holder.transform.position;
UpdateLastRealPos ( ) ;
2022-01-26 05:38:12 +00:00
if ( lastKickLeft )
{
2023-04-26 12:43:35 +00:00
//toeCurve.KeyPoints[1].transform.localPosition = new Vector3(5.39f, 0);
toePath . positions [ 1 ] . pos = new Vector3 ( 5.39f , 0 ) ;
2022-01-26 05:38:12 +00:00
}
else
{
2023-04-26 12:43:35 +00:00
//toeCurve.KeyPoints[1].transform.localPosition = new Vector3(6.49f, 0);
toePath . positions [ 1 ] . pos = new Vector3 ( 6.49f , 0 ) ;
2022-01-26 05:38:12 +00:00
}
2022-02-02 08:36:20 +00:00
HitFX ( ) ;
2022-01-24 02:15:23 +00:00
}
private void Update ( )
{
2023-04-26 12:43:35 +00:00
float beat = Conductor . instance . songPositionInBeats ;
2022-02-26 23:38:27 +00:00
switch ( state ) //handle animations
2022-01-24 02:15:23 +00:00
{
2022-03-26 02:08:46 +00:00
case State . None : //the only time any ball should ever have this state is if it's the unused offscreen ball (which is the only reason this state exists)
{
gameObject . SetActive ( false ) ;
break ;
}
2022-02-26 07:27:51 +00:00
case State . Dispensing :
2022-01-24 02:15:23 +00:00
{
2022-02-26 07:27:51 +00:00
float normalizedBeatAnim = Conductor . instance . GetPositionFromBeat ( startBeat , 2.35f ) ;
2022-02-02 08:36:20 +00:00
2023-04-26 12:43:35 +00:00
//dispenseCurve.KeyPoints[0].transform.position = new Vector3(kicker.transform.GetChild(0).position.x - 6f, kicker.transform.GetChild(0).position.y - 6f);
//dispenseCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x - 1f, kicker.transform.GetChild(0).position.y - 6f);
2022-01-24 02:15:23 +00:00
2023-04-26 12:43:35 +00:00
dispensePath . positions [ 0 ] . pos = new Vector3 ( - 6f , - 6f ) ;
dispensePath . positions [ 1 ] . pos = new Vector3 ( - 1f , - 6f ) ;
//holder.transform.localPosition = dispenseCurve.GetPoint(normalizedBeatAnim);
holder . transform . localPosition = GetPathPositionFromBeat ( dispensePath , Mathf . Max ( beat , startBeat ) , out float height , startBeat ) ;
2022-02-26 07:27:51 +00:00
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( 0f , - 1440f , normalizedBeatAnim ) ) ;
break ;
}
case State . Kicked :
2022-01-24 02:15:23 +00:00
{
2022-02-26 07:27:51 +00:00
float normalizedBeatAnim = Conductor . instance . GetPositionFromBeat ( startBeat , 1.5f ) ;
2023-04-26 12:43:35 +00:00
kickPath . positions [ 0 ] . pos = lastRealPos ;
2022-02-26 07:27:51 +00:00
if ( ! lastKickLeft )
2022-01-24 10:13:46 +00:00
{
2023-04-26 12:43:35 +00:00
//kickCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x + 0.5f, kicker.transform.GetChild(0).position.y - 6f);
kickPath . positions [ 1 ] . pos = new Vector3 ( 0 , - 6f ) ;
2022-02-26 07:27:51 +00:00
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( lastSpriteRot , lastSpriteRot - 360f , normalizedBeatAnim ) ) ;
2022-01-24 10:13:46 +00:00
}
2022-02-26 07:27:51 +00:00
else
2022-01-24 10:13:46 +00:00
{
2023-04-26 12:43:35 +00:00
//kickCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x - 2.5f, kicker.transform.GetChild(0).position.y - 6f);
kickPath . positions [ 1 ] . pos = new Vector3 ( - 2.5f , - 6f ) ;
2022-02-26 07:27:51 +00:00
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( lastSpriteRot , lastSpriteRot + 360f , normalizedBeatAnim ) ) ;
2022-01-24 10:13:46 +00:00
}
2022-02-26 07:27:51 +00:00
2023-04-26 12:43:35 +00:00
//holder.transform.localPosition = kickCurve.GetPoint(normalizedBeatAnim);
holder . transform . localPosition = GetPathPositionFromBeat ( kickPath , Mathf . Max ( beat , startBeat ) , out float height , startBeat ) ;
2022-02-26 07:27:51 +00:00
break ;
2022-01-24 02:15:23 +00:00
}
2022-02-26 07:27:51 +00:00
case State . HighKicked :
{
float normalizedBeatAnim = Conductor . instance . GetPositionFromBeat ( startBeat , GetAnimLength ( State . HighKicked ) + 0.3f ) ;
2023-04-26 12:43:35 +00:00
highKickPath . positions [ 0 ] . duration = GetAnimLength ( State . HighKicked ) + 0.3f ;
//highKickCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x - 3.5f, kicker.transform.GetChild(0).position.y - 6f);
2022-02-02 08:36:20 +00:00
2023-04-26 12:43:35 +00:00
highKickPath . positions [ 0 ] . pos = lastRealPos ;
highKickPath . positions [ 1 ] . pos = new Vector3 ( - 3.5f , - 6f ) ;
2022-02-02 08:36:20 +00:00
2023-04-26 12:43:35 +00:00
//holder.transform.localPosition = highKickCurve.GetPoint(normalizedBeatAnim);
holder . transform . localPosition = GetPathPositionFromBeat ( highKickPath , Mathf . Max ( beat , startBeat ) , out float height , startBeat ) ;
2022-02-26 07:27:51 +00:00
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( lastSpriteRot , lastSpriteRot + 360f , normalizedBeatAnim ) ) ;
break ;
2022-01-24 02:15:23 +00:00
}
2022-02-26 07:27:51 +00:00
case State . Toe :
{
float normalizedBeatAnim = Conductor . instance . GetPositionFromBeat ( startBeat , GetAnimLength ( State . Toe ) + 0.35f ) ;
2023-04-26 12:43:35 +00:00
toePath . positions [ 0 ] . duration = GetAnimLength ( State . Toe ) + 0.35f ;
toePath . positions [ 0 ] . pos = lastRealPos ;
2022-02-02 08:36:20 +00:00
2022-02-26 07:27:51 +00:00
if ( ! lastKickLeft )
{
2023-04-26 12:43:35 +00:00
//toeCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x + 0.5f, kicker.transform.GetChild(0).position.y - 6f);
toePath . positions [ 1 ] . pos = new Vector3 ( - 1.5f , - 6f ) ;
2022-02-26 07:27:51 +00:00
}
else
{
2023-04-26 12:43:35 +00:00
//toeCurve.KeyPoints[1].transform.position = new Vector3(kicker.transform.GetChild(0).position.x - 1.0f, kicker.transform.GetChild(0).position.y - 6f);
toePath . positions [ 1 ] . pos = new Vector3 ( - 0.5f , - 6f ) ;
2022-02-26 07:27:51 +00:00
}
2022-02-02 08:36:20 +00:00
2023-04-26 12:43:35 +00:00
//holder.transform.localPosition = toeCurve.GetPoint(normalizedBeatAnim);
holder . transform . localPosition = GetPathPositionFromBeat ( toePath , Mathf . Max ( beat , startBeat ) , out float height , startBeat ) ;
2022-02-26 07:27:51 +00:00
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( lastSpriteRot , - 860f , normalizedBeatAnim ) ) ;
break ;
}
2022-01-24 02:15:23 +00:00
}
2023-04-26 12:43:35 +00:00
holder . transform . position = new Vector3 ( holder . transform . position . x , holder . transform . position . y , kicker . transform . GetChild ( 0 ) . position . z ) ;
2022-02-02 08:36:20 +00:00
}
private void HitFX ( )
{
GameObject kickfx = Instantiate ( kickFX . gameObject , SpaceSoccer . instance . transform ) ;
kickfx . SetActive ( true ) ;
kickfx . transform . position = holder . transform . position ;
2022-01-24 02:15:23 +00:00
}
2022-02-06 08:28:14 +00:00
2022-02-26 07:27:51 +00:00
private void SetState ( State newState )
2022-02-06 08:28:14 +00:00
{
2022-02-26 07:27:51 +00:00
state = newState ;
startBeat = nextAnimBeat ;
nextAnimBeat + = GetAnimLength ( newState ) ;
}
public float GetAnimLength ( State anim )
{
switch ( anim )
2022-02-06 08:28:14 +00:00
{
2022-02-26 07:27:51 +00:00
case State . Dispensing :
return 2f ;
case State . Kicked :
return 1f ;
case State . HighKicked :
2022-02-06 08:28:14 +00:00
return 2f - highKickSwing ;
2022-02-26 07:27:51 +00:00
case State . Toe :
return 2f - ( 1f - highKickSwing ) ;
default :
Debug . LogError ( "Ball has invalid state. State number: " + ( int ) anim ) ;
return 0f ;
2022-02-06 08:28:14 +00:00
}
}
2022-01-24 02:15:23 +00:00
}
}