3D游戏-作业四-游戏对象与图形基础

牧师与魔鬼项目动作初版传送门:https://github.com/lurui7/3D-Game/tree/master/Priests-and-Devils
牧师与魔鬼项目动作分离版传送门:https://github.com/lurui7/3D-Game/tree/master/Priests-and-Devils-v2

基本操作演练【建议做】

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

这是非常有意思的设计环节,我们可以通过各种素材的组合,设计各种风格的游戏场景(就是比较耗费时间),不管是Skybox,还是绘制地图都是比较有意思的内容。这里简要展示我制作的Skybox及制作过程。

  • 1.首先创建名为mySky的Material,接下来就在 Inspector 视图中选择 Shader -> Skybox -> 6Sided,一一添加素材如下:在这里插入图片描述
  • 2.将Skybox加入到Camera 对象中的部件 Rendering ,然后Camera 就能看到此时的效果。在这里插入图片描述

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

  • 首先是Camera对象,这是每一个游戏中都不可缺少的一部分,是“玩家”观察游戏世界的一个“窗口”。利用这一特性,我们可以在上面挂载一些脚本,例如人物视角的移动,或者某个基类等等。
  • Light对象,这是游戏中的光源,可以设置点光源、平行光、聚光顶,以及多个光源的组合等等,来实现游戏中的光影变化。
  • 各种实体对象(包括Cube,Sphere等),可以通过这些对象来构建游戏场景,例如各种抽象小游戏的场景(上次实现的牧师与魔鬼),同时,还可以给这些对象挂载脚本,可以模拟各种场景(例如模拟抛物线,模拟爆炸)。
  • 空对象。这是一个比较重要的内容,通常我们将它作为一个载体来使用,因为挂载在实体对象上的脚本可能会因为对象的删除而失效,这时候就需要一个永远存在的空对象来挂载脚本,渲染游戏场景。

编程实践 牧师与魔鬼动作分离版

要求

  • 动作分离,把上一版本中的ModelCon中的move方法移除,由Action来管理。即不用为每个对象都一一加上move方法,通过Action来统一管理调用。
  • 【2019开始的新要求】:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

实现思路

  • 首先是裁判类的实现
    这个部分相较Action类来说要更简单一点,只需要把在接口把Check方法移除,以及将Controller中的Check方法实现转到Judge类中,把Check的调用改为Judge调用就可以解决。
    实现如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using modelcon;
    public class Judge {
    	LandModel start_land;
    	LandModel end_land;
    	BoatModel boat;
    	public Judge(LandModel start_,LandModel end_,BoatModel boat_)
    	{
    		start_land = start_;
    		end_land = end_;
    		boat = boat_;
    	}
    	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 2;
    
    		int[] boat_role_num = boat.GetRoleNumber();
    		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) 
    		{      
    			return 1;
    		}
    		if (end_priest > 0 && end_priest < end_devil)        
    		{
    			return 1;
    		}
    		return 0;                                             
    	}
    }
    
  • Action部分实现解析:

ISSActionCallback接口
该接口实现了不同函数之间信息回调,将一个函数运行结果传给另一个函数的功能。

	public enum SSActionEventType : int { Started, Competeted }

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

SSAction子类
实现动作类的基类。其中gameObject为动作作用的实体对象。callback是回调接口,当动作类需要向别的类传递信息时,就通过ISSActionCallback接口来实现。

public class SSAction : ScriptableObject          
	{

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

		public GameObject gameobject;                   
		public Transform transform;                    
		public ISSActionCallback callback;             

		protected SSAction() { }                        

		public virtual void Start()                   
		{
			throw new System.NotImplementedException();
		}

		public virtual void Update()
		{
			throw new System.NotImplementedException();
		}
	}

SSActionManager子类
动作管理类的基类,作为动作生成、运行与销毁的管理者。其中:
actions保存了当前正在运行的动作
waitingAdd是等待运行的动作
waitingDelete中是运行结束,等待删除的动作。

public class SSActionManager : MonoBehaviour, ISSActionCallback                      
	{

		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);
				DestroyObject(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)
		{

		}
	}

SSMoveToAction子类
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()
		{

		}
	}

SequenceAction子类
SequenceAction为组合动作类,即把一个动作序列按照合适的顺序执行:

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()
		{

		}
	}

MySceneActionManager子类
管理对象的动作,包括船的移动,牧师与魔鬼的上下船等

public class MySceneActionManager : SSActionManager  
	{

		private SSMoveToAction moveBoatToEndOrStart;     
		private SequenceAction moveRoleToLandorBoat;    

		public Controller sceneController;

		protected void Start()
		{
			sceneController = (Controller)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);
		}
	}

至此,完成了Action部分的实现,接下来只需要把Modelcon中的动作调用修改为Action调用,方法实现移除,就完成了动作分离的目标。
其余的部分代码相较上次项目并没有上面改变,就不再展示出来了,可以去往Priests-and-Devils查看。

运行效果展示

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

材料与渲染联系【可选】

要求
在这里插入图片描述
实现
阅读官方手册Albedo Color and Transparency部分,发现这种方法相较与直接调整Material颜色来说,更简便地实现了对象的材质效果。

以下为演示效果:
创建五个Cube和五个Material(0,255,0),并逐渐增大A属性,然后可以看到如下效果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值