Browse Source

Add support for multiple actions for one actor. #1

master
parent
commit
d5bed01a78
21 changed files with 417 additions and 167 deletions
  1. +200
    -0
      Assets/Scripts/coa4u/ActionsBase/ActionInstant.cs
  2. +38
    -0
      Assets/Scripts/coa4u/ActionsInstant/ActionSelectRoamingPoint.cs
  3. +43
    -0
      Assets/Scripts/coa4u/ActionsInterval/ActionMoveForward.cs
  4. +12
    -0
      Assets/scripts/coa4u/ActionsBase/Action.cs
  5. +2
    -4
      Assets/scripts/coa4u/ActionsBase/ActionParallel.cs
  6. +7
    -0
      Assets/scripts/coa4u/ActionsBase/ActionRepeat.cs
  7. +3
    -8
      Assets/scripts/coa4u/ActionsBase/ActionSequence.cs
  8. +1
    -1
      Assets/scripts/coa4u/ActionsBase/ActionStop.cs
  9. +2
    -1
      Assets/scripts/coa4u/ActionsInstant/ActionLog.cs
  10. +1
    -3
      Assets/scripts/coa4u/ActionsInstant/ActionSetDirection.cs
  11. +1
    -1
      Assets/scripts/coa4u/ActionsInstant/ActionSetRotation.cs
  12. +9
    -1
      Assets/scripts/coa4u/ActionsInterval/ActionFadeIn.cs
  13. +1
    -18
      Assets/scripts/coa4u/ActionsInterval/ActionMoveBy.cs
  14. +1
    -2
      Assets/scripts/coa4u/ActionsInterval/ActionMoveTo.cs
  15. +1
    -0
      Assets/scripts/coa4u/ActionsInterval/ActionRotateBy.cs
  16. +14
    -6
      Assets/scripts/coa4u/ActionsInterval/ActionRotateTo.cs
  17. +0
    -51
      Assets/scripts/coa4u/ActionsInterval/ActionSkewBy.cs
  18. +10
    -1
      Assets/scripts/coa4u/CoreClasses/Axises.cs
  19. +70
    -63
      Assets/scripts/coa4u/UnityComponents/Actor.cs
  20. +0
    -4
      Assets/scripts/coa4u/UnityComponents/ActorSampleActions.cs
  21. +1
    -3
      README.md

+ 200
- 0
Assets/Scripts/coa4u/ActionsBase/ActionInstant.cs View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using UnityEngine;

