当前位置: 首页 > 工具软件 > crossfade.js > 使用案例 >

我的游戏开发笔记(一):完善并把u3d自带的ThirdPersonController.js改成cs版本

宗政博文
2023-12-01

刚开始学习u3d,u3d自带的ThirdPersonController.js实在是看得不太懂,而且动作实在太少了,想做一个动作类游戏都做不成。

今天初步把它改成了cs版本,并随便加了几个动作,以便后期使用。

每天奋斗一点点

.

using UnityEngine;
using System.Collections;

public class ThirdPersonControl : MonoBehaviour {

    #region 动作片段
    public AnimationClip idleAnimation;
    public AnimationClip walkAnimation;
    public AnimationClip runAnimation;
    public AnimationClip jumpPoseAnimation;
    public AnimationClip jumpFallAnimation;
    public AnimationClip kickAnimation;
    public AnimationClip utimateAnimation;
    private Animation _animation; 
    #endregion

    #region 动作片段枚举值
    enum CharacterState
    {
        Idle = 0,
        Walking = 1,
        Trotting = 2,
        Running = 3,
        Jumping = 4,
        Falling = 5,
        Kicking = 6,
        Utimate = 7
    } 
    #endregion

    #region 最大限速
    public float walkMaxAnimationSpeed = 0.75f;
    public float trotMaxAnimationSpeed = 1.0f;
    public float runMaxAnimationSpeed = 1.0f;
    public float jumpAnimationSpeed = 1.15f;
    public float landAnimationSpeed = 1.0f;
    public float kickMaxAnimationSpeed = 0.8f; 
    #endregion

    //判断游戏是否开始
    public static int jug = 0;
    
    //判断角色状态
    private CharacterState _characterState;

    #region 角色在做什么
    // Are we jumping? (Initiated with jump button and not grounded yet)
    //是否正在跳跃
    public bool jumping = false;
    private bool jumpingReachedApex = false;
    //是否正在踢人
    public bool kicking = false;
    //是否正在放大
    public bool utimating = false;
    //各种状态
    public bool slow = false;
    #endregion

    #region 记录动作开始时间以及各种参数
    // When did the user start walking (Used for going into trot after a while)
    //走路开始时间,一段时间后进入快跑状态
    private float walkTimeStart = 0.0f;
    // Last time the jump button was clicked down
    //最后一次按“跳跃按键的时间”
    private float lastJumpButtonTime = -10.0f;
    //跳
    private float lastJumpTime = -1.0f;
    //踢
    private float lastKickTime = -1.0f;
    //绝技
    private float lastUtimateTime = -0.1f;
    // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
    //记录最后一次跳跃时的高度(高度过高会受伤之类的)
    private float lastJumpStartHeight = 0.0f;
    //绝技
    private float lastUtimateStartHeight = 0.0f;
    //落地
    private float lastGroundedTime = 0.0f;
    //跳跃参数
    private float jumpRepeatTime = 0.05f;
    private float jumpTimeout = 0.15f;
    private float groundedTimeout = 0.25f;
    //减速时间
    public float slowTime=0.0f;
    #endregion

    #region 角色基本属性,可以外部修改
    // The speed when walking
    public float walkSpeed = 2.0f;
    // after trotAfterSeconds of walking we trot with trotSpeed
    public float trotSpeed = 4.0f;
    // when pressing "Fire3" button (cmd) we start running
    public float runSpeed = 6.0f;
    public float kickSpeed = 3.0f;
    //????
    public float inAirControlAcceleration = 3.0f;
    // How high do we jump when pressing jump and letting go immediately
    public float jumpHeight = 0.5f;
    // The gravity for the character
    public float gravity = 20.0f;
    // The gravity in controlled descent mode
    public float speedSmoothing = 10.0f;
    public float rotateSpeed = 500.0f;
    public float trotAfterSeconds = 3.0f;
    //可跳与否
    public bool canJump = true;
    #endregion

    #region 各种私有变量
    // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
    private float lockCameraTimer = 0.0f;
    // The current move direction in x-z
    private Vector3 moveDirection = Vector3.zero;
    // The current vertical speed
    private float verticalSpeed = 0.0f;
    // The current x-z move speed
    private float moveSpeed = 0.0f;
    // The last collision flags returned from controller.Move
    private CollisionFlags collisionFlags;
    // Are we moving backwards (This locks the camera to not do a 180 degree spin)
    //是否往回走
    private bool movingBack = false;
    // Is the user pressing any keys?
    private bool isMoving = false;
    private Vector3 inAirVelocity = Vector3.zero;
    //是否可以控制
    private bool isControllable = true; 
    #endregion

