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 ;
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
{
2022-01-25 01:02:45 +00:00
public class Ball : MonoBehaviour
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)]
[SerializeField] private BezierCurve3D dispenseCurve ;
[SerializeField] private BezierCurve3D kickCurve ;
[SerializeField] private BezierCurve3D highKickCurve ;
[SerializeField] private BezierCurve3D toeCurve ;
[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-01-31 16:15:51 +00:00
public float zValue ;
2022-01-24 02:15:23 +00:00
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-01-31 16:15:51 +00:00
zValue = kicker . zValue ;
2022-02-26 07:33:10 +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 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 )
2022-01-24 02:15:23 +00:00
Jukebox . PlayOneShotGame ( "spaceSoccer/ballHit" ) ;
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 ;
if ( kicker . kickLeft )
2022-01-24 02:15:23 +00:00
{
kickCurve . transform . localScale = new Vector3 ( - 1 , 1 ) ;
}
else
{
kickCurve . transform . localScale = new Vector3 ( 1 , 1 ) ;
}
kickCurve . KeyPoints [ 0 ] . transform . position = holder . transform . position ;
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
highKickCurve . KeyPoints [ 0 ] . transform . position = holder . transform . position ;
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
2022-01-24 02:15:23 +00:00
toeCurve . KeyPoints [ 0 ] . transform . position = holder . transform . position ;
2022-01-26 05:38:12 +00:00
if ( lastKickLeft )
{
toeCurve . KeyPoints [ 1 ] . transform . localPosition = new Vector3 ( 5.39f , 0 ) ;
}
else
{
toeCurve . KeyPoints [ 1 ] . transform . localPosition = new Vector3 ( 6.49f , 0 ) ;
}
2022-02-02 08:36:20 +00:00
HitFX ( ) ;
2022-01-24 02:15:23 +00:00
}
private void Update ( )
{
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
2022-02-26 07:27:51 +00:00
dispenseCurve . KeyPoints [ 0 ] . transform . position = new Vector3 ( kicker . transform . position . x - 6f , kicker . transform . position . y - 6f ) ;
dispenseCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x - 1f , kicker . transform . position . y - 6f ) ;
2022-01-24 02:15:23 +00:00
2022-02-26 07:27:51 +00:00
holder . transform . localPosition = dispenseCurve . GetPoint ( normalizedBeatAnim ) ;
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 ) ;
if ( ! lastKickLeft )
2022-01-24 10:13:46 +00:00
{
2022-02-26 07:27:51 +00:00
kickCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x + 0.5f , kicker . transform . position . y - 6f ) ;
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
{
2022-02-26 07:27:51 +00:00
kickCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x - 2.5f , kicker . transform . position . y - 6f ) ;
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
holder . transform . localPosition = kickCurve . GetPoint ( normalizedBeatAnim ) ;
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 ) ;
2022-02-02 08:36:20 +00:00
2022-02-26 07:27:51 +00:00
highKickCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x - 3.5f , kicker . transform . position . y - 6f ) ;
2022-02-02 08:36:20 +00:00
2022-02-26 07:27:51 +00:00
holder . transform . localPosition = highKickCurve . GetPoint ( normalizedBeatAnim ) ;
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 ) ;
2022-02-02 08:36:20 +00:00
2022-02-26 07:27:51 +00:00
if ( ! lastKickLeft )
{
toeCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x + 0.5f , kicker . transform . position . y - 6f ) ;
}
else
{
toeCurve . KeyPoints [ 1 ] . transform . position = new Vector3 ( kicker . transform . position . x - 1.0f , kicker . transform . position . y - 6f ) ;
}
2022-02-02 08:36:20 +00:00
2022-02-26 07:27:51 +00:00
holder . transform . localPosition = toeCurve . GetPoint ( normalizedBeatAnim ) ;
spriteHolder . transform . eulerAngles = new Vector3 ( 0 , 0 , Mathf . Lerp ( lastSpriteRot , - 860f , normalizedBeatAnim ) ) ;
break ;
}
2022-01-24 02:15:23 +00:00
}
2022-02-02 08:36:20 +00:00
2023-01-31 16:15:51 +00:00
holder . transform . position = new Vector3 ( holder . transform . position . x , holder . transform . position . y , zValue ) ;
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
}
}