namespace coa4u
{
/// <summary>
/// Basic action class for subclassing. To inherit interval actions, consider using the ActionInterval as the base class.
/// </summary>
public class ActionInstant
{
/// <summary>
/// Axis locks - the action will try to preserve tha values of these axises when moving or rotating the target.
/// </summary>
public Axises locks = Axises.none;
/// <summary>
/// Sets if the action should stop when the actor's StopAllActions method is called.
/// </summary>
public bool unstopable = false;

protected Actor target;
protected Transform transform;
protected Renderer renderer;
private float durationValue = 0;
private float dtrValue = 0;
private bool isRunning = false;

public ActionInstant()
{
}

/// <summary>
/// Returns a copy of the action.
/// </summary>
public virtual ActionInstant Clone()
{
return new ActionInstant();
}

/// <summary>
/// Returns the reversed version of the action, if it is possible.
/// </summary>
public virtual ActionInstant Reverse()
{
throw new Exception("Can reverse only the reversable interval actions");
}

/// <summary>
/// This method is called at the action start. Usable for instant and interval actions.
/// </summary>
public virtual void Start()
{
if (target == null)
throw new Exception("Can start the action only after it's atached to the actor");
transform = target.transformCached;
renderer = target.rendererCached;
}

/// <summary>
/// This method is called at every frame update. Not usable for instant actions.
/// </summary>
public virtual void StepTimer(float dt)
{
if (target == null)
throw new Exception("Can update the action only after it's atached to the actor");
}

/// <summary>
/// This method is called after the interval action is stopped. Not usable for instant actions.
/// </summary>
public virtual void Stop()
{
if (target == null)
throw new Exception("Can stop the action only after it's atached to the actor");
}

/// <summary>
/// This method sets the actor for the action.
/// </summary>
public void SetActor(Actor actor)
{
target = actor;
}

/// <summary>
/// This method modifies the given vector to keep the locked axises untouched.
/// </summary>
protected void LockAxises(ref Vector3 point)
{
{
if (target == null)
throw new Exception("Can calculate axises only after the action is atached to the actor");
}

switch (locks)
{
case Axises.x:
point.x = transform.position.x;
break;
case Axises.y:
point.y = transform.position.y;
break;
case Axises.z:
point.z = transform.position.z;
break;
case Axises.xy:
point.x = transform.position.x;
point.y = transform.position.y;
break;
case Axises.xz:
point.x = transform.position.x;
point.z = transform.position.z;
break;
case Axises.yz:
point.y = transform.position.y;
point.z = transform.position.z;
break;
case Axises.xyz:
point.x = transform.position.x;
point.y = transform.position.y;
point.z = transform.position.z;
break;
case Axises.rx:
point.x = transform.rotation.eulerAngles.x;
break;
case Axises.ry:
point.y = transform.rotation.eulerAngles.y;
break;
case Axises.rz:
point.z = transform.rotation.eulerAngles.z;
break;
case Axises.rxy:
point.x = transform.rotation.eulerAngles.x;
point.y = transform.rotation.eulerAngles.y;
break;
case Axises.rxz:
point.x = transform.rotation.eulerAngles.x;
point.z = transform.rotation.eulerAngles.z;
break;
case Axises.ryz:
point.y = transform.rotation.eulerAngles.y;
point.z = transform.rotation.eulerAngles.z;
break;
case Axises.rxyz:
point.x = transform.rotation.eulerAngles.x;
point.y = transform.rotation.eulerAngles.y;
point.z = transform.rotation.eulerAngles.z;
break;
}
}

/// <summary>
/// Readonly property. Shows the remaining time of the action.
/// </summary>
public float duration
{
get
{
return durationValue;
}

protected set
{
durationValue = value;
}
}

/// <summary>
/// Readonly property. Shows if the action is running or not.
/// </summary>
public bool running
{
get
{
return isRunning;
}

protected set
{
isRunning = value;
}
}

/// <summary>
/// Readonly property. Contains the remaining tick time after action finished.
/// </summary>
public float dtr
{
get
{
return dtrValue;
}

protected set
{
dtrValue = value;
}
}
}
}

+ 38
- 0
Assets/Scripts/coa4u/ActionsInstant/ActionSelectRoamingPoint.cs View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using coa4u;

namespace coa4u
{
/// <summary>
/// Moves the target to the random point inside the given zone.
/// </summary>
class ActionSelectRoamingPoint : ActionInstant
{
protected Vector3 radius;
protected Vector3 pointRef;
protected float speed;
protected Vector3 delta;

public ActionSelectRoamingPoint(Vector3 targetRadius, ref Vector3 point)
: base()
{
radius = targetRadius;
pointRef = point;
}

public override ActionInstant Clone()
{
return new ActionSelectRoamingPoint(radius, ref pointRef);
}

public override void Start()
{
base.Start();
pointRef.x = UnityEngine.Random.Range(-radius.x, radius.x);
pointRef.y = UnityEngine.Random.Range(-radius.y, radius.y);
pointRef.z = UnityEngine.Random.Range(-radius.z, radius.z);
}
}
}

+ 43
- 0
Assets/Scripts/coa4u/ActionsInterval/ActionMoveForward.cs View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using UnityEngine;

namespace coa4u
{
/// <summary>
/// Moves in the given direction for the given amount of seconds.
/// </summary>
class ActionMoveForward : ActionInterval
{
protected float speed;
protected Vector3 delta;

public ActionMoveForward(float targetSpeed, float targetDuration)
: base(targetDuration)
{
speed = targetSpeed;
}

public override ActionInstant Clone()
{
return new ActionMoveForward(speed, duration);
}

public override ActionInstant Reverse()
{
return new ActionMoveForward(speed * -1F, duration);
}

public override void Start()
{
base.Start();
delta = speed * transform.forward;
}

public override void Step(float dt)
{
float d = dt / duration;
transform.Translate(delta * d, Space.World);
}
}
}

