3D游戏(4)——游戏对象与图形基础

1、基本操作演练【建议做】

下载 Fantasy Skybox FREE, 构建自己的游戏场景

Fantasy Skybox FREE添加至我的资源,从Unity的Window选项里进入Package Manager下载Fantasy Skybox FREE并导入到Asset中。

在这里插入图片描述

首先创建天空盒,在Assert中右键Create一个Material,命名为Sky。

然后设置这个Material的Shader为Skybox/Panoramic,再从下载到的素材里选一张合适的图片贴入Spherical中,最终将该天空盒拖入场景中即可。

在这里插入图片描述

在这里插入图片描述

然后创建一个地形,GameObject->3D Object->Terrain。先创建一个光地板,再慢慢通过Terrain的各项工具绘制山、草、树等等。

在这里插入图片描述

在这里插入图片描述

成果:

在这里插入图片描述

好像还可以(×),真的一言难尽(√)

写一个简单的总结,总结游戏对象的使用

游戏对象本身作为组件的容器使用,可以通过向其中添加不同的组件来调用不同的功能。一个对象挂载了组件,便拥有了组件的相关属性。

同时,不同的游戏对象还有着它独特的功能。比如:

  • Camera:作为游戏的眼睛,是玩家观察游戏世界的媒介;
  • Light:光源,既可以用来照明也可用于添加阴影;
  • Empty空对象:多被用于当做载体,例如挂载游戏脚本、成为其他对象的父对象等。;
  • Cube等3D Object:搭建游戏世界的组成元素,通过设置其Transform等属性来变换它们的Position、Rotation、Scale;
  • Terrain等:既是组成元素,又是编辑工具,Terrain本身是地图,然后又附带了绘制地图的各项工具(造山、种树种草等)。

2、编程实践

牧师与魔鬼 动作分离版

设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。

首先,要在上一次作业的基础上实现动作分离版的牧师与魔鬼,就需要在原来的基础上新增动作管理相关的类。

先前的作业就已经实现了一个Move和一个MoveController来对动作进行管理了。但这只是一个简单的动作管理类,这一次需要实现的是更细分的动作管理。

在这里插入图片描述

在这里插入图片描述

因而,最基本要新增SSAction、CCMoveToAction、CCSequenceAction、ISSActionCallback、SSActionManager、CCActionManager这几个类。

在这里,因为我的人物动作几乎都是直线移动即可,CCSequenceAction就没实现了,因为懒

1.首先,实现SSAction。

public class SSAction : ScriptableObject
{

    public bool enable=true;
    public bool destroy=false;

    public GameObject gameObject{get;set;}
    public Transform transform{get;set;}
    public ISSActionCallback callback{get;set;}

    protected SSAction(){}

    // Start is called before the first frame update
    public virtual void Start(){
        throw new System.NotImplementedException();
    }

    // Update is called once per frame
    public virtual void Update(){
        throw new System.NotImplementedException();
    }
}

这里利用ISSACtionCallback来实现消息的通知,同时使用virtual申明虚方法,通过重写实现多态。

2.CCMoveToAction。

public class CCMoveToAction : SSAction
{
    public Vector3 target;
    public float speed;

    public static CCMoveToAction GetSSAction(Vector3 target, float speed){
        CCMoveToAction action=ScriptableObject.CreateInstance<CCMoveToAction>();
        action.target=target;
        action.speed=speed;
        return action;
    }

    // Start is called before the first frame update
    public override void Start()
    {
        
    }

    // Update is called once per frame
    public override void Update()
    {
        this.transform.localPosition=Vector3.MoveTowards(this.transform.localPosition,target,speed*Time.deltaTime);
        if(this.gameObject==null||this.transform.localPosition==target){
            this.destroy=true;
            this.callback.SSActionEvent(this);
        }
    }
}

此类继承的是SSAction,实现较为简单的移动。

3.ISSActionCallback接口。

public enum SSActionEventType : int{Started,Competed}
public interface ISSActionCallback{
    void SSActionEvent(SSAction source,
        SSActionEventType events=SSActionEventType.Competed,
        int intParam=0,
        string strParam=null,
        Object objectParam=null);
}

由始至终都是在copy老师课件上的代码。

4.SSActionManager动作管理基类。

public class SSActionManager : MonoBehaviour
{
    private Dictionary<int,SSAction> actions=new Dictionary<int,SSAction>();
    private List<SSAction> waitingAdd=new List<SSAction>();
    private List<int> waitingDelete=new List<int>();

    protected void Update(){
        foreach(SSAction ac in waitingAdd) actions[ac.GetInstanceID()]=ac;
        waitingAdd.Clear();

        foreach(KeyValuePair<int,SSAction> kv in actions){
            SSAction ac=kv.Value;
            if(ac.destroy){
                waitingDelete.Add(ac.GetInstanceID());
            }
            else if(ac.enable){
                ac.Update();
            }
        }

        foreach(int key in waitingDelete){
            SSAction ac=actions[key];
            actions.Remove(key);
            Destroy(ac);
        }
        waitingDelete.Clear();
    }

    public void RunAction(GameObject gameObject,SSAction action,ISSActionCallback manager){
        action.gameObject=gameObject;
        action.transform=gameObject.transform;
        action.callback=manager;
        waitingAdd.Add(action);
        action.Start();
    }

    // Start is called before the first frame update
    protected void Start()
    {

    }

}

