1

unity官方教程TANKS,难度系数中阶。
跟着官方教程学习Unity,通过本教程你可以学会使用Unity开发游戏的基本流程。

clipboard.png

一、环境

Unity 版本 > 5.2
Asset Store 里面搜索 Tanks!Tutorial ,下载导入

二、项目设置

为了便于开发,很多时候我们选用的窗口布局是 2by3 Layout,然后将 Project 面板拖动到 Hierarchy 面板下面,如下图所示

clipboard.png

三、场景设置

项目设置完毕后,就进入场景设置环节

1、新建一个场景,命名为 Main
2、删除场景中的 Directional Light
3、找到 Prefabs 文件夹下的 LevelArt,将其拖入 Hierarchy 内,这个 prefab 是我们的游戏地形
4、打开菜单 Windows->Lighting->Settings,取消 Auto Generate 和 Baked GI,将 Environment Lighting Source 改为 Color,并将颜色设置为(72,62,113),点击 Generate Lighting,这一步主要是渲染设置
5、调整 Main Camera 位置为 (-43,42,-25),旋转属性为 (40,60,0),投影改为正交 Orthographic,Clear Flags 改为 Solid Color ,Background 颜色设置为(80,60,50),Clear Flags不设置也可以,这个设置主要影响的是相机移动到看不到场景内的物体时屏幕显示的天空盒还是自己设置的 Solid Color 颜色

四、坦克设置

现在要往场景里加坦克了

1、在 Models 文件夹里面找到 Tank,将其拖拽到 Hierarchy 中
2、选中 Tank,在Inspector面板将 Layer 设置为 Players,跳出对话框时选 No,this object only
3、给 Tank 添加一个 Rigidbody Component,展开 Constraints 选项,勾选 Freeze Position Y 和 Freeze Rotation X Z,因为地面位于 XZ 平面,所以限定坦克不能在 Y 方向移动并且只能沿 Y 轴转动
4、给 Tank 添加一个 Box Collider Component,将其中心 Center 调整为(0,0.85,0),尺寸 Size 调整为(1.5,1.7,1.6)
5、给 Tank 添加两个 Audio Source Component,将第一个 Audio Source 的 AudioClip 属性填充为 Engine Idle(坦克不动时的音频),并勾选 Loop,将第二个 Audio Source 的 Play On Awake 取消
6、选中 Project 面板的 Prefabs 文件夹,将 Tank 拖入到该文件夹,至此我们就创建好了坦克 Prefab
7、将 Prefabs 文件夹中的 DustTrail 拖到 Hierarchy 面板中的 Tank 物体上,使其成为 Tank 的子物体,并Crtl + D(windows)复制一个,然后重命名为 LeftDustTrail 和 RightDustTrail,这是特效 - 坦克运动过程地面扬起的土
8、调整 LeftDustTrail 的 position 为(-0.5,0,-0.75),RightDustTrail 的position 为(0.5,0,-0.75)

以上过程便制作好了游戏主角 Tank,下面就要编程控制它运动了

1、找到 ScriptsTank 文件夹下的 TankMovement.cs,将其拖入到 Tank 物体上,打开 TankMovement.cs

public class TankMovement : MonoBehaviour
{
    public int m_PlayerNumber = 1;         
    public float m_Speed = 12f;            
    public float m_TurnSpeed = 180f;       
    public AudioSource m_MovementAudio;    
    public AudioClip m_EngineIdling;       
    public AudioClip m_EngineDriving;      
    public float m_PitchRange = 0.2f;

    /*
    private string m_MovementAxisName;     
    private string m_TurnAxisName;         
    private Rigidbody m_Rigidbody;         
    private float m_MovementInputValue;    
    private float m_TurnInputValue;        
    private float m_OriginalPitch;         


    private void Awake()
    {
        m_Rigidbody = GetComponent<Rigidbody>();
    }


    private void OnEnable ()
    {
        m_Rigidbody.isKinematic = false;
        m_MovementInputValue = 0f;
        m_TurnInputValue = 0f;
    }


    private void OnDisable ()
    {
        m_Rigidbody.isKinematic = true;
    }


    private void Start()
    {
        m_MovementAxisName = "Vertical" + m_PlayerNumber;
        m_TurnAxisName = "Horizontal" + m_PlayerNumber;

        m_OriginalPitch = m_MovementAudio.pitch;
    }
    */

    private void Update()
    {
        // Store the player's input and make sure the audio for the engine is playing.
    }


    private void EngineAudio()
    {
        // Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing.
    }


    private void FixedUpdate()
    {
        // Move and turn the tank.
    }


    private void Move()
    {
        // Adjust the position of the tank based on the player's input.
    }


    private void Turn()
    {
        // Adjust the rotation of the tank based on the player's input.
    }
}

里面已经有一些代码了,下面我们就对其扩充来控制坦克移动
Unity控制物体移动的方法主要有两种:
①非刚体(Update)
obj.transform.position = obj.transform.position+移动向量*Time.deltaTime;
obj.transform.Translate(移动向量*Time.deltaTime);
②刚体(FixedUpdate)
GetComponent<Rigidbody>().velocity
GetComponent<Rigidbody>().AddForce
GetComponent<Rigidbody>().MovePosition