+ 12
- 0
Assets/scripts/coa4u/ActionsBase/Action.cs View File

@@ -4,6 +4,18 @@ using UnityEngine;

namespace coa4u
{
public enum Axises
{
none,
x,
y,
z,
xy,
xz,
yz,
xyz
}

/// <summary>
/// Basic action class for subclassing. To inherit interval actions, consider using the ActionInterval as the base class.
/// </summary>


+ 2
- 4
Assets/scripts/coa4u/ActionsBase/ActionParallel.cs View File

@@ -79,15 +79,13 @@ namespace coa4u
}
}

/// <summary>
/// This method is called after the interval action is stopped.
/// </summary>
public override void Stop()
{
base.Stop();
for (int i = 0; i < actions.Length; i++)
{
actions[i].Stop();
if (actions[i].running)
actions[i].Stop();
}
}
}

+ 7
- 0
Assets/scripts/coa4u/ActionsBase/ActionRepeat.cs View File

@@ -71,5 +71,12 @@ namespace coa4u
Stop();
}
}

public override void Stop()
{
base.Stop();
if (action.running)
action.Stop();
}
}
}

+ 3
- 8
Assets/scripts/coa4u/ActionsBase/ActionSequence.cs View File

@@ -51,7 +51,7 @@ namespace coa4u
index = 0;
actions[0].SetActor(target);
actions[0].Start();
while (!actions[index].running && index < actions.Length)
while (!actions[index].running && index < actions.Length - 1)
{
index += 1;
actions[index].SetActor(target);
@@ -84,16 +84,11 @@ namespace coa4u
}
}

/// <summary>
/// This method is called after the interval action is stopped.
/// </summary>
public override void Stop()
{
base.Stop();
for (int i = 0; i < actions.Length; i++)
{
actions[i].Stop();
}
if (actions[index].running)
actions[index].Stop();
}
}
}

+ 1
- 1
Assets/scripts/coa4u/ActionsBase/ActionStop.cs View File

@@ -22,7 +22,7 @@ namespace coa4u
public override void Start()
{
base.Start();
target.StopAction();
target.StopAllActions();
}
}
}

+ 2
- 1
Assets/scripts/coa4u/ActionsInstant/ActionLog.cs View File

@@ -7,9 +7,10 @@ namespace coa4u
/// <summary>
/// Prints a message in Unity debug console.
/// </summary>
[System.Serializable]
class ActionLog : ActionInstant
{
string message;
public string message;

public ActionLog(string targetMessage)
: base()


+ 1
- 3
Assets/scripts/coa4u/ActionsInstant/ActionSetDirection.cs View File

@@ -44,9 +44,7 @@ namespace coa4u
value = other.transformCached.position;
}
if (locks != Axises.none)
{
value.z = transform.position.z;
}
LockAxises(ref value);
transform.rotation = Quaternion.LookRotation(value - transform.position);
}
}

+ 1
- 1
Assets/scripts/coa4u/ActionsInstant/ActionSetRotation.cs View File

@@ -20,7 +20,7 @@ namespace coa4u
public ActionSetRotation(float angle)
: this(new Vector3(0, 0, angle))
{
locks = Axises.xy;
locks = Axises.rxy;
}

public override ActionInstant Clone()


+ 9
- 1
Assets/scripts/coa4u/ActionsInterval/ActionFadeIn.cs View File

@@ -11,7 +11,7 @@ namespace coa4u
{

public ActionFadeIn(float targetDuration)
: base(1, targetDuration)
: base(2, targetDuration)
{
}

@@ -24,5 +24,13 @@ namespace coa4u
{
return new ActionFadeOut(duration);
}

public override void Start()
{
base.Start();
Color targetColor = renderer.material.color;
targetColor.a = 0;
renderer.material.color = targetColor;
}
}
}

+ 1
- 18
Assets/scripts/coa4u/ActionsInterval/ActionMoveBy.cs View File