依旧在copy老师的代码。

  1. SSActionManager是作为动作生成、运行与销毁的管理者。
  2. actions以字典的形式将正在运行中的动作存储起来。
  3. waitingAdd保存的是即将被运行的动作。
  4. waitingDelete保存的是即将被删除的动作。
  5. Update()每次都会将waitingAdd中的动作加入到actions当中,然后遍历actions中的动作,运行每一个动作。如果动作已经结束,则加入到waitingDelete中,最后将waitingDelete中的动作删除并销毁。

5.CCActionManager动作管理者。

public class CCActionManager : SSActionManager, ISSActionCallback
{
    private bool isMoving=false;
    public CCMoveToAction moveObjAction;
    public FirstController controller;

    protected new void Start()
    {
        controller=SSDirector.getInstance().currentSceneController as FirstController;
    }

    public bool IsMoving(){
        return isMoving;
    }
    public void MoveObj(GameObject obj,Vector3 target,float speed){
        if(isMoving) return;
        isMoving=true;
        moveObjAction=CCMoveToAction.GetSSAction(target,speed);
        this.RunAction(obj,moveObjAction,this);
    }
    public void SSActionEvent(SSAction source,
        SSActionEventType events=SSActionEventType.Competed,
        int intParam=0,
        string strParam=null,
        Object objectParam=null){
            isMoving=false;
        }
}

到这里,老师课件上的代码就不太适用了,最好是根据自己的实际情况稍作修改。没得直接照抄了

CCActionManager跟上一次的Move和MoveController都有着较大的交集,最主要的功能还是给FirstController提供一个移动游戏对象的函数接口。

将一系列的动作管理类实现好了之后,接下来就需要修改原来的代码了。

若目标只是能运行的话,只需要将FirstController原来对MoveController相关函数的调用改为CCActionManager里面的函数即可。将原来的MoveController注释掉,并在Awake()函数里将CCActionManager脚本挂载上this.gameObject.AddComponent<CCActionManager>();,这样直接就能够正常运行了。

然而,题目还有一个要求是要实现一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。也就是说将原先FirstController中判断游戏结束的功能分离出来,单独实现一个Judgment类来完成。

其实,原来为了方便(),在FirstController中存储了leftPriestNum、leftDevilNum、rightPriestNum、rightDevilNum四个变量来对游戏状态进行判断。但是呢,在把Check的功能分离出去之后,在FirstController中存储这四个变量显然是不合适的,说到底还是应该放去LandModel中去。同时,对这四个变量的初始化也就放去LandModelController里的CreateLand函数里面。

那么,在Judgement里就是通过LandModelController来获取河两岸牧师魔鬼的个数信息了。

public class Judgement : MonoBehaviour
{

    private FirstController controller;
    private LandModelController landRoleController;

    // Start is called before the first frame update
    void Start()
    {
        controller=SSDirector.getInstance().currentSceneController as FirstController;
        landRoleController=controller.GetLandModelController();
    }

    // Update is called once per frame
    void Update()
    {
        if(!controller.GetIsRuning()) return;
		this.gameObject.GetComponent<UserGUI>().gameMessage="";
		if(landRoleController.GetLandModel().rightPriestNum==3&&landRoleController.GetLandModel().rightDevilNum==3){
            controller.JudgeCallback(false,"You Win!!");
		}
		else if((landRoleController.GetLandModel().leftPriestNum!=0
            &&landRoleController.GetLandModel().leftPriestNum<landRoleController.GetLandModel().leftDevilNum)
			    ||(landRoleController.GetLandModel().rightPriestNum!=0
            &&landRoleController.GetLandModel().rightPriestNum<landRoleController.GetLandModel().rightDevilNum)){
			    controller.JudgeCallback(false,"Game Over!!");
		    }
    }
}

实质上就是将原来的Check函数放去update()函数里面,改改变量名,最后再调用相关的回调函数JudgeCallback就行了。(FirstController里面还需要添加GetIsRuning()和GetLandModelController()两个函数)

最后,将原来跟Check()函数相关的语句注释掉,再在FirstController的Awake()函数里将Judgement脚本挂载上就可以了this.gameObject.AddComponent<Judgement>();

在这里插入图片描述

本来想着是将前面自己构建的游戏场景用上去,但效果实在是。。。倒不如用原来的场景。

最后,附上完整代码

3、材料与渲染联系【可选】

Standard Shader自然场景渲染器。

在场景中新建一个”球“,再在Asset新建一个Material并拖到球体上。

在这里插入图片描述

首先可以在Albedo处改变颜色。

在这里插入图片描述

在这里插入图片描述

将Rendering Mode勾选为Transparent模式,再修改Albedo里面Color的A值,就能改变球体的透明度。

在这里插入图片描述

在这里插入图片描述

还可以改变Metallic的值,使其带上一种金属质感。

在这里插入图片描述

在这里插入图片描述

还可以改变Smoothness的值。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

呃。。拉满之后简直一言难尽。。

声音

  • 阅读官方Audio手册
  • 用博客给出游戏中利用Reverb Zones呈现车辆穿过隧道的声效的案例

下载汽车音频

直接在前面的球体上(偷懒),AddComponent->Audio->Audio Source和Audio Reverb Zones,将下载到的音频拖放到音源处。

在这里插入图片描述

再将Reverb Zone的Reverb Preset设为Cave。

在这里插入图片描述

点击运行即可。

猜你喜欢

转载自blog.csdn.net/qq_43278234/article/details/108967361