Unity3D角色攻击+攻击轨迹(初版)

layerAttackController.cs 是控制角色连招的脚本,上次已经分享过,不过添加了少少东西
layerDelegate.cs 是一个单例脚本,控制接受和传递事件的
SwordTrial.cs 是控制攻击的刀的轨迹的
//上面三个脚本绑定到自己的角色类中即可
刀的轨迹还需参照 AssestStore下载的一个刀轨迹的插件 (好像叫MeleeWeapon啥的)
Interpolate.cs和MeleeWeaponTrail.cs 是在AssestStore下载的一个刀轨迹的插件,个人感觉非常不错,简单易用,想看的朋友可以去下来看看,自带了例子的

Demo截图:



我写得不是很好,如果各位大鸟有更好的思路,可以分享给我研究研究

using UnityEngine;
using System.Collections;

public delegate void AttackStateDelegate(string name);

public class PlayerAttackController : MonoBehaviour {
	//派发改变攻击动画状态的委托
	public AttackStateDelegate setAttackState = null;
	//记录当前攻击动画;
	AnimationClip currentAttack;
	//获取人物动画组件;
	Animation playerAnimation;
	//动画标签;
	public enum ActionState
	{
		Attack_0,
		Attack_1,
		Attack_2,
		Attack_3,
		None
	}
	//记录当前动画标签;
	private ActionState actionState = ActionState.None;
	
	/**
	 * 攻击的逻辑
	 */
	void AttackLogic(){
		if (Input.GetButtonDown("Fire1")){
			if (actionState != ActionState.Attack_0 && actionState != ActionState.Attack_1&& actionState != ActionState.Attack_2&& actionState != ActionState.Attack_3) {
				actionState = ActionState.Attack_0;
			}else if (actionState == ActionState.Attack_0 && playerAnimation[currentAttack.name].time > 1.0f){
				actionState = ActionState.Attack_1;
			}else if (actionState == ActionState.Attack_1 && playerAnimation[currentAttack.name].time > 1.3f){
				actionState = ActionState.Attack_2;
			}else if (actionState == ActionState.Attack_2 && playerAnimation[currentAttack.name].time > 0.45f){
				actionState = ActionState.Attack_3;
			}
		}
	}
	
	/**
	 * 攻击套路选择
	 */
	void Attacks (){
		float delayTime =0.0f;
		
		switch (actionState){
			case ActionState.Attack_0:
				
				delayTime = -0.1f;
				if(setAttackState!=null){
					setAttackState("Attack");
				}
				playerAnimation.CrossFade("Attack", 0.15f);
				currentAttack = playerAnimation["Attack"].clip;
				
				break;
				
			case ActionState.Attack_1:
				
				delayTime = -0.1f;
				if(setAttackState!=null){
					setAttackState("Attack01");
				}
				playerAnimation.CrossFade("Attack01", 0.15f);
				currentAttack = playerAnimation["Attack01"].clip;
				
				break;
			
			case ActionState.Attack_2:
				
				delayTime = -0.1f;
				if(setAttackState!=null){
					setAttackState("Attack02");
				}
				playerAnimation.CrossFade("Attack02", 0.05f);
				currentAttack = playerAnimation["Attack02"].clip;
				
				break;
			
			case ActionState.Attack_3:
				
				delayTime = -0.1f;
				if(setAttackState!=null){
					setAttackState("Attack03");
				}
				playerAnimation.CrossFade("Attack03", 0.15f);
				currentAttack = playerAnimation["Attack03"].clip;
				
				break;
			
			case ActionState.None:
				if(setAttackState!=null){
					setAttackState("None");
					
				}
				
				break;
		}
		
		//Switch to default if an animation is almost over
		if (playerAnimation[currentAttack.name].time > (playerAnimation[currentAttack.name].length +delayTime)){
			actionState = ActionState.None;
			currentAttack = playerAnimation["AttackStandy"].clip;
			playerAnimation.CrossFade("AttackStandy", 0.5f);
		}
	}
	
	void Awake(){
		//程序开启前,获取人物动画组件;
		playerAnimation = GetComponent () as Animation;
		playerAnimation["Attack"].speed=1.6f;
		playerAnimation["Attack01"].speed=1.3f;
		playerAnimation["Attack02"].speed=1.2f;
		playerAnimation["Attack03"].speed=1.5f;
	}
	
	protected void Initialise (){
		
	}
	
	void Start () {
		
		if (playerAnimation.clip) {
			currentAttack = playerAnimation.clip;
		} else {
			currentAttack = playerAnimation["AttackStandy"].clip;
		}
		
	}
	
	// Update is called once per frame
	void Update () {
		if (currentAttack != null){
			AttackLogic();
			Attacks();
		}
		
	}
}

