3d游戏项目实训一周总结

    近期学校有一个3d游戏的项目实训,要求学生组成项目组共同完成一个3d游戏的制作。当然,游戏制作过程中的所有任务,包括设计、策划、美工、编码、测试等等,都将由我们自己完成。我们的项目组决定制作一款类似球球大作战以“吞食”为核心玩法的休闲游戏,游戏的主角是鲲(?),另外我们的游戏场景要做成3d版本。我们的项目组采用Unity引擎进行游戏开发,并且打算实现在线多人对战的功能。项目实训开始到今天已经经过约一周时间,在这一周时间内我们其实主要还是以学习为主,不过也完成了游戏指针过程中的一些任务。我在这一周内的学习成果和工作成果主要包括两方面:

一:系统总体设计文档的编写:

    这一部分的内容还是比较多的,虽然有一份文档模板,但由于之前没有类似的经验,所以一开始写起来还是觉得有点困难。我在编写文档之前也在网上查阅了一些关于文档编写的资料,同时结合实际的文档编写过程,作出了下面的一些个人总结,包括内容和编写技巧两个方面。

        在文档的内容方面:

            1.总体设计:主要对整个游戏进行一些概要性的说明,包括功能模块、关卡设计、界面设计、交互事件设计等等。

             功能模块可以理解为游戏开发时所需要的一些主要的组件,如场景定义、事件处理等等(功能模块从用户的角度来说也可以游戏提供提供给用户的一些子系统,如好友系统、排名系统等等);

               关卡设计中定义主游戏场景中的一些规则;

               另外交互事件不只包括玩家输入,也包括AI等元素触发的其他事件。

            2.游戏状态转换设计:游戏中的状态包括主界面、游戏进行中等状态。

            3.总体架构设计:整个游戏开发过程采用的架构模式。网络多人对战游戏一般采用客户端/服务器的架构模式。

        在文档的编写技巧方面:

            1.注意文档的内容一定要清晰准确,不能出现“可以这么做”“可能要”之类的话,否则别人看了文档怎么知道是要做还是不要做呢?

            2.避免相同的内容重复。一个内容只在文档出现一次,除了避免阅读的人读到相同的内容降低效率,更重要的是可以避免修改文档时带来的麻烦:如果文档中有内容重复,那么一改则全改,而且万一不小心漏了一两处没改呢?(感觉上避免重复的意义跟编程概念中的“函数”的意义有种异曲同工之妙)

            3.把握好内容细分的粒度。文档的内容不能太笼统也不能太详细...

二:游戏角色控制脚本的编写:

     这一部分算是一个不难不易的技术点,主要是实现通过用户输入操控游戏角色和游戏视角的功能。我们的角色要能够在3D的场景中的3个自由度中移动,所以游戏角色的操控方法其实也不太好设计。而且,我们需要设计一个跟随角色移动的摄像机,这个摄像机本身也有一个活动的范围。经过本人的探索和测试,目前算是初步实现了这样的控制功能,但性能还有待优化。

        游戏角色的控制功能:

            1.鼠标在游戏画面上移动时,改变游戏角色的朝向。

                定义一个Vector3变量保存角色的朝向信息,在每一帧中,获取鼠标的偏移并对应更新其朝向信息,我这里主要通过向量的球面插值(Vector3.Slerp)实现。 

            2.按下WSAD时,角色移动(移动方向根据其朝向方向决定)。按下W键时向其朝向的方向移动。

                每一帧根据输入获取角色移动方向的向量(和其朝向信息有关),根据这个向量更改角色的位置即可。

        游戏摄像机的控制功能:

            1.跟随游戏角色的移动。

                摄像机有一个游戏角色的引用,表示其跟随的对象。摄像机的脚本每一帧获取其跟随游戏角色的朝向方向,确定摄像机的朝向方向(通过球面插值),再根据游戏角色的位置,确定摄像机的位置,然后让摄像机看向游戏角色即可。

            2.按下右键,鼠标移动改变摄像机视角(此时不改变游戏角色本身)。

                 摄像机的脚本本身保存自身的偏移角度数据,当右键按下,鼠标移动改变摄像机偏移角度,由游戏角色的朝向和摄像机的偏移角度共同决定摄像机的最终朝向。

            3.松开右键,摄像机归位,要求有平滑过渡。

                  摄像机归位只需把摄像机的偏移角度置零即可,但要实现平滑效果则不能在一帧之内马上把偏移角度置零,我的方案是让偏移角度逐帧按比例减小直至归零。


//PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{

    public float mouseSensitivity = 1.0f;

    private Vector3 towards;//角色朝向的方向
    private Vector3 up;//向上向量
    private Vector3 right;//规定向右向量的y方向分量为0,避免镜头“翻滚”
    private float speed;

    private enum MOVE_DIRECTION { FRONT, FRONT_LEFT, FRONT_RIGHT, LEFT, RIGHT };
    private MOVE_DIRECTION moveDirection;

    void Start()
    {
        speed = gameObject.GetComponent().speed;
        towards = new Vector3(0.0f, 0.0f, 1.0f);
        up = new Vector3(0.0f, 1.0f, 0.0f);
        right = new Vector3(1.0f, 0.0f, 0.0f);
        moveDirection = MOVE_DIRECTION.FRONT;
    }

    private void FixedUpdate()
    {
        if (!Input.GetMouseButton(1))//如果鼠标右键被按下,则不需要对角色的朝向方向作任何修改
        {
            float mouseX = -Input.GetAxis("Mouse X") * mouseSensitivity;
            float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;

            //ctrlX和ctrlY可置为1或-1,控制角色朝向的操控方式
            float ctrlX = -1.0f, ctrlY = -1.0f;

            right = Vector3.Cross(towards, up);
            towards = Vector3.SlerpUnclamped(towards, up, ctrlY * mouseY / 90.0f);
            towards.Normalize();
            //限制最大“俯仰角”不超过45度
            if (towards.y * towards.y > towards.x * towards.x + towards.z * towards.z)
            {
                float sqXXZZ = Mathf.Sqrt(towards.x * towards.x + towards.z * towards.z);
                towards.y = towards.y > 0 ? 0.707f : -0.707f;
                towards.x = 0.707f * towards.x / sqXXZZ;
                towards.z = 0.707f * towards.z / sqXXZZ;
            }
            towards.Normalize();
            towards = Vector3.SlerpUnclamped(towards, right, ctrlX * mouseX / 90.0f);
            towards.Normalize();
            right = new Vector3(towards.z, 0.0f, -towards.x).normalized;
            up = Vector3.Cross(right, towards);
            up.Normalize();
        }

        //根据朝向和移动方向最终决定角色的“旋转”
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");
        Vector3 lookAt = new Vector3();
        if (moveHorizontal > 0.0f)
            if (moveVertical > 0.0f)
                moveDirection = MOVE_DIRECTION.FRONT_RIGHT;
            else
                moveDirection = MOVE_DIRECTION.RIGHT;
        else if (moveHorizontal < 0.0f)
            if (moveVertical > 0.0f)
                moveDirection = MOVE_DIRECTION.FRONT_LEFT;
            else
                moveDirection = MOVE_DIRECTION.LEFT;
        else if (moveVertical >= 0.0f)
            moveDirection = MOVE_DIRECTION.FRONT;
        switch (moveDirection)
        {
            case MOVE_DIRECTION.FRONT:
                lookAt = towards;
                break;
            case MOVE_DIRECTION.FRONT_LEFT:
                lookAt = Vector3.Slerp(towards, -right, 0.5f);
                break;
            case MOVE_DIRECTION.LEFT:
                lookAt = -right;
                break;
            case MOVE_DIRECTION.FRONT_RIGHT:
                lookAt = Vector3.Slerp(towards, right, 0.5f);
                break;
            case MOVE_DIRECTION.RIGHT:
                lookAt = right;
                break;
        }
        transform.LookAt(gameObject.transform.position + lookAt);

        //限制不能向后移动
        if (moveVertical < 0.0f)
            moveVertical = 0.0f;

        //更新位置
        Vector3 move = towards * moveVertical + right * moveHorizontal;
        gameObject.transform.position += (move.normalized * speed);
    }

    public Vector3 GetTowards()
    {
        return towards;
    }
}


//CameraController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;



public class CameraController : MonoBehaviour
{

    public GameObject player;

    public float mouseSensitivity = 3.0f;
    public float scrollSensitivity = 3.0f;

    private float distanceToPlayer;
    public float distanceToPlayerInit = 7.5f;
    public float maxDistanceInit = 10.0f;
    public float minDistanceInit = 5.0f;

    private Vector3 direction;//方向向量,玩家角色指向摄像机
    //向右向量和向上向量是相对“角色朝向”的
    private Vector3 up;
    private Vector3 right;//规定向右向量的y方向分量为0,避免镜头“翻滚”

    //摄像机本身的偏移角度
    private float offsetAngleHorizontal;
    private float offsetAngleVertical;

    void Start()
    {
        distanceToPlayer = distanceToPlayerInit;
        offsetAngleHorizontal = 0.0f;
        offsetAngleVertical = 0.0f;
    }

    private void FixedUpdate()
    {
        if (Input.GetMouseButton(1))//鼠标右键被按下,调整视角
        {
            float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
            float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
            offsetAngleHorizontal += mouseX;
            offsetAngleVertical += mouseY;
        }
        else//视角回归原位,对视角进行平滑过渡
        {
            if (Mathf.Abs(offsetAngleHorizontal) < 1e-6)
                offsetAngleHorizontal = 0.0f;
            else
                offsetAngleHorizontal *= 0.6f;
            if (Mathf.Abs(offsetAngleVertical) < 1e-6)
                offsetAngleVertical = 0.0f;
            else
                offsetAngleVertical *= 0.6f;
        }

        //计算摄像机朝向方向
        Vector3 playerTowards = player.gameObject.GetComponent().GetTowards();
        right = new Vector3(playerTowards.z, 0.0f, -playerTowards.x).normalized;
        up = Vector3.Cross(playerTowards, right).normalized;
        direction = Vector3.SlerpUnclamped(playerTowards, right, offsetAngleHorizontal / 90.0f);
        direction = Vector3.SlerpUnclamped(direction, up, 1.6f + offsetAngleVertical / 90.0f).normalized;

        //摄像机距离角色的距离根据角色大小来变化
        float playerSize = player.GetComponent().GetPlayerSize().x;
        distanceToPlayer = playerSize * distanceToPlayerInit;

        float scroll = Input.GetAxis("Mouse ScrollWheel");
        distanceToPlayerInit -= scroll * scrollSensitivity * playerSize;//滚轮往“上”滚时,摄像机距离拉近
        distanceToPlayerInit = Mathf.Clamp(distanceToPlayerInit, minDistanceInit, maxDistanceInit);
    }

    //摄像机位置的更新一般要放在其跟随物体的更新之后
    void LateUpdate()
    {
        transform.position = player.gameObject.transform.position + direction * distanceToPlayer;
        transform.LookAt(player.transform);
    }
}

你可能感兴趣的:(3d游戏项目实训一周总结)