@@ -10,7 +10,6 @@ namespace coa4u
class ActionMoveBy : ActionInterval
{
protected Vector3 delta;
protected Vector3 referencePoint;

public ActionMoveBy(Vector3 targetDelta, float targetDuration)
: base(targetDuration)
@@ -23,12 +22,6 @@ namespace coa4u
{
}

public ActionMoveBy(ref Vector3 refPoint, float targetDuration)
: this(Vector3.zero, targetDuration)
{
referencePoint = refPoint;
}

public override ActionInstant Clone()
{
return new ActionMoveBy(delta, duration);
@@ -39,20 +32,10 @@ namespace coa4u
return new ActionMoveBy(delta * -1F, duration);
}

public override void Start()
{
base.Start();
if (referencePoint != null)
{
delta = referencePoint;
}
}

public override void Step(float dt)
{
float d = dt / duration;
Vector3 target = delta * d;
transform.Translate(target, Space.World);
transform.Translate(delta * d, Space.World);
}
}
}

+ 1
- 2
Assets/scripts/coa4u/ActionsInterval/ActionMoveTo.cs View File

@@ -40,8 +40,7 @@ namespace coa4u
public override void Step(float dt)
{
float d = dt / duration;
Vector3 target = path * d;
transform.Translate(target, Space.World);
transform.Translate(path * d, Space.World);
}
}
}

+ 1
- 0
Assets/scripts/coa4u/ActionsInterval/ActionRotateBy.cs View File

@@ -20,6 +20,7 @@ namespace coa4u
public ActionRotateBy(float angle, float targetDuration)
: this(new Vector3(0, 0, angle), targetDuration)
{
locks = Axises.rxy;
}

public override ActionInstant Clone()


+ 14
- 6
Assets/scripts/coa4u/ActionsInterval/ActionRotateTo.cs View File

@@ -21,7 +21,7 @@ namespace coa4u
public ActionRotateTo(float angle, float targetDuration)
: this(new Vector3(0, 0, angle), targetDuration)
{
locks = Axises.xy;
locks = Axises.rxy;
}

public override ActionInstant Clone()
@@ -37,10 +37,18 @@ namespace coa4u
{
float t = value[i];
float f = transform.rotation.eulerAngles[i];
if (Math.Abs(t - f) < Math.Abs(t + 360 - f))
if ((f - t) <= 180 && (f - t) >= -180)
{
path[i] = t - f;
else
path[i] = t + 360 - f;
}
else if ((f - t) > 180)
{
path[i] = t - f + 360;
}
else if ((f - t) < -180)
{
path[i] = t - f - 360;
}
}
if (locks != Axises.none)
LockAxises(ref path);
@@ -48,8 +56,8 @@ namespace coa4u
public override void Step(float dt)
{
float d = dt / duration;
Vector3 target = path * d;
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + target);
Vector3 rotation = path * d;
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + rotation);
}
}
}

+ 0
- 51
Assets/scripts/coa4u/ActionsInterval/ActionSkewBy.cs View File

@@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;

namespace coa4u
{
/// <summary>
/// Skews the object by the given angles.
/// </summary>
class ActionSkewBy : ActionInterval
{
protected Vector3 skewAngles1;
protected Vector3 skewAngles2;
protected Mesh mesh;

public ActionSkewBy(Vector3 targetAngles1, Vector3 targetAngles2, float targetDuration)
: base(targetDuration)
{
skewAngles1 = targetAngles1;
skewAngles2 = targetAngles2;
}

public override ActionInstant Clone()
{
return new ActionSkewBy(skewAngles1, skewAngles2, duration);
}

public override ActionInstant Reverse()
{
return new ActionSkewBy(-skewAngles1, -skewAngles2, duration);
}

public override void Start()
{
base.Start();
if (!(target is Actor))
{
throw new Exception("You should use Actor class instead of Actor, if you want to skew your object.");
}
}

public override void Step(float dt)
{
float d = dt / duration;
Vector3 vTarget = skewAngles1 * d;
((Actor)target).skewAngles1 += vTarget;
vTarget = skewAngles2 * d;
((Actor)target).skewAngles2 += vTarget;
}
}
}

+ 10
- 1
Assets/scripts/coa4u/CoreClasses/Axises.cs View File

@@ -13,6 +13,15 @@ namespace coa4u
xy,
xz,
yz,
xyz
xyz,
rx,
ry,
rz,
rxy,
rxz,
ryz,
rxyz


}
}