using UnityEngine;
using System.Collections;

/**
 *所有player事件统一处理的单例事例;
 *
 */
public class PlayerDelegate : MonoBehaviour {
	//攻击脚本;
	PlayerAttackController playerAc;
	//刀的轨迹脚本;
	SwordTrial swordTrial;
	
	// Use this for initialization
	void Start () {
		swordTrial = GetComponent() as SwordTrial;
		playerAc = GetComponent() as PlayerAttackController;
		playerAc.setAttackState +=setAttackState;
	}
	
	void setAttackState(string str){
		swordTrial.setAttackState(str);
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

using UnityEngine;
using System.Collections;

public class SwordTrial : MonoBehaviour {
	//MeleeTrailSample
	public MeleeWeaponTrail _trail;
	//记录当前动画Clip;
	public AnimationState _animationState;
	//记录当前动画帧数;
	float currentFrame =0.0f;
	//开始动画帧数;
	float startTime = 0.0f;
	//结束动画帧数;
	float endTime = 0.0f;
	//记录攻击状态;
	private string actionState="None";
	
	void Start () {
		//初始化trail不可见;
		_trail.Emit = false;
	}
	
	/**
	 * 外部调用改变攻击状态;
	 */
	public void setAttackState(string str){
		actionState = str;
		_animationState = animation[actionState];
	}
	
	// Update is called once per frame
	void Update () {
		if(actionState!="None"){
			if(animation.IsPlaying(actionState)){
				if(actionState=="Attack"){
					startTime = 0.72f;
					endTime = 0.85f;
				}else if(actionState=="Attack01"){
					startTime = 0.95f;
					endTime = 1.5f;
				}else if(actionState=="Attack02"){
					startTime =0.05f;
					endTime = 1.2f;
				}else if(actionState=="Attack03"){
					startTime =0.45f;
					endTime = 0.58f;
				}
				currentFrame=_animationState.normalizedTime*_animationState.clip.length;
				if(currentFrame>=startTime&¤tFrame<=endTime){
					_trail.Emit = true;
				}else{
					_trail.Emit = false;
					
				}
			}
		}else{
			_trail.Emit = false;
			
		}
	}
}

#define USE_INTERPOLATION

//
// By Anomalous Underdog, 2011
//
// Based on code made by Forest Johnson (Yoggy) and xyber
//

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class MeleeWeaponTrail : MonoBehaviour
{
	[SerializeField]
	bool _emit = true;
	public bool Emit { set{_emit = value;} }

	bool _use = true;
	public bool Use { set{_use = value;} }

	[SerializeField]
	float _emitTime = 0.0f;

	[SerializeField]
	Material _material;

	[SerializeField]
	float _lifeTime = 1.0f;

	[SerializeField]
	Color[] _colors;

	[SerializeField]
	float[] _sizes;

	[SerializeField]
	float _minVertexDistance = 0.1f;
	[SerializeField]
	float _maxVertexDistance = 10.0f;

	float _minVertexDistanceSqr = 0.0f;
	float _maxVertexDistanceSqr = 0.0f;

	[SerializeField]
	float _maxAngle = 3.00f;

	[SerializeField]
	bool _autoDestruct = false;

#if USE_INTERPOLATION
	[SerializeField]
	int subdivisions = 4;
#endif

	[SerializeField]
	Transform _base;
	[SerializeField]
	Transform _tip;

	List _points = new List();
#if USE_INTERPOLATION
	List _smoothedPoints = new List();
#endif
	GameObject _trailObject;
	Mesh _trailMesh;
	Vector3 _lastPosition;

	[System.Serializable]
	public class Point
	{
		public float timeCreated = 0.0f;
		public Vector3 basePosition;
		public Vector3 tipPosition;
	}

	void Start()
	{
		_lastPosition = transform.position;
		_trailObject = new GameObject("Trail");
		_trailObject.transform.parent = null;
		_trailObject.transform.position = Vector3.zero;
		_trailObject.transform.rotation = Quaternion.identity;
		_trailObject.transform.localScale = Vector3.one;
		_trailObject.AddComponent(typeof(MeshFilter));
		_trailObject.AddComponent(typeof(MeshRenderer));
		_trailObject.renderer.material = _material;

		_trailMesh = new Mesh();
		_trailMesh.name = name + "TrailMesh";
		_trailObject.GetComponent().mesh = _trailMesh;

		_minVertexDistanceSqr = _minVertexDistance * _minVertexDistance;
		_maxVertexDistanceSqr = _maxVertexDistance * _maxVertexDistance;
	}

	void OnDisable()
	{
		Destroy(_trailObject);
	}

	void Update()
	{
		if (!_use)
		{
			return;
		}

		if (_emit && _emitTime != 0)
		{
			_emitTime -= Time.deltaTime;
			if (_emitTime == 0) _emitTime = -1;
			if (_emitTime < 0) _emit = false;
		}

		if (_emit==false && _points.Count == 0 && _autoDestruct)
		{
			Destroy(_trailObject);
			Destroy(gameObject);
		}

		// early out if there is no camera
		if (!Camera.main) return;

		// if we have moved enough, create a new vertex and make sure we rebuild the mesh
		float theDistanceSqr = (_lastPosition - transform.position).sqrMagnitude;
		if (_emit)
		{
			if (theDistanceSqr > _minVertexDistanceSqr)
			{
				bool make = false;
				if (_points.Count < 3)
				{
					make = true;
				}
				else
				{
					//Vector3 l1 = _points[_points.Count - 2].basePosition - _points[_points.Count - 3].basePosition;
					//Vector3 l2 = _points[_points.Count - 1].basePosition - _points[_points.Count - 2].basePosition;
					Vector3 l1 = _points[_points.Count - 2].tipPosition - _points[_points.Count - 3].tipPosition;
					Vector3 l2 = _points[_points.Count - 1].tipPosition - _points[_points.Count - 2].tipPosition;
					if (Vector3.Angle(l1, l2) > _maxAngle || theDistanceSqr > _maxVertexDistanceSqr) make = true;
				}

				if (make)
				{
					Point p = new Point();
					p.basePosition = _base.position;
					p.tipPosition = _tip.position;
					p.timeCreated = Time.time;
					_points.Add(p);
					_lastPosition = transform.position;


#if USE_INTERPOLATION
					if (_points.Count == 1)
					{
						_smoothedPoints.Add(p);
					}
					else if (_points.Count > 1)
					{
						// add 1+subdivisions for every possible pair in the _points
						for (int n = 0; n < 1+subdivisions; ++n)
							_smoothedPoints.Add(p);
					}

					// we use 4 control points for the smoothing
					if (_points.Count >= 4)
					{
						Vector3[] tipPoints = new Vector3[4];
						tipPoints[0] = _points[_points.Count - 4].tipPosition;
						tipPoints[1] = _points[_points.Count - 3].tipPosition;
						tipPoints[2] = _points[_points.Count - 2].tipPosition;
						tipPoints[3] = _points[_points.Count - 1].tipPosition;

						//IEnumerable smoothTip = Interpolate.NewBezier(Interpolate.Ease(Interpolate.EaseType.Linear), tipPoints, subdivisions);
						IEnumerable smoothTip = Interpolate.NewCatmullRom(tipPoints, subdivisions, false);

						Vector3[] basePoints = new Vector3[4];
						basePoints[0] = _points[_points.Count - 4].basePosition;
						basePoints[1] = _points[_points.Count - 3].basePosition;
						basePoints[2] = _points[_points.Count - 2].basePosition;
						basePoints[3] = _points[_points.Count - 1].basePosition;

						//IEnumerable smoothBase = Interpolate.NewBezier(Interpolate.Ease(Interpolate.EaseType.Linear), basePoints, subdivisions);
						IEnumerable smoothBase = Interpolate.NewCatmullRom(basePoints, subdivisions, false);

						List smoothTipList = new List(smoothTip);
						List smoothBaseList = new List(smoothBase);

						float firstTime = _points[_points.Count - 4].timeCreated;
						float secondTime = _points[_points.Count - 1].timeCreated;

						//Debug.Log(" smoothTipList.Count: " + smoothTipList.Count);

						for (int n = 0; n < smoothTipList.Count; ++n)
						{

							int idx = _smoothedPoints.Count - (smoothTipList.Count-n);
							// there are moments when the _smoothedPoints are lesser
							// than what is required, when elements from it are removed
							if (idx > -1 && idx < _smoothedPoints.Count)
							{
								Point sp = new Point();
								sp.basePosition = smoothBaseList[n];
								sp.tipPosition = smoothTipList[n];
								sp.timeCreated = Mathf.Lerp(firstTime, secondTime, (float)n/smoothTipList.Count);
								_smoothedPoints[idx] = sp;
							}
							//else
							//{
							//	Debug.LogError(idx + "/" + _smoothedPoints.Count);
							//}
						}
					}
#endif
				}
				else
				{
					_points[_points.Count - 1].basePosition = _base.position;
					_points[_points.Count - 1].tipPosition = _tip.position;
					//_points[_points.Count - 1].timeCreated = Time.time;

#if USE_INTERPOLATION
					_smoothedPoints[_smoothedPoints.Count - 1].basePosition = _base.position;
					_smoothedPoints[_smoothedPoints.Count - 1].tipPosition = _tip.position;
#endif
				}
			}
			else
			{
				if (_points.Count > 0)
				{
					_points[_points.Count - 1].basePosition = _base.position;
					_points[_points.Count - 1].tipPosition = _tip.position;
					//_points[_points.Count - 1].timeCreated = Time.time;
				}

#if USE_INTERPOLATION
				if (_smoothedPoints.Count > 0)
				{
					_smoothedPoints[_smoothedPoints.Count - 1].basePosition = _base.position;
					_smoothedPoints[_smoothedPoints.Count - 1].tipPosition = _tip.position;
				}
#endif
			}
		}



		RemoveOldPoints(_points);
		if (_points.Count == 0)
		{
			_trailMesh.Clear();
		}

#if USE_INTERPOLATION
		RemoveOldPoints(_smoothedPoints);
		if (_smoothedPoints.Count == 0)
		{
			_trailMesh.Clear();
		}
#endif


#if USE_INTERPOLATION
		List pointsToUse = _smoothedPoints;
#else
		List pointsToUse = _points;
#endif

		if (pointsToUse.Count > 1)
		{
			Vector3[] newVertices = new Vector3[pointsToUse.Count * 2];
			Vector2[] newUV = new Vector2[pointsToUse.Count * 2];
			int[] newTriangles = new int[(pointsToUse.Count - 1) * 6];
			Color[] newColors = new Color[pointsToUse.Count * 2];

			for (int n = 0; n < pointsToUse.Count; ++n)
			{
				Point p = pointsToUse[n];
				float time = (Time.time - p.timeCreated) / _lifeTime;

				Color color = Color.Lerp(Color.white, Color.clear, time);
				if (_colors != null && _colors.Length > 0)
				{
					float colorTime = time * (_colors.Length - 1);
					float min = Mathf.Floor(colorTime);
					float max = Mathf.Clamp(Mathf.Ceil(colorTime), 1, _colors.Length - 1);
					float lerp = Mathf.InverseLerp(min, max, colorTime);
					if (min >= _colors.Length) min = _colors.Length - 1; if (min < 0) min = 0;
					if (max >= _colors.Length) max = _colors.Length - 1; if (max < 0) max = 0;
					color = Color.Lerp(_colors[(int)min], _colors[(int)max], lerp);
				}

				float size = 0f;
				if (_sizes != null && _sizes.Length > 0)
				{
					float sizeTime = time * (_sizes.Length - 1);
					float min = Mathf.Floor(sizeTime);
					float max = Mathf.Clamp(Mathf.Ceil(sizeTime), 1, _sizes.Length - 1);
					float lerp = Mathf.InverseLerp(min, max, sizeTime);
					if (min >= _sizes.Length) min = _sizes.Length - 1; if (min < 0) min = 0;
					if (max >= _sizes.Length) max = _sizes.Length - 1; if (max < 0) max = 0;
					size = Mathf.Lerp(_sizes[(int)min], _sizes[(int)max], lerp);
				}

				Vector3 lineDirection = p.tipPosition - p.basePosition;

				newVertices[n * 2] = p.basePosition - (lineDirection * (size * 0.5f));
				newVertices[(n * 2) + 1] = p.tipPosition + (lineDirection * (size * 0.5f));

				newColors[n * 2] = newColors[(n * 2) + 1] = color;

				float uvRatio = (float)n/pointsToUse.Count;
				newUV[n * 2] = new Vector2(uvRatio, 0);
				newUV[(n * 2) + 1] = new Vector2(uvRatio, 1);

				if (n > 0)
				{
					newTriangles[(n - 1) * 6] = (n * 2) - 2;
					newTriangles[((n - 1) * 6) + 1] = (n * 2) - 1;
					newTriangles[((n - 1) * 6) + 2] = n * 2;

					newTriangles[((n - 1) * 6) + 3] = (n * 2) + 1;
					newTriangles[((n - 1) * 6) + 4] = n * 2;
					newTriangles[((n - 1) * 6) + 5] = (n * 2) - 1;
				}
			}

			_trailMesh.Clear();
			_trailMesh.vertices = newVertices;
			_trailMesh.colors = newColors;
			_trailMesh.uv = newUV;
			_trailMesh.triangles = newTriangles;
		}
	}

	void RemoveOldPoints(List pointList)
	{
		List remove = new List();
		foreach (Point p in pointList)
		{
			// cull old points first
			if (Time.time - p.timeCreated > _lifeTime)
			{
				remove.Add(p);
			}
		}
		foreach (Point p in remove)
		{
			pointList.Remove(p);
		}
	}
}

QQ图片20131029141124.jpg(42 Bytes, 下载次数: 0)

2013-10-29 14:12:38 上传

下载次数: 0

QQ图片20131029141147.jpg(73 Bytes, 下载次数: 0)

2013-10-29 14:12:50 上传

下载次数: 0

你可能感兴趣的:(Unity3d)