    void Awake ()
    {
	    moveDirection = transform.TransformDirection(Vector3.forward);
	
	    _animation = gameObject.GetComponent<Animation>();
        //若没有animation组件则报错
	    if(!_animation)
		    Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird.");

        //检查各个Animation是否都存在对应动作
	    if(!idleAnimation) {
		    _animation = null;
		    Debug.Log("No idle animation found. Turning off animations.");
	    }
	    if(!walkAnimation) {
		    _animation = null;
		    Debug.Log("No walk animation found. Turning off animations.");
	    }
	    if(!runAnimation) {
		    _animation = null;
		    Debug.Log("No run animation found. Turning off animations.");
	    }
	    if(!jumpPoseAnimation && canJump) {
		    _animation = null;
		    Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations.");
	    }	
        if(!jumpFallAnimation) {
		    _animation = null;
		    Debug.Log("No fall animation found and the character has canJump enabled. Turning off animations.");
	    }
        if(!kickAnimation) {
		    _animation = null;
		    Debug.Log("No kick animation found. Turning off animations.");
	    }
        if(!utimateAnimation) {
		    _animation = null;
		    Debug.Log("No utimate animation found. Turning off animations.");
	    }		
    }

    void UpdateSmoothedMovementDirection ()
    {
        //找到主摄像机的位置
	    Transform cameraTransform = Camera.main.transform;
        //与操作,返回值为bool型,1为在地上,0为在空中
	    bool grounded = IsGrounded();
	
	    // Forward vector relative to the camera along the x-z plane	
        //找到摄像机向前一步的向量,并把向量中的y置0
	    Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
	    forward.y = 0;
	    forward = forward.normalized;

	    // Right vector relative to the camera
	    // Always orthogonal to the forward vector
        //跟着摄像机的移动方向往右走
	    Vector3 right = new Vector3(forward.z, 0, -forward.x);

        //获得水平移动和垂直移动的float值
	    float v = Input.GetAxisRaw("Vertical");
	    float h = Input.GetAxisRaw("Horizontal");

	    // Are we moving backwards or looking backwards
        //若垂直移动距离太小,movingBack值置为true,意思是已进行后移
	    if (v < -0.2)
		    movingBack = true;
	    else
		    movingBack = false;
	
        //wasMoving存isMoving,表示是否正在移动
	    bool wasMoving = isMoving;
        //或操作,若水平移动或者垂直移动的绝对值>0.1,则返回1,表示正在移动0
	    isMoving = Mathf.Abs (h) > 0.1 || Mathf.Abs (v) > 0.1;
		
	    // Target direction relative to the camera
        //
	    Vector3 targetDirection = h * right + v * forward;
	
	    // Grounded controls
        //若在地上
	    if (grounded && !kicking)
	    {
		    // Lock camera for short period when transitioning moving & standing still
            //控制对应的ThirdPerson Camera 本游戏用不到
		    lockCameraTimer += Time.deltaTime;
		    if (isMoving != wasMoving)
			    lockCameraTimer = 0.0f;

		    // We store speed and direction seperately,
		    // so that when the character stands still we still have a valid forward direction
		    // moveDirection is always normalized, and we only update it if there is user input.
		    if (targetDirection != Vector3.zero)
		    {
			    // If we are really slow, just snap to the target direction
			    if (moveSpeed < walkSpeed * 0.9 && grounded)
			    {
				    moveDirection = targetDirection.normalized;
			    }
			    // Otherwise smoothly turn towards it
			    else
			    {
				    moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000);
				
				    moveDirection = moveDirection.normalized;
			    }
		    }
		
		    // Smooth the speed based on the current target direction
		    float curSmooth = speedSmoothing * Time.deltaTime;
		
		    // Choose target speed
		    //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
		    float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f);
	
		    _characterState = CharacterState.Idle;
		