+ 70
- 63
Assets/scripts/coa4u/UnityComponents/Actor.cs View File

@@ -10,22 +10,16 @@ using coa4u;
public class Actor : MonoBehaviour
{
protected Dictionary<string, MethodHolder> methodsCache = new Dictionary<string, MethodHolder>();
protected ActionInstant action;
protected List<ActionInstant> actions = new List<ActionInstant>();
protected List<ActionInstant> actionsToDelete = new List<ActionInstant>();
protected List<ActionInstant> actionsToAdd = new List<ActionInstant>();
private bool paused = false;
protected Vector3 angles1prev = Vector3.zero;
protected Vector3 angles2prev = Vector3.zero;
private bool running = false;
protected const float coeff = Mathf.PI / 180;
protected Vector3[] initialState;
[HideInInspector]
public Transform transformCached;
[HideInInspector]
public Renderer rendererCached;
[HideInInspector]
public Mesh meshCached;
[HideInInspector]
public Vector3 skewAngles1;
[HideInInspector]
public Vector3 skewAngles2;

/// <summary>
/// This method is called when the script instance is being loaded.
@@ -34,13 +28,6 @@ public class Actor : MonoBehaviour
{
transformCached = gameObject.transform;
rendererCached = gameObject.renderer;

Component component = gameObject.GetComponent<MeshFilter>();
if (component != null)
{
meshCached = ((MeshFilter)component).mesh;
initialState = meshCached.vertices;
}
}

/// <summary>
@@ -48,45 +35,36 @@ public class Actor : MonoBehaviour
/// </summary>
protected void Update()
{
if (paused || action == null)
if (paused)
return;
if (action.running)
action.StepTimer(Time.deltaTime);
if (skewAngles1 != angles1prev || skewAngles2 != angles2prev)
UpdateSkew();
foreach (ActionInstant action in actions)
{
if (action.running)
action.StepTimer(Time.deltaTime);
if (!action.running)
actionsToDelete.Add(action);
}
}

/// <summary>
/// Updates the skew for the mesh.
/// This method is called after the every frame update.
/// </summary>
void UpdateSkew()
protected void LateUpdate()
{
if (meshCached == null)
return;

Matrix4x4 m = Matrix4x4.zero;
m[0, 0] = 1;
m[1, 1] = 1;
m[2, 2] = 1;
m[3, 3] = 1;
m[0, 1] = Mathf.Tan(skewAngles1.x * coeff); // skewing in xy
m[0, 2] = Mathf.Tan(skewAngles2.x * coeff); // skewing in xz
m[1, 0] = Mathf.Tan(skewAngles1.y * coeff); // skewing in yx
m[1, 2] = Mathf.Tan(skewAngles2.y * coeff); // skewing in yz
m[2, 0] = Mathf.Tan(skewAngles1.z * coeff); // skewing in zx
m[2, 1] = Mathf.Tan(skewAngles2.z * coeff); // skewing in zy

Vector3[] verts = new Vector3[initialState.Length];
int i = 0;
while (i < verts.Length)
foreach (ActionInstant action in actionsToAdd)
{
verts[i] = m.MultiplyPoint3x4(initialState[i]);
i++;
if (action.running)
actions.Add(action);
}

meshCached.vertices = verts;
angles1prev = skewAngles1;
angles2prev = skewAngles2;
foreach (ActionInstant action in actionsToDelete)
{
if (!action.running)
actions.Remove(action);
}
actionsToDelete.Clear();
actionsToAdd.Clear();
running = actions.Count > 0;
}

/// <summary>
@@ -94,31 +72,39 @@ public class Actor : MonoBehaviour
/// </summary>
public void AttachAction(ActionInstant targetAction)
{
if (action != null)
targetAction.SetActor(this);
targetAction.Start();
if (targetAction.running)
{
action.Stop();
actionsToAdd.Add(targetAction);
}
action = targetAction;
action.SetActor(this);
action.Start();
}

/// <summary>
/// Stopes and removes the given action.
/// </summary>
public void RemoveAction(ActionInstant targetAction)
{
if (targetAction.running)
targetAction.Stop();
}

/// <summary>
/// Stops all running actions for this actor.
/// </summary>
public void StopAction()
public void StopAllActions()
{
if (action == null)
return;
if (action.running)
action.Stop();
action = null;
foreach (ActionInstant action in actions)
{
if (action.running &! action.unstopable)
action.Stop();
}
}

/// <summary>
/// Pauses actions for this actor.
/// </summary>
public void PauseAction()
public void PauseActions()
{
paused = true;
}
@@ -126,7 +112,7 @@ public class Actor : MonoBehaviour
/// <summary>
/// Unpauses actions for this actor.
/// </summary>
public void UnpauseAction()
public void UnpauseActions()
{
paused = false;
}
@@ -136,9 +122,13 @@ public class Actor : MonoBehaviour
/// </summary>
public void SetTimeScale(float ts)
{
if (action is ActionInterval)
for (int i = 0; i < actions.Count; i++)
{
((ActionInterval)action).SetTimeScale(ts);
ActionInstant action = actions[i];
if (action is ActionInterval)
{
((ActionInterval)action).SetTimeScale(ts);
}
}
}

@@ -150,6 +140,9 @@ public class Actor : MonoBehaviour
methodsCache.Add(method.Method.Name, new MethodHolder(method));
}