由于我们的坦克是刚体,且移动被限制在了 XZ 平面,此时最好的方式是采用 MovePosition
获取用户输入

    private void Start()
    {
        //在菜单Edit->Project Settings->Input设置,默认玩家1左右移动按键是 a 和 d,前后按键是 w 和 s
        m_MovementAxisName = "Vertical" + m_PlayerNumber;
        m_TurnAxisName = "Horizontal" + m_PlayerNumber;
    }

    private void Update()
    {
        //获取用户通过按键 w 和 s 的输入量
        m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
        //获取用户通过按键 a 和 d 的输入量
        m_TurnInputValue = Input.GetAxis(m_TurnAxisName);
    }

移动和转动

    private void Move()
    {
        
        Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
        m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
    }


    private void Turn()
    {
        
        float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
        // 沿y轴转动
        Quaternion turnRotation = Quaternion.Euler(0f, turn, 0f);
        m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
    }

音效控制

    private void EngineAudio()
    {
        // 坦克是静止的
        if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
        {
            // 若此时播放的是坦克运动时的音效
            if (m_MovementAudio.clip == m_EngineDriving)
            {
                m_MovementAudio.clip = m_EngineIdling;
                m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);//控制音频播放速度
                m_MovementAudio.Play();
            }
        }
        else
        {
            if (m_MovementAudio.clip == m_EngineIdling)
            {
                m_MovementAudio.clip = m_EngineDriving;
                m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);//控制音频播放速度
                m_MovementAudio.Play();
            }
        }
    }

TankMovement.cs 完整代码

using UnityEngine;

public class TankMovement : MonoBehaviour
{
    public int m_PlayerNumber = 1;              // Used to identify which tank belongs to which player.  This is set by this tank's manager.
    public float m_Speed = 12f;                 // How fast the tank moves forward and back.
    public float m_TurnSpeed = 180f;            // How fast the tank turns in degrees per second.
    public AudioSource m_MovementAudio;         // Reference to the audio source used to play engine sounds. NB: different to the shooting audio source.
    public AudioClip m_EngineIdling;            // Audio to play when the tank isn't moving.
    public AudioClip m_EngineDriving;           // Audio to play when the tank is moving.
    public float m_PitchRange = 0.2f;           // The amount by which the pitch of the engine noises can vary.


    private string m_MovementAxisName;          // The name of the input axis for moving forward and back.
    private string m_TurnAxisName;              // The name of the input axis for turning.
    private Rigidbody m_Rigidbody;              // Reference used to move the tank.
    private float m_MovementInputValue;         // The current value of the movement input.
    private float m_TurnInputValue;             // The current value of the turn input.
    private float m_OriginalPitch;              // The pitch of the audio source at the start of the scene.


    private void Awake()
    {
        m_Rigidbody = GetComponent<Rigidbody>();
    }


    private void OnEnable()
    {
        // When the tank is turned on, make sure it's not kinematic.
        m_Rigidbody.isKinematic = false;

        // Also reset the input values.
        m_MovementInputValue = 0f;
        m_TurnInputValue = 0f;
    }


    private void OnDisable()
    {
        // When the tank is turned off, set it to kinematic so it stops moving.
        m_Rigidbody.isKinematic = true;
    }


    private void Start()
    {
        // The axes names are based on player number.
        m_MovementAxisName = "Vertical" + m_PlayerNumber;
        m_TurnAxisName = "Horizontal" + m_PlayerNumber;

        // Store the original pitch of the audio source.
        m_OriginalPitch = m_MovementAudio.pitch;
    }


    private void Update()
    {
        // Store the value of both input axes.
        m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
        m_TurnInputValue = Input.GetAxis(m_TurnAxisName);

        EngineAudio();
    }


    private void EngineAudio()
    {
        // If there is no input (the tank is stationary)...
        if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
        {
            // ... and if the audio source is currently playing the driving clip...
            if (m_MovementAudio.clip == m_EngineDriving)
            {
                // ... change the clip to idling and play it.
                m_MovementAudio.clip = m_EngineIdling;
                m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                m_MovementAudio.Play();
            }
        }
        else
        {
            // Otherwise if the tank is moving and if the idling clip is currently playing...
            if (m_MovementAudio.clip == m_EngineIdling)
            {
                // ... change the clip to driving and play.
                m_MovementAudio.clip = m_EngineDriving;
                m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                m_MovementAudio.Play();
            }
        }
    }


    private void FixedUpdate()
    {
        // Adjust the rigidbodies position and orientation in FixedUpdate.
        Move();
        Turn();
    }


    private void Move()
    {
        // Create a vector in the direction the tank is facing with a magnitude based on the input, speed and the time between frames.
        Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;

        // Apply this movement to the rigidbody's position.
        m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
    }


    private void Turn()
    {
        // Determine the number of degrees to be turned based on the input, speed and time between frames.
        float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;

        // Make this into a rotation in the y axis.
        Quaternion turnRotation = Quaternion.Euler(0f, turn, 0f);

        // Apply this rotation to the rigidbody's rotation.
        m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
    }
}

2、在将 TankMovement.cs 拖入到 Tank 上时,选择 Tank 的第一个 Audio Source Component 拖入到TankMovement 的 Movement Audio上,并选择 Engine Idling 为 EngineIdle 音频,Engine Drving 为 EngineDrving 音频,至此点击 Apply,将我们后面对 Tank 的修改保存到 Tank prefab 中

clipboard.png

3、保存场景,点击 Play 试玩一下

图片描述

通过今天的教程,你可以学会

  • 场景设置,基本的物体操作
  • 编程控制物体移动

下期教程继续。。。


爱种地的码农
28 声望8 粉丝