zoukankan      html  css  js  c++  java
  • [Unity3D]Unity3D游戏开发之ACT游戏三连击效果实现综述

            各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在研究了Unity3D Mecanim动画系统的重定向特性后,今天我们继续来探索Mecanim动画系统很多其它的特性吧。今天博主想和大家分享的是ACT游戏中的三连击效果的实现,因为Unity3D眼下存在Animation和Animator两种类型的动画组件,因此本文将分别讲这两种类型的动画组件的三连击效果的实现,当中Animation组件是Unity3.5以下版本号所使用的动画组件,Animator组件是眼下Unity3D的Mecanim动画系统所使用的动画组件。
      我们首先来了解三连击效果的详细流程,假定角色当前处于Idle状态,此时玩家假设按下攻击键则进入Attack1状态,假设在规定的时间内,玩家继续按下攻击键则进入Attack2状态,否则返回到Idle状态;同理,假设角色处于Attack2状态,假设此时玩家按下攻击键则进入Attack3状态,否则返回Idle状态;当Attack3状态结束后,将返回到Idle状态,等待玩家触发下一次攻击。由此我们能够归纳出三连击的状态变化:
    (1)Idle->Attack1->Idle
    (2)Idle->Attack1->Attack2->Idle
    (3)Idle->Attack1->Attack->Attack3->Idle
           通过状态变化情况我们能够考虑使用两种思路来实现三连击效果。第一种思路是,各状态动画相互独立,通过状态切换来实现总体的动画效果。另外一种思路是,美工人员将各状态动画以序列形式,程序设计人员依据时间来控制动画效果。今天我们主要採用第一种方法,目的是领会游戏设计中的有限状态机思想,将其更好的应用到游戏开发中。好了,以下我们正式開始今天的内容吧!


             一、Animator组件篇

            Animator组件是Unity3DMecanim动画系统所使用的动画组件。这个组件通过Animator Controller来实现对动画的控制。如图是我们今天项目的主角,一个左手持盾,右手持剑的女战士。


        我们首先来创建一个Animator Controller并将其命名为SwordGirlController,双击打开Animator窗体,依照我们对状态变化情况的讨论,我们能够非常easy地设计出以下的状态模型:


        在这里我们定义一个整型变量ActionID,其默认值为0。当ActionID的值为1时角色由Idle切换到Attack1,当ActionID的值为2时角色由Attack1切换到Attack2,当ActionID3时角色由Attack2切换到Attack3。全部的指向Idle的连线的切换条件是ActionID的值为0。这样我们就建立了一个动画切换的状态模型。好了,以下我们来编写脚本实现对动画的控制:

    //基于Mecanim动画系统的三连击效果,眼下最大的问题就是玩家在攻击后无法
    //自己主动恢复到Idle状态,须要运行一次攻击才干够回到Idle状态
    
    using UnityEngine;
    using System.Collections;
    
    public class SwordGirlScript : MonoBehaviour {
    
    	//Mecanim动画组件
    	private Animator mAnimator=null;
    	//动画状态信息
    	private AnimatorStateInfo mStateInfo;
    	//定义状态常量值,前面不要带层名啊,否则无法推断动画状态
    	private const string IdleState="Idle";
    	private const string Attack1State="Attack1";
    	private const string Attack2State="Attack2";
    	private const string Attack3State="Attack3";
    
    	//定义玩家连击次数
    	private int mHitCount=0;
    	
    	void Start () 
    	{
    		//获取动画组件
    		mAnimator=GetComponent<Animator>();
    		//获取状态信息
    		mStateInfo=mAnimator.GetCurrentAnimatorStateInfo(0);
    	}
    
    	void Update () 
    	{
    	    //假设玩家处于攻击状态,且攻击已经完毕,则返回到Idle状态
    		if(!mStateInfo.IsName(IdleState) && mStateInfo.normalizedTime>1.0F)
    		{
    			mAnimator.SetInteger("ActionID",0);
    			mHitCount=0;
    		}
            //假设按下鼠标左键,则開始攻击
    		if(Input.GetMouseButton(0))
    		{
    	        Attack();
    		}
    	}
    
    	void Attack()
    	{
    	   //获取状态信息
    	   mStateInfo=mAnimator.GetCurrentAnimatorStateInfo(0);
    	   //假设玩家处于Idle状态且攻击次数为0,则玩家依照攻击招式1攻击,否则依照攻击招式2攻击,否则依照攻击招式3攻击
    	   if(mStateInfo.IsName(IdleState) && mHitCount==0 && mStateInfo.normalizedTime>0.50F)
    	   {
    		  mAnimator.SetInteger("ActionID",1);
    		  mHitCount=1;
    	   }else if(mStateInfo.IsName(Attack1State) && mHitCount==1 && mStateInfo.normalizedTime>0.65F)
    	   {
    		  mAnimator.SetInteger("ActionID",2);
    		  mHitCount=2;
    	   }else if(mStateInfo.IsName(Attack2State)&& mHitCount==2 && mStateInfo.normalizedTime>0.70F)
    	   {
    		  mAnimator.SetInteger("ActionID",3);
    	      mHitCount=3;
    		}
    	}
    }

          这样我们就能够实现ACT游戏中的三连击效果了,我们一起来看看终于的效果吧!


       博主在实际測试的过程中发现角色在运行一次攻击后无法自己主动恢复到Idle状态,除非玩家继续按下攻击键,博主眼下并没有找到解决的办法,假设各位朋友知道详细原因的话,一定要告诉博主啊,哈哈。


            二、Animation组件篇

            我们知道Mecanim动画系统是通过状态机来实现对动画的控制的,而在3.5版本号曾经的Unity3D所採用的动画系统呢,依照博主的理解,事实上就是一种无状态的动画,我们只能通过动画片段的名称来决定播放某一个动画片段或者在一个确定的时间内进行动画的切换。因此,假设我们希望使用Animation组件来实现三连击效果的话,就必须在该组件的基础上实现一个状态机的结构。依据開始讨论的结果,我们知道整个三连击过程中有四个状态Attack1Attack2Attack3Idle,由此我们能够定义一个动画状态的枚举类型ActionState。接下来我们就能够依据这个状态值来切换攻击动画,实现三连击的效果,我们一起来看脚本:

    using UnityEngine;
    using System.Collections;
     
    public class AttackScripts : MonoBehaviour {
    
        //当前攻击动画;
        AnimationClip currentClip;
        //动画组件;
        Animation mAnimation;
    
        //动画状态枚举
        public enum ActionState
        {
            Attack1,
            Attack2,
            Attack3,
            None
        }
    
        //当前动画状态;
        private ActionState mState = ActionState.None;
         
        //攻击触发
        void AttackTrigger(){
            if (Input.GetMouseButton(0)){
                if (mState != ActionState.Attack1 && mState != ActionState.Attack2 && mState != ActionState.Attack3 ) {
                    mState = ActionState.Attack1;
                }else if (mState == ActionState.Attack1 &&  mState != ActionState.Attack2 && mState != ActionState.Attack3 
                    && mAnimation[currentClip.name].time > 1.0F){
                    mState = ActionState.Attack2;
                }else if (mState == ActionState.Attack2 &&  mState != ActionState.Attack1 && mState != ActionState.Attack3   
                    && mAnimation[currentClip.name].time > 1.0F){
                    mState = ActionState.Attack2;
                }
            }
        }
         
        //攻击套路
        void Attacks (){
            float delayTime =0.0F;
            switch (mState){
                case ActionState.Attack1:
                    delayTime = -0.1F;
                    mAnimation.CrossFade("Attack1", 0.15F);
                    currentClip = mAnimation["Attack1"].clip;
                    break;
                     
                case ActionState.Attack2:
                    delayTime = -0.1f;
                    mAnimation.CrossFade("Attack2", 0.15F);
                    currentClip = mAnimation["Attack2"].clip;
                    break;
    
                case ActionState.Attack3:
                    delayTime = -0.1f;
                    mAnimation.CrossFade("Attack3", 0.15F);
                    currentClip = mAnimation["Attack3"].clip;
                    break;
                     
                case ActionState.None:
                    break;
            }
             
            //假设攻击动画播放完就切换到Idle状态
            if (mAnimation[currentClip.name].time > (mAnimation[currentClip.name].length +delayTime)){
                mState = ActionState.None;
                currentClip = mAnimation["Idle"].clip;
            }
        }
         
        void Awake(){
            //获取动画组件;
            mAnimation = GetComponent<Animation>();
        }
         
        void Start () {
            if (mAnimation.clip) {
                currentClip = mAnimation.clip;
            } else {
                currentClip = mAnimation["Idle"].clip;
            }
        }
         
        void Update () {
            if (currentClip != null){
                AttackTrigger();
                Attacks();
            }
        }
    }

           这里的连击效果并没有设置打断,即全部的动画一次性播放完毕。假设我们在Mecanim动画系统中只保留第三种情形,那么它实现的效果是一样的,这一点希望大家注意。好了,今天的内容就是这样了,感谢大家关注我的博客,希望大家能够喜欢。


    每日箴言:无论当下的我们有没有人爱,我们都要努力做一个可爱的人。不埋怨谁,不嘲笑谁,也不羡慕谁,做自己的梦,走自己的路。



    喜欢我的博客请记住我的名字:秦元培,我博客地址是blog.csdn.net/qinyuanpei。
    转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/38023199


  • 相关阅读:
    SQL进程死锁排查
    SQL 日期转换
    SQL Server 删除日志文件
    SQL 修复表
    charindex函数--->检索字符在字符串中的起始位置
    SQL使用链接服务器执行远程数据库上的存储过程
    C# 学习第二天笔记
    C# 学习笔记第一天
    SQL Prompt 5 功能按键说明
    自定义排序(Icompare)
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4080788.html
Copyright © 2011-2022 走看看