unity应用实例——从头撸一个全新的FPS游戏(1)

从今天开始打算从头开始搞一个全新的FPS游戏,引擎使用的是unity2017,所有美术资源都计划从商店购买或是网上下载(自己实在搞不来),主要玩法是玩家需要穿越多个地图到达目的地,穿越途中会遇到怪物追杀和哨兵把守,玩家突破重重阻碍到达终点即可胜利。在这里主要是做一下记录和总结,有不足之处希望指正。

这一篇是整个系列的准备工作。首先创建一个空物体作为玩家控制的对象,添加一个Character Controller组件。然后需要添加一个玩家控制角色的脚本,主要负责使玩家视角跟随对象,并控制角色移动、跳跃、下蹲等。这种脚本比较熟悉了,因为是fps游戏,不用给玩家自己设置动画,所以我手撸了一个简易版的,效果满意。下面是脚本代码。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class player : MonoBehaviour
{
    private bool iscrouching;
    [SerializeField]
    private float gravity;
    public GameObject eyeposition;
    public float steptime;
    public float jumpspeed;
    public float movespeed;
    public float crouchmovespeed;
    public Camera m_camera;
    public CharacterController m_player;
    public AudioClip[]stepsound=new AudioClip[4];//数组要在定义时直接分配空间
    public AudioClip jumpsound;
    public AudioSource m_audio;
    private float y = 0;
    private float timer = 0;//用来计算播放走路音效的时间间隔
    private float controllerheight;
    private Vector3 controllercenter;
    void Start()
    {
        m_player = gameObject.GetComponent<CharacterController>();
        controllerheight = m_player.height;
        controllercenter = m_player.center;
        m_audio = gameObject.GetComponent<AudioSource>();
  
    }
    private void FixedUpdate()
    {
        playermove();

        float deltay, deltax;
        deltay = Input.GetAxis("Mouse X");
        deltax = Input.GetAxis("Mouse Y");
        Cameramove(deltax, deltay);

        if (!m_player.isGrounded)
        {
            y -= gravity * Time.deltaTime;
        }
    }
    #region 主角移动和脚步声音
    public void playermove()
    {

        timer += Time.deltaTime;
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
       
        if (m_player.isGrounded)
        {
            if (!iscrouching&&Input.GetKeyDown(KeyCode.Space))//起跳
            {
                Jump();
                timer = -steptime / 2;//这个值是随意设置的,只是为了起跳时不播放走路音效
            }

            bool crouch =Input.GetKey(KeyCode.C);
            ForCrouching(crouch);//蹲下
        }

        if (!iscrouching)
        {
            if (m_player.velocity.magnitude!=0&&timer > steptime)
            {
                m_audio.PlayOneShot(stepsound[Random.Range(0, 4)]);//PlayOneShot可以直接播放一次指定AudioClip
                timer = 0;
            }

            m_player.Move
(gameObject.transform.TransformDirection(new Vector3(x, y, z) * movespeed * Time.deltaTime));//移动
        }
        else m_player.Move
(gameObject.transform.TransformDirection(new Vector3(x, y, z) * crouchmovespeed * Time.deltaTime));//蹲着移动
    }
    public void Jump()
    {
            y = jumpspeed;
            m_audio.PlayOneShot(jumpsound);
    }
    public void ForCrouching(bool crouch)
    {
        if (crouch)
        {
            if (iscrouching) return;
            m_player.height = m_player.height / 1.5f;
            m_player.center += new Vector3(0, 0.2f, 0);
            iscrouching = true;
        }
        else
        {
            m_player.height = controllerheight;
            m_player.center = controllercenter;
            iscrouching = false;
        }
    }
    #endregion
    #region 摄像头角度移动
    public void Cameramove(float deltax, float deltay)
    {
        //鼠标控制摄像头角度
        Vector3 angle = m_camera.transform.eulerAngles;
        angle.x -= deltax;
        angle.y += deltay;
        if (angle.x > 35 && angle.x < 90) angle.x = 35;
        if (angle.x < 325 && angle.x > 270) angle.x = 325;//控制上下视野

        m_camera.transform.eulerAngles = angle;
        //主角角度与摄像头角度同步
       angle.x = angle.z = 0;
        transform.eulerAngles = angle;
        //摄像机跟随眼睛
        m_camera.transform.position = eyeposition.transform.position;
    }
    #endregion
}

这样的话角色控制就实现了,准备工作还没有做完,我们知道,很多unity项目都需要创建一个对象池来提高效率,在本项目中也不例外:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//对象池
public class pool : MonoBehaviour
{
    public static pool instance;

    //用字典构造多个池子,每个类型的池子的名字为string类型,一个池子本质上是一个栈
    private static Dictionary<string, Stack<GameObject>> m_pool;
   
    void Awake()
    {
        m_pool = new Dictionary<string, Stack<GameObject>>();
        instance = this;//单例模式
    }

    //从池子得到物体
    public static GameObject GetPrefab(GameObject prefab, Vector3 position,Quaternion rotation)
    {
        //池子的名字,这样子命名是因为预制体实例化后会名字会加一个(Clone)
        string key = prefab.name + "(Clone)";

        if(!m_pool.ContainsKey(key))//没有这个栈
        {
            GameObject one = Instantiate(prefab, position, rotation);
            m_pool.Add(key, new Stack<GameObject>());
            one.SetActive(true);
            return one;
        }

        else if ( m_pool[key].Count > 0)//如果栈存在且有东西
        {
            GameObject one = m_pool[key].Pop();
            one.transform.position = position;
            one.transform.rotation = rotation;
            one.SetActive(true);
            return one;
        }
        else //栈存在,栈里没东西
        {
            GameObject one = Instantiate(prefab,position,rotation);
            one.SetActive(true);
            return one;
        }
     
    }

    //将已经实例化出的gameobject放入对应的池子
    public static GameObject PrefabReturn(GameObject one)
    {
        m_pool[one.name].Push(one);
        one.SetActive(false);
        return one;
    }
}

对象池脚本写好后,我把他挂在一个命名为pool的空物体上,这样准备工作就完成了,下一篇开始武器系统。

猜你喜欢

转载自blog.csdn.net/qq_37553152/article/details/81736025