		    // Pick speed modifier
		    if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift))
		    {
			    targetSpeed *= runSpeed;
			    _characterState = CharacterState.Running;
		    }
		    else if (Time.time - trotAfterSeconds > walkTimeStart)
		    {
			    targetSpeed *= trotSpeed;
			    _characterState = CharacterState.Trotting;
		    }
		    else
		    {
			    targetSpeed *= walkSpeed;
			    _characterState = CharacterState.Walking;
		    }
		
		    moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
		
		    // Reset walk time start when we slow down
		    if (moveSpeed < walkSpeed * 0.3)
			    walkTimeStart = Time.time;
	    }
	    // In air controls
	    else
	    {
		    // Lock camera while in air
		    if (jumping)
			    lockCameraTimer = 0.0f;

		    if (isMoving)
			    inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration;
	    }		
    }

    void ApplyJumping ()
    {
	    // Prevent jumping too fast after each other
        //设置一个时间间隔,这里为Time.time,在这间隔内不能连续跳跃
	    if (lastJumpTime + jumpRepeatTime > Time.time)
		    return;

	    if (IsGrounded()&&!utimating&&!kicking) {
		    // Jump
		    // - Only when pressing the button down
		    // - With a timeout so you can press the button slightly before landing		
            //若可以跳跃,则跳
		    if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) {
			    verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
			    SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
		    }
	    }
    }

    void ApplyGravity ()
    {
        //若角色处于可控状态
	    if (isControllable&&!utimating)	// don't move player at all if not controllable.
	    {
		    // Apply gravity
		    var jumpButton = Input.GetButton("Jump");
		
		    // When we reach the apex of the jump we send out a message
            //若jumping、并没有达到跳跃最高点、垂直速度<0
		    if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0)
		    {
                //把角色已到达最高点置为真
			    jumpingReachedApex = true;
                //执行DidJumpReachApex,这里没有
			    SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
		    }
	    
            //若已到达地面
		    if (IsGrounded ())
            //垂直速度置0
			    verticalSpeed = 0.0f;
		    else
            //若没到达地面,设置下落速度
			    verticalSpeed -= gravity * Time.deltaTime;
	    }
    }

    void ApplyKicking()
    {
	    if (lastKickTime + 0.5 > Time.time)
		    return;
        if (IsGrounded()&&!kicking) 
        {
		    SendMessage("DidKick", SendMessageOptions.DontRequireReceiver);
        }
    }

    void ApplyUtimating()
    {
	    if (lastUtimateTime + 0.5 > Time.time)
		    return;

        if(!IsGrounded())
        {
            SendMessage("DidUtimate", SendMessageOptions.DontRequireReceiver);   
        }
    }

    float CalculateJumpVerticalSpeed (float targetJumpHeight)
    {
	    // From the jump height and gravity we deduce the upwards speed 
	    // for the character to reach at the apex.
	    return Mathf.Sqrt(2 * targetJumpHeight * gravity);
    }
    void DidJump ()
    {
	    jumping = true;
	    jumpingReachedApex = false;
	    lastJumpTime = Time.time;
	    lastJumpStartHeight = transform.position.y;
	    lastJumpButtonTime = -10;

	    _characterState = CharacterState.Jumping;
    }

    void DidKick()
    {
        kicking = true;
         lastKickTime = Time.time;
        _characterState = CharacterState.Kicking;
    }

    void DidUtimate()
    {
        utimating=true;
        lastUtimateTime = Time.time;
        lastUtimateStartHeight = transform.position.y;
        _characterState = CharacterState.Utimate;
    }

    void Update() {
    if(jug==1){
        //如果不能控制,则重置输入轴
	    if (!isControllable)
	    {
		    // kill all inputs if not controllable.
		    Input.ResetInputAxes();
	    }

        //如果按下跳(就是空格)键,把最后起跳时间记录下来
	    if (Input.GetButtonDown ("Jump"))
	    {
		    lastJumpButtonTime = Time.time;
	    }

        //这东西是对对应ThirdPersonCamera的摄像机的位置进行修正,本游戏用不到
	    UpdateSmoothedMovementDirection();
	
	    // Apply gravity
	    // - extra power jump modifies gravity
	    // - controlledDescent mode modifies gravity
	    ApplyGravity ();

	    // Apply jumping logic
	    ApplyJumping ();

        if(Input.GetKeyDown(KeyCode.K))
        {
            ApplyUtimating();
        }

        if(Input.GetKeyDown(KeyCode.J))
        {
            ApplyKicking();
        }
	
	    // Calculate actual motion
        //计算角色的移动向量
	    var movement = moveDirection * moveSpeed +  new Vector3 (0, verticalSpeed, 0) + inAirVelocity;
	    movement *= Time.deltaTime;
	
	    // Move the controller
        //移动角色
	    CharacterController controller = gameObject.GetComponent<CharacterController>();
	    collisionFlags = controller.Move(movement);
	
	    // ANIMATION sector
        //若每一个动作片段都存在
	    if(_animation) {
            //若角色的状态处于跳跃状态
		    if(_characterState == CharacterState.Jumping) 
		    {
                //若没到达跳跃顶峰
			    if(!jumpingReachedApex) {
                    //执行跳跃动作
				    _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;
                    //重复执行这一动作直到结束
				    _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
				    _animation.CrossFade(jumpPoseAnimation.name);
			    } else {
                //若已到达顶峰
                    //执行下落动作
				    _animation[jumpFallAnimation.name].speed = -landAnimationSpeed;
                    //重复执行这一动作直到结束
				    _animation[jumpFallAnimation.name].wrapMode = WrapMode.ClampForever;
				    _animation.CrossFade(jumpFallAnimation.name);				
			    }
		    } 
            else if(_characterState == CharacterState.Kicking)
            {
            //若处于踢人状态
                if(Time.time - lastKickTime<0.8)
                {
                    _animation[kickAnimation.name].speed = kickMaxAnimationSpeed;
			        _animation[kickAnimation.name].wrapMode = WrapMode.Loop;
			        _animation.CrossFade(kickAnimation.name);
                }else
                {
                    //lastKickTime = Time.time;
                    kicking = false;
                }
            }
            else if(_characterState == CharacterState.Utimate)
            {
                //若处于放大招状态
                if(Time.time - lastUtimateTime<0.5)
                {
                    //_animation[utimateAnimation.name].speed = jumpAnimationSpeed;
                    Vector3 newY = transform.position;
                    newY.y = lastUtimateStartHeight;
                    transform.position = newY;
	                _animation[utimateAnimation.name].wrapMode = WrapMode.ClampForever;
	                _animation.CrossFade(utimateAnimation.name);
                    verticalSpeed -= gravity * Time.deltaTime*0.5f;
                 
                }else{
                    utimating=false;
                    jumpingReachedApex = true;
                    _characterState = CharacterState.Jumping;
                }
            }
		    else 
		    {
                //若不处于跳跃状态
                //若角色的运行向量开方小于0.1,执行Idle动作
			    if(controller.velocity.sqrMagnitude < 0.1) {
				    _animation.CrossFade(idleAnimation.name);
			    }
			    else 
			    {
                //若角色的运行向量开方大于0.1
                    //若角色处于奔跑状态
				    if(_characterState == CharacterState.Running) {
					    _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, runMaxAnimationSpeed);
					    _animation.CrossFade(runAnimation.name);	
				    }
                    //若处于快步走状态
				    else if(_characterState == CharacterState.Trotting) {
					    _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, trotMaxAnimationSpeed);
					    _animation.CrossFade(walkAnimation.name);	
				    }
                    //若处于走路状态
				    else if(_characterState == CharacterState.Walking) {
					    _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, walkMaxAnimationSpeed);
					    _animation.CrossFade(walkAnimation.name);	
				    }
			    }
		    }
	    }
	    // ANIMATION sector
	
	    // Set rotation to the move direction
	    if (IsGrounded())
	    {
		
		    transform.rotation = Quaternion.LookRotation(moveDirection);
			
	    }	
	    else
	    {
		    var xzMove = movement;
		    xzMove.y = 0;
		    if (xzMove.sqrMagnitude > 0.001)
		    {
			    transform.rotation = Quaternion.LookRotation(xzMove);
		    }
	    }	
	
	    // We are in jump mode but just became grounded
	    if (IsGrounded())
	    {
		    lastGroundedTime = Time.time;
		    inAirVelocity = Vector3.zero;
		    if (jumping)
		    {
			    jumping = false;
			    SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
		    }
	    }
        }
    }

    void OnControllerColliderHit (ControllerColliderHit hit )
    {
    //	Debug.DrawRay(hit.point, hit.normal);
	    if (hit.moveDirection.y > 0.01) 
		    return;
    }

    float GetSpeed () {
	    return moveSpeed;
    }

    bool IsJumping () {
	    return jumping;
    }

    bool IsGrounded () {
	    return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
    }

    Vector3 GetDirection () {
	    return moveDirection;
    }

    bool IsMovingBackwards () {
	    return movingBack;
    }

    float GetLockCameraTimer () 
    {
	    return lockCameraTimer;
    }

    bool IsMoving ()
    {
	    return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5;
    }

    bool HasJumpReachedApex ()
    {
	    return jumpingReachedApex;
    }

    bool IsGroundedWithTimeout ()
    {
	    return lastGroundedTime + groundedTimeout > Time.time;
    }

    void Reset ()
    {
	    gameObject.tag = "Player";
    }
}

.

存此记录我的游戏开发过程。



 类似资料: