HW4 游戏对象与图形基础

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

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

    1. 在 Asset Store 中下载 Fantasy Skybox FREE ,下载完成后导入

    2. 创建一个Terrian对象,并使用如下的 Brushes 工具绘制山
      在这里插入图片描述

      绘制效果如下:
      在这里插入图片描述

在这里插入图片描述

  1. 在 Asset Store 中下载 Mobile Tree Package ,下载完成后导入

  2. 在地形的Inspector界面,点击Edit Trees→Add Tree,将导入的预制树添加进去,然后用Brush添加即可
    在这里插入图片描述

    添加完效果如下:

在这里插入图片描述

  1. 点击Edit Details→Add Grass Texture,选择预制好的草,然后用Brush添加即可

    但此时遇到一个小问题,用Brush添加后看不到,百度以后才知道是因为草太小了,在Scene界面放大以后可以才可以看到(😓

在这里插入图片描述

  1. 最终效果:

在这里插入图片描述

 (草因为太小了,看不到...)
  • 写一个简单的总结,总结游戏对象的使用

    • Camera:
      通过Camera来观察游戏世界。

    • Light:
      光源,可以用来照明也可用于添加阴影

    • Empty空对象
      空对象多被用于当做载体,例如挂载游戏脚本、成为其他对象的父对象等。

    • Cube等3D Object:
      搭建游戏世界的组成元素,通过设置其Transform等属性来变换它们的位置、形态等。

    • Terrain等:
      即是组成元素,又是编辑工具,例如Terrain本身是地图,然后又附带了绘制地图的各项工具(造山、造草等)。

    • 除了直接在Unity3d中控制和改变对象的属性,我们还需要编写脚本来控制各种对象。

2、牧师与魔鬼 动作分离版

【2019开始的新要求】:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

  • 该版本改进的目的:

    1. 把每个需要移动的游戏对象的移动方法单独拿出来,建立一个动作管理器来管理不同的移动方法。

    2. 当动作很多或是需要做同样动作的游戏对象很多的时候,使用动作管理器可以让动作很容易管理,也提高了代码复用性。

    3. 上一个版本中,每一个可移动的游戏对象的组件都有一个Move脚本,当游戏对象需要移动时候,游戏对象自己调用Move脚本中的方法让自己移动。

      而动作分离版中剥夺了游戏对象自己调用动作的能力,而是建立一个动作管理器,通过场景控制器(Controllor)把需要移动的游戏对象传递给动作管理器,让动作管理器去移动游戏对象。

  • 具体实现如下:

    Actions.cs:

    • SSAction是所有动作的基类,代码如下:

      public class SSAction : ScriptableObject            // 所有动作的父类
      {
      
          public bool enable = true;                      
          public bool destroy = false;                    
      
          public GameObject gameobject;                  
          public Transform transform;                     
          public ISSActionCallback callback;              // 回调函数
      
          protected SSAction() { }                        // 使SSAction不会被new
      
          // 子类重写这两个函数
          public virtual void Start() {                   
              throw new System.NotImplementedException();
          }
      
          public virtual void Update() {
              throw new System.NotImplementedException();
          }
      }
      
    • SSMoveToAction使对象以一定的速度向目的地移动,代码如下:

      public class SSMoveToAction : SSAction                        // 移动类
      {
          public Vector3 target;        // 目的地
          public float speed;           // 移动速度
      
          private SSMoveToAction() { }
          public static SSMoveToAction GetSSAction(Vector3 target, float speed) {
              SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();
              action.target = target;
              action.speed = speed;
              return action;
          }
      
          public override void Update() {
              this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
              if (this.transform.position == target) {
                  this.destroy = true;
                  this.callback.SSActionEvent(this);   //告诉动作管理或动作组合该动作已完成
              }
          }
      
          public override void Start() {
              
          }
      }
      
    • ISSActionCallback是动作管理者和动作的回调接口。当动作完成的时候,动作会调用这个接口,告诉动作管理者,当前动作已完成,然后动作管理者对下一个动作进行处理。动作管理者继承并实现接口。代码如下:

      public interface ISSActionCallback
      {
          void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
              int intParam = 0, string strParam = null, Object objectParam = null);
      }
      
    • SequenceAction继承了SSAction基类和ISSActionCallback,实现角色移动的组合动作,代码如下:

      public class SequenceAction : SSAction, ISSActionCallback
      {
          public List<SSAction> sequence;   
          public int repeat = -1;            // 无限循环做组合中的动作
          public int start = 0;             
      
          public static SequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence) {
              SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();
              action.repeat = repeat;
              action.sequence = sequence;
              action.start = start;
              return action;
          }
      
          public override void Update() {
              if (sequence.Count == 0) 
                  return;
              if (start < sequence.Count)
                  sequence[start].Update();     
          }
      
          public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
              int intParam = 0, string strParam = null, Object objectParam = null) {
              
              source.destroy = false;          
              this.start++;
              if (this.start >= sequence.Count) {
                  this.start = 0;
                  if (repeat > 0) 
                      repeat--;
                  if (repeat == 0) {
                      this.destroy = true;               // 删除动作组合
                      this.callback.SSActionEvent(this); 
                  }
              }
          }
      
          public override void Start() {
              foreach (SSAction action in sequence) {
                  action.gameobject = this.gameobject;
                  action.transform = this.transform;
                  action.callback = this;                
                  action.Start();
              }
          }
      
          void OnDestroy()  {
          }
      }
      
    • SSActionManager是动作管理基类,管理SequenceAction和SSAction,给它们传递游戏对象,从而使对象做动作,同时还控制动作的切换,代码如下:

      public class SSActionManager : MonoBehaviour, ISSActionCallback                      // action管理器
      {
      
          private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();    // 将执行的动作的字典集合,int为key,SSAction为value
          private List<SSAction> waitingAdd = new List<SSAction>();                       // 等待去执行的动作列表
          private List<int> waitingDelete = new List<int>();                              // 等待删除的动作的key                
      
          protected void Update() {
              foreach (SSAction ac in waitingAdd) {
                  actions[ac.GetInstanceID()] = ac;                                      // 获取动作实例的ID作为key
              }
              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();
          }
      
          public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
              int intParam = 0, string strParam = null, Object objectParam = null) {
                                                      // 移动完成后无下一个动作,所以为空
          }
      }
      
    • MySceneActionManager是游戏的动作管理器,设置当前场景控制器的动作管理者为MySceneActionManager,从而调用动作管理器的方法实现不同游戏对象(船和角色)的移动,代码如下:

      public class MySceneActionManager : SSActionManager  // 本游戏管理器
      {
      
          private SSMoveToAction moveBoatToEndOrStart;     // 移动船到结束岸,移动船到开始岸
          private SequenceAction moveRoleToLandorBoat;     // 移动角色到陆地,移动角色到船上
      
          public Controllor sceneController;
      
          protected void Start() {
              sceneController = (Controllor)SSDirector.GetInstance().CurrentScenceController;
              sceneController.actionManager = this;
          }
          public void moveBoat(GameObject boat, Vector3 target, float speed) {
              moveBoatToEndOrStart = SSMoveToAction.GetSSAction(target, speed);
              this.RunAction(boat, moveBoatToEndOrStart, this);
          }
      
          public void moveRole(GameObject role, Vector3 middle_pos, Vector3 end_pos, float speed) {
              SSAction action1 = SSMoveToAction.GetSSAction(middle_pos, speed);
              SSAction action2 = SSMoveToAction.GetSSAction(end_pos, speed);
              moveRoleToLandorBoat = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });
              this.RunAction(role, moveRoleToLandorBoat, this);
          }
      }
      

    Model.cs:

    • 为实现**“设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束”**的目的,将Controllor.cs中的Check函数改为Model.cs中的裁判类,并在Controllor中实例化,代码如下:

      public class Judger
      {
          LandModel start_land;
          LandModel end_land;
          BoatModel boat; 
      
          public Judger(LandModel bl, LandModel el, BoatModel b) {
              start_land = bl;
              end_land = el;
              boat = b;
          }
      
          public int Check() {
              int start_priest = (start_land.GetRoleNum())[0];
              int start_devil = (start_land.GetRoleNum())[1];
              int end_priest = (end_land.GetRoleNum())[0];
              int end_devil = (end_land.GetRoleNum())[1];
      
              if (end_priest + end_devil == 6)        // 获胜
                  return 3;
      
              int[] boat_role_num = boat.GetRoleNum();
              if (boat.GetBoatSign() == 1) {          // 在开始岸和船上的角色
                  start_priest += boat_role_num[0];
                  start_devil += boat_role_num[1];
              } else {                                // 在结束岸和船上的角色
                  end_priest += boat_role_num[0];
                  end_devil += boat_role_num[1];
              }
      
              if ((start_priest > 0 && start_priest < start_devil) || (end_priest > 0 && end_priest < end_devil)) { //失败
                  return 2;
              }
      
              return 1;                               //未完成
          }
      }
      

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

  • Standard Shader 自然场景渲染器。

    调节Albedo参数控制曲面的基础颜色:

    颜色改变过程如图所示:

在这里插入图片描述
在这里插入图片描述

改变对比度,变化过程如图所示:

在这里插入图片描述
在这里插入图片描述

  • 声音

    • 阅读官方 Audio 手册
    • 用博客给出游戏中利用 Reverb Zones 呈现车辆穿过隧道的声效的案例
    1. 从Asset Store中下载汽车音效

    2. 新建一个空的游戏对象,添加Audio Source和Audio Reverb Zone组件

    3. 把下载导入的汽车音效挂到刚创建的空对象上,勾选Audio Source中的Loop、将Audio Reverb Zone中的Reverb Preset改为Cave,,即完成了车辆穿过隧道的声效

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值