Harald wroteJust add a
using Spine;
statement at the top, it does not find Spine.TrackEntry
.
ah i see, thank you. It doesn't throw error now but...
Something weird happened.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;
using Spine;
public class PlayerNormalAttack : Skill
{
int attackNumber = 0;
bool at_state = false;
public Skill nextAttack;
public override void EnterAttack()
{
Debug.Log("EXECUTE ATTACK");
boss.set_animation(0,"attack1",false);
attackNumber = 1;
at_state = true;
}
void Awake()
{
boss.animationState.Complete += OnSpineAnimationComplete; // << THIS ONE
}
public void OnSpineAnimationComplete(TrackEntry trackEntry)
{
}
}
When I comment out/delete boss.animationState.Complete += OnSpineAnimationComplete;
it sets animation properly. But when I add/ uncomment it, it doesn't change animation and it keep repeating Debug.Log("EXECUTE ATTACK")
over and over again.
hmm that doesn't make sense to me. I can't comprehend.
this is the Character
class:
Somehow currentState
keep showing States.Stand
while nextState
keep showing States.Attack
. My guess is maybe it keep entering stand > attack > stand > attack but I don't know why. I never write any script that change state to States.Stand
when in States.Attack
. @.@
Or maybe because the script stopped executing... It didn't notify that it changed currentState.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Spine.Unity;
public class Character : MonoBehaviour
{
// Animation
public bool autoFacing = false;
public Vector2 facing;
public Vector2 targeting;
public GameObject puppet;
SkeletonAnimation skeletonAnimation;
public Spine.AnimationState animationState;
//Skeleton skeleton;
// Character Property
public float moveSpeed = 4f;
public Rigidbody2D rb;
// Skill slot
public Skill[] attackSlot = new Skill[1];
// Energy System
public bool unlimited_energy = false;
int energy;
int max_energy = 1000;
int energy_regeneration = 10;
int adrenaline_level = 10;
float regen_delay = 1f;
// State property (used for character movement)
float duration = 0f; // used in Evade state.
Vector2 freezed_movement; // used in Evade state.
int currentAttack = 0; // used in Attack state.
// Character Controller / Input
public Vector2 movement;
public bool dash = false;
public int attack = -1; // -1 = stop attacking. 0~.. index for attackSlot
public bool block = false;
//StateMachine
int previousState;
int currentState;
public int nextState;
// States
public enum States:int {
Stand,
Run,
Evade,
Sprint,
Attack, //not implemented yet
Block
};
void Start()
{
rb = GetComponent<Rigidbody2D>();
skeletonAnimation = puppet.GetComponent<SkeletonAnimation>();
animationState = skeletonAnimation.AnimationState;
//skeleton = skeletonAnimation.skeleton;
}
void FixedUpdate()
{
// Energy system
regen_delay -= Time.fixedDeltaTime;
if (regen_delay <= 0f)
{
regen_delay += 0.1f;
if (energy != max_energy)
{
energy = Mathf.Clamp(energy + energy_regeneration,0,max_energy);
//Debug.Log("Energy : "+energy.ToString());
}
}
// State Method
if (currentState != nextState)
{
ExitState(currentState);
previousState = currentState;
EnterState(nextState);
currentState = nextState;
Debug.Log("Enter state: "+nextState.ToString());
}
ProcessState(currentState,Time.fixedDeltaTime);
}
bool useEnergy(int amount)
{
if (hasEnoughEnergy(amount)){
energy -= amount;
return true;
} else {
return false;
}
}
bool hasEnoughEnergy(int amount)
{
if (energy >= amount){
return true;
}
else {
return false;
}
}
void move(Vector2 amount) // to move character normally
{
rb.MovePosition( rb.position + (amount*Time.fixedDeltaTime) );
}
void push(Vector2 amount) // to move character in one frame.
{
}
void refresh_facing() // for puppet
{
transform.localScale = new Vector3(Mathf.Sign(facing.x),1,1);
}
void set_facing(float direction) // for puppet
{
transform.localScale = new Vector3(Mathf.Sign(direction),1,1);
}
public void set_animation(int track,string animation, bool loop)
{
if(skeletonAnimation.AnimationState.GetCurrent(track) == null || !string.Equals(skeletonAnimation.AnimationState.GetCurrent(track).Animation.Name,animation))
{
skeletonAnimation.AnimationState.SetAnimation(track,animation,loop);
}
}
void EnterState(int state)
{
switch (state)
{
case (int)States.Stand:
set_animation(0,"stand",true);
break;
case (int)States.Run:
set_animation(0,"run",true);
break;
case (int)States.Sprint:
set_animation(0,"dash",true);
break;
case (int)States.Evade:
set_facing(movement.x);
//skeletonAnimation.AnimationState.TimeScale = 2f;
set_animation(0,"roll",false);
duration = 1f;
freezed_movement = movement.normalized;
break;
case (int)States.Attack:
attackSlot[currentAttack].EnterAttack();
break;
case (int)States.Block:
set_animation(0,"block",false);
break;
default:
break;
}
}
void ProcessState(int state,float delta)
{
switch (state)
{
case (int)States.Stand:
if ( (movement.x != 0f) || (movement.y != 0f) )
{
nextState = (int)States.Run;
}
else if (block)
{
nextState = (int)States.Block;
}
else if (attack != -1)
{
nextState = (int)States.Attack;
}
if (autoFacing)
{
refresh_facing();
}
break;
case (int)States.Run:
//Debug.Log(skeletonAnimation.AnimationState.GetCurrent(0));
move(movement.normalized*moveSpeed);
if ( (movement.x == 0f) && (movement.y == 0f) )
{
nextState = (int)States.Stand;
}
else if (dash)
{
nextState = (int)States.Evade;
}
else if (block)
{
nextState = (int)States.Block;
}
if (autoFacing)
{
if (Mathf.Sign(movement.x) == -Mathf.Sign(facing.x))
{
set_animation(0,"run_back",true);
}
else if (Mathf.Sign(movement.x) == Mathf.Sign(facing.x))
{
set_animation(0,"run",true);
}
refresh_facing();
}
break;
case (int)States.Evade:
duration -= Time.fixedDeltaTime;
//Vector2 amount = freezed_movement[i]7f[/i]duration*moveSpeed;
Vector2 amount = (freezed_movement[i]5f[/i]moveSpeed)[i]duration[/i]duration;
move(amount);
if (duration <= 0f)
{
nextState = (int)States.Run;
if (dash)
{
nextState = (int)States.Sprint;
}
else
{
nextState = (int)States.Run;
}
}
break;
case (int)States.Sprint:
move(movement.normalized[i]moveSpeed[/i]2f);
if ( (movement.x == 0f) && (movement.y == 0f) )
{
nextState = (int)States.Stand;
}
if (movement.x != 0)
{
set_facing(movement.x);
}
break;
case (int)States.Attack:
attackSlot[currentAttack].ProcessAttack();
break;
case (int)States.Block:
if (!block)
{
nextState = (int)States.Stand;
}
break;
default:
break;
}
}
void ExitState(int state)
{
switch (state)
{
case (int)States.Evade:
skeletonAnimation.AnimationState.TimeScale = 1f;
break;
case (int)States.Attack:
attackSlot[currentAttack].ExitAttack();
break;
default:
break;
}
}
}
I will try to use other method for the time being... :confused:
EDIT
I also tried
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;
using Spine;
public class PlayerNormalAttack : Skill
{
int attackNumber = 0;
bool at_state = false;
public Skill nextAttack;
public override void EnterAttack()
{
Debug.Log("EXECUTE ATTACK");
boss.set_animation(0,"attack1",false);
attackNumber = 1;
at_state = true;
}
public override void ProcessAttack()
{
Debug.Log("processing");
}
// copas
[SpineEvent] public string slashEventName = "slash";
// copas
void Awake()
{
// http://esotericsoftware.com/spine-unity-events Start
var skeletonAnimation = GetComponent<SkeletonAnimation>();
if (skeletonAnimation == null) return;
skeletonAnimation.AnimationState.Event += HandleEvent;
skeletonAnimation.AnimationState.Start += delegate (TrackEntry trackEntry) {
Debug.Log(string.Format("track {0} started a new animation.", trackEntry.TrackIndex));
};
skeletonAnimation.AnimationState.End += delegate {
// ... or choose to ignore its parameters.
Debug.Log("An animation ended!");
};
// http://esotericsoftware.com/spine-unity-events Start
}
void HandleEvent(TrackEntry trackEntry, Spine.Event e)
{
Debug.Log("SPINE EVENT");
if (e.Data.Name == slashEventName) {
Debug.Log("Play a footstep sound!");
}
}
}
but this does not call either Debug.Log("An animation ended!")
, Debug.Log("Play a footstep sound!")
, and Debug.Log(string.Format("track {0} started a new animation.", trackEntry.TrackIndex))
at all. 😢
If I used Start()
instead of Awake()
like in the guide on that page. The same with the earlier problem happened, the one that had multiple "EXECUTE ATTACK" messages.