/// <summary>
/// Adds method to cache to speed-up the ActionSendMessage.
/// </summary>
public void AddMethodToCache<T>(Action<T> method)
{
methodsCache.Add(method.Method.Name, new MethodHolder<T>(method));
@@ -170,6 +163,9 @@ public class Actor : MonoBehaviour
}
}

/// <summary>
/// Proxy method to receive messages. WARNING: If the message can be handled by the actor, it will be handled and will not be passed to the Unity3D gameobject.
/// </summary>
public void ReceiveMessage(string key, object param = null, SendMessageOptions options = SendMessageOptions.DontRequireReceiver)
{
if (methodsCache.ContainsKey(key))
@@ -184,4 +180,15 @@ public class Actor : MonoBehaviour
gameObject.SendMessage(key, param, options);
}
}

/// <summary>
/// Shows if the actor has any running actions.
/// </summary>
public bool hasRunningActions
{
get
{
return running;
}
}
}

+ 0
- 4
Assets/scripts/coa4u/UnityComponents/ActorSampleActions.cs View File

@@ -19,15 +19,11 @@ public class ActorSampleActions : Actor
new ActionDelay(1),
new ActionBlink(5, 0.1F, 0.4F),
new ActionDelay(1),
new ActionSkewBy(Vector3.zero, new Vector3(0, 30, 0), 1),
new ActionDelay(1),
new ActionJumpBy(new Vector3(-10, 0, 0), 1, 4, 1),
new ActionSkewBy(Vector3.zero, new Vector3(30, 0, 30), 1),
new ActionJumpTo(new Vector3(10, 10, 10), 1, 3, 1),
new ActionRotateBy(new Vector3(90, 0, 0), 1),
new ActionSkewBy(Vector3.zero, new Vector3(-30, 0, -30), 1),
new ActionJumpBy(new Vector3(-10, 0, 0), 1, 2, 1),
new ActionSkewBy(Vector3.zero, new Vector3(0, -30, 0), 1),
new ActionDelay(0.5F),
new ActionBezierRel(new Vector2 (5, 0), new Vector2(5, -10), new Vector2 (0, -10), 2),
new ActionScaleTo(new Vector3(2, 2, 2), 1),


+ 1
- 3
README.md View File

@@ -63,14 +63,12 @@ Base actions
Interval actions
- [ ] Follow - follows another actor with the given speed for the given amount of time (of forever).
- [ ] LookAt - rotates the object to look at the given actor.
- [x] SkewBy - skews the mesh by given values.
- [ ] SkewTo - skews the mesh to the given values.

Instant actions
- [x] SetRotation - instantly rotates the object to the given euler angles.
- [x] SetTint - instantly tints the object to the given color.
- [x] SetDirection - instantly rotates the object to look at the given actor.
- [ ] Stop - stops all actions for this object.
- [x] Stop - stops all actions for this object.

### Future plans
After completing these actions, i'm going to add some more to the list.