#Unity
#C#

AoB creation blog entry #2

キャラクターを動かしよう

Coding plan

  • Manager script ( マネージャースクリプト)
  • Control input script(コントロールインプット)
  • Camera control script(カメラスクリプト)
  • Animation control script(モーション)
  • Jumping(ジャンプ)
  • Stats script(ステータス、HP、攻撃力など)
  • Combat script(コンバットスクリプト)

Scripts

Player Manager - プレヤーマネージャー

Theory
いつでもプレヤーキャラクターの存在を認識しているスクリプト。

スクリプト

qiita.rb
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerManager : MonoBehaviour {


    #region Singleton

    public static PlayerManager instance;

    void Awake() {
        instance = this;
    }

    #endregion

    public GameObject player;

}

Player Controller - プレヤーコントローラ

Theory

数学の力で、スムーズな動きを作りましょう!

1.png

Mathf.Atan2:

Tan が y/x になる角度をラジアンで返します。
戻り値は X 軸と 0 で始まり (X, Y)で終わる 2D ベクトルの角度です。
注意 この関数は X が 0 であるケースを考慮していることに注意してください。 0 で除算する例外処理よりもむしろ正しい角度を返します。

Returns the angle in radians whose Tan is y/x.
Return value is the angle between the x-axis and a 2D vector starting at zero and terminating at (x,y).
Note: This function takes account of the cases where x is zero and returns the correct angle rather than throwing a division by zero exception.

Quaternion.EulerAngles:

回転をオイラー角の値で返します。
Z 座標を軸に euler.z 度、X 座標を軸に euler.x 度、Y 座標を軸に euler.y 度 (順番はこのとおり) 回転させる回転。
*
The rotation as Euler angles in degrees.
The x, y, and z angles represent a rotation z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis (in that order).
Only use this variable to read and set the angles to absolute values. Don't increment them, as it will fail when the angle exceeds 360 degrees. Use Transform.Rotate instead.*

Rad2Deg:

ラジアンから度に変換する定数。
Radians-to-degrees conversion constant.

Script
qiita.rb
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {

    [SerializeField]
    float walkSpeed, runSpeed;

    [SerializeField]
    float turnSmoothTime = 0.2f;
    float turnSmoothVelocity;

    [SerializeField]
    float speedSmoothTime = 0.1f;
    float speedSmoothVelocity;
    float currentSpeed;

    Animator animator;

    // Use this for initialization
    void Start () {
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update () {

        Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
        Vector2 inputDir = input.normalized;

        if (inputDir != Vector2.zero)
        {
            float targetRotation = Mathf.Atan2(inputDir.x, inputDir.y) * Mathf.Rad2Deg;
            transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, turnSmoothTime);
        }

        bool running = Input.GetKey(KeyCode.LeftShift);
        float targetSpeed = ((running) ? runSpeed : walkSpeed) * inputDir.magnitude;
        currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, speedSmoothTime);

        transform.Translate(transform.forward * currentSpeed * Time.deltaTime, Space.World);

        float animationSpeedPercent = ((running) ? 1 : .5f) * inputDir.magnitude;
        animator.SetFloat("speedPercent", animationSpeedPercent, speedSmoothTime, Time.deltaTime);

    }
}

Camera

Theory

Yaw, pitch, roll

yawpitchroll.png

TPS - サードパーソンカメラ

camera3rd_freeCam.png

Script
qiita.rb
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TpsCamera : MonoBehaviour {

    public bool lockCursor;
    public float mouseSensitivity = 10f;
    public Transform target;
    public float dstFromTarget = 2;
    public Vector2 pitchMinMax = new Vector2(-40, 85);

    public float rotationSmoothTime = .12f;
    Vector3 rotationSmoothVelocity;
    Vector3 currentRotation;

    float yaw;
    float pitch;

    void Start () {
        if(lockCursor)
        {
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
        }
    }

    void LateUpdate () {
        yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
        pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
        pitch = Mathf.Clamp(pitch, pitchMinMax.x, pitchMinMax.y);

        currentRotation = Vector3.SmoothDamp(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
        transform.eulerAngles = currentRotation;
        transform.position = target.position - transform.forward * dstFromTarget;
    }
}

Jumping

qiita.rb
void Update(){
 if(Input.GetKeyDown(KeyCode.Space))
        {
            Jump();
        }
}

void Jump()
    {
        if(controller.isGrounded)
        {
            float jumpVelocity = Mathf.Sqrt(-2 * gravity * jumpHeight);
            velocityY = jumpVelocity;
        }
    }

    float GetModifiedSmoothTime( float smoothTime)
    {
        if( controller.isGrounded)
        {
            return smoothTime;
        }

        if ( airControlPercent == 0)
        {
            return float.MaxValue;
        }

        return smoothTime / airControlPercent;
    }

Animation

  • Animator Controller
  • Importing animations
  • Locomotion
  • Actions and parameters

Combat and Stats

  • HP
  • Attack power
  • Armor
  • Dodging
  • Restoring HP
  • Using items
  • Changing weapons

Player Controller Final

qiita.rb
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {

    [SerializeField]
    float walkSpeed, runSpeed, jumpHeight;

    [Range(0, 1)]
    public float airControlPercent;

    [SerializeField]
    float turnSmoothTime = 0.2f;
    float turnSmoothVelocity;

    [SerializeField]
    float speedSmoothTime = 0.1f;
    float speedSmoothVelocity;
    float currentSpeed;
    float velocityY;

    Animator animator;
    Transform cameraT;
    CharacterController controller;

    public float gravity = -12;

    // Use this for initialization
    void Start () {
        animator = GetComponent<Animator>();
        cameraT = Camera.main.transform;
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update () {

        //インプット
        Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
        Vector2 inputDir = input.normalized;

        bool running = Input.GetKey(KeyCode.LeftShift);
        Move(inputDir, running);

        if(Input.GetKeyDown(KeyCode.Space))
        {
            Jump();
        }

        //モーション
        float animationSpeedPercent = ((running) ? currentSpeed / runSpeed : currentSpeed / walkSpeed * .5f);
        animator.SetFloat("speedPercent", animationSpeedPercent, speedSmoothTime, Time.deltaTime);

    }

    void Move( Vector2 inputDir, bool running)
    {
        if (inputDir != Vector2.zero)
        {
            float targetRotation = Mathf.Atan2(inputDir.x, inputDir.y) * Mathf.Rad2Deg + cameraT.eulerAngles.y;
            transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime));
        }


        float targetSpeed = ((running) ? runSpeed : walkSpeed) * inputDir.magnitude;
        currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));

        velocityY += Time.deltaTime * gravity;

        Vector3 velocity = transform.forward * currentSpeed + Vector3.up * velocityY;
        controller.Move(velocity * Time.deltaTime);
        currentSpeed = new Vector2(controller.velocity.x, controller.velocity.z).magnitude;

        if (controller.isGrounded)
        {
            velocityY = 0;
        }


    }

    void Jump()
    {
        if(controller.isGrounded)
        {
            float jumpVelocity = Mathf.Sqrt(-2 * gravity * jumpHeight);
            velocityY = jumpVelocity;
        }
    }

    float GetModifiedSmoothTime( float smoothTime)
    {
        if( controller.isGrounded)
        {
            return smoothTime;
        }

        if ( airControlPercent == 0)
        {
            return float.MaxValue;
        }

        return smoothTime / airControlPercent;
    }
}