3D游戏设计HW5

与游戏世界交互

编写一个简单的鼠标打飞碟(Hit UFO)游戏

1.游戏内容要求:

  • 游戏有 n 个 round,每个 round 都包括10 次 trial;
  • 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
  • 每个 trial 的飞碟有随机性,总体难度随 round 上升;
  • 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。

2. 游戏的要求:

  • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
  • 尽可能使用前面 MVC 结构实现人机交互与游戏模型分离

游戏的UML图如下:
在这里插入图片描述

可以看出用了之前的牧师与魔鬼的很多设计,比如导演类和动作分离。主要的区别就是工厂类UFOFactory,用于飞碟的生产。
这个类使用了重复利用的思想,维护两个列表,一个是正在使用中的飞碟,另一个是空闲的飞碟。每次需要产生飞碟的时候就从空闲飞碟队列中弹出第一个,当有飞碟被打中或者飞到屏幕之外后会被重新加入到空闲队列中。如果空闲飞碟队列为空,就新创建一个飞碟并随即生成颜色和位姿。工厂类的代码如下:

public class UFOFactory : MonoBehaviour {
	public List<GameObject> used_UFO = new List<GameObject>();
	public List<GameObject> free_UFO = new List<GameObject>();
	public void GenUFO()
	{
		GameObject ufo;
		if(free_UFO.Count == 0)
		{
			ufo = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/UFO"), Vector3.zero, Quaternion.identity);
		}
		else
		{
			ufo = free_UFO[0];
			free_UFO.RemoveAt(0);
		}
		float x = Random.Range(-10.0f, 10.0f);
		ufo.transform.position = new Vector3(x, 0, 0);
		ufo.transform.Rotate(new Vector3(x < 0? -x*9 : x*9, 0, 0));

		float random = Random.Range (0f, 9f);
		Color red = new Color (1f, 0f, 0f);
		Color green = new Color (0f, 1f, 0f);
		Color blue = new Color (0f, 0f, 1f);
		Color color = new Color(0f,0f,0f);
		if (random >= 0 && random <= 3)
			color = red;
		else if (random > 3 && random <= 6)
			color = green;
		else if (random > 6 && random <= 9)
			color = blue;

		ufo.transform.GetComponent<Renderer>().material.color = color;
		used_UFO.Add(ufo);
	}
	public void Recycleufo(GameObject usedUFO)
	{
		usedUFO.transform.position = new Vector3 (0, 0, -10);
		free_UFO.Add(usedUFO);
	}
}

除此之外还有与牧师与魔鬼不同的就是用来实现单例的模板类Singleton,用于实现场景单例模式。生产飞碟的工厂是每个场景都有且仅有一个,Singleton类是用来给每个场景创建工厂的模板。具体代码如下:

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

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{

	protected static T instance;

	public static T Instance {  
		get {  
			if (instance == null) { 
				instance = (T)FindObjectOfType (typeof(T));  
				if (instance == null) {
					Debug.LogError ("An instance of " + typeof(T) +
						" is needed in the scene, but there is none.");  
				}
			}
			return instance;  
		}
	}
}

其他的类就与牧师与魔鬼类似,首先是控制运动的类,由于飞碟的运动不需要分阶段进行,所以直接使用原来的运动类,从当前位置以speed运动到target:

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

public class CCMoveToAction : SSAction
{
	public Vector3 target;
	public float speed;
	public GameObject ufo;
	public static CCMoveToAction GetSSAction(Vector3 target, float speed )
	{
		CCMoveToAction action = CreateInstance<CCMoveToAction>();
		action.target = target;
		action.speed = speed;
		return action;
	}
		
	public override void Update()
	{
		if(enable)
		{
			this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed);
			if (this.transform.position == target)
			{
				this.enable = false;
				this.callback.SSActionEvent(this);
			}
		}
	}
}

动作管理类,维护动作的列表,每次根据情况从中取出动作进行运动:

public class CCActionManager : SSActionManager, ISSActionCallback {
	public FirstSceneController sceneController;
	public List<CCMoveToAction> seq = new List<CCMoveToAction>();
	public UserClickAction userClickAction;
	public UFOFactory factory;

	protected new void Start()
	{
		sceneController = (FirstSceneController)SSDirector.getInstance().current;
		sceneController.actionManager = this;
		factory = Singleton<UFOFactory>.Instance;
	}
	protected new void Update()
	{
		if(factory.used_ufos.Count > 0)
		{
			GameObject disk = factory.used_ufos[0].gameObject;
			float x = Random.Range(-10, 10);
			CCMoveToAction moveToAction = CCMoveToAction.GetSSAction(new Vector3(x, 12, 0), (Mathf.CeilToInt(FirstSceneController.times / 10) + 1) * Time.deltaTime);
			if (disk.transform.GetComponent<Renderer>().material.color == Color.red)
				moveToAction = CCMoveToAction.GetSSAction(new Vector3(x, 12, 0), 5 * (Mathf.CeilToInt(FirstSceneController.times / 10) + 1) * Time.deltaTime);
			else if(disk.transform.GetComponent<Renderer>().material.color == Color.green)
				moveToAction = CCMoveToAction.GetSSAction(new Vector3(x, 12, 0), 4 * (Mathf.CeilToInt(FirstSceneController.times / 10) + 1) * Time.deltaTime);
			else if(disk.transform.GetComponent<Renderer>().material.color == Color.blue)
				moveToAction = CCMoveToAction.GetSSAction(new Vector3(x, 12, 0), 3 * (Mathf.CeilToInt(FirstSceneController.times / 10) + 1) * Time.deltaTime);
			
			seq.Add(moveToAction);
			this.RunAction(disk, moveToAction, this);
			factory.used_ufos.RemoveAt(0);
		}
		if (Input.GetMouseButtonDown(0) && sceneController.flag == 0)
		{
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hitGameObject;
			if (Physics.Raycast(ray, out hitGameObject))
			{
				GameObject gameObject = hitGameObject.collider.gameObject;
				if (gameObject.tag == "ufo")
				{
					foreach(var k in seq)
					{
						if (k.gameObject == gameObject)
							k.transform.position = k.target;
					}
					if(gameObject.transform.GetComponent<Renderer>().material.color==Color.red)
						userClickAction = UserClickAction.GetSSAction(3);
					else if(gameObject.transform.GetComponent<Renderer>().material.color==Color.green)
						userClickAction = UserClickAction.GetSSAction(2);
					else if(gameObject.transform.GetComponent<Renderer>().material.color==Color.blue)
						userClickAction = UserClickAction.GetSSAction(1);					
					this.RunAction(gameObject, userClickAction, this);
				}
			}
		}
		base.Update();
	}
	public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intParam = 0, string strParam = null, Object objParam = null)
	{
		factory.Recycleufo(source.gameObject);
		seq.Remove(source as CCMoveToAction);
		source.destory = true;
		if (FirstSceneController.times >= 30)
			sceneController.flag = 1;
		
	}
	public void CheckEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intParam = 0, string strParam = null, Object objParam = null)
	{
	}
	public void Pause()
	{
		if(sceneController.flag == 0)
		{
			foreach (var k in seq)
			{
				k.enable = false;
			}
			sceneController.flag = 2;
		}
		else if(sceneController.flag == 2)
		{
			foreach (var k in seq)
			{
				k.enable = true;
			}
			sceneController.flag = 0;
		}
	}
}

在这个类里面我实现了不同飞碟不同速度和分数的功能,方法都是类似的,即创建动作时根据动作主体的颜色来改变参数。创建运动动作时就在传速度时乘以一个速度加成,创建点击动作实例时就传入参数,这个参数根据点击飞碟的颜色而不同,在点击动作中有FirstSceneController类,可以根据传入的add_score增加分数。点击动作实现如下:

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

public class UserClickAction : SSAction {
	public int add_score = 0;
	public static UserClickAction GetSSAction(int s)
	{
		UserClickAction action = CreateInstance<UserClickAction>();
		action.add_score = s;
		return action;
	}
	public override void Start(){
	}	

	public override void Update()
	{
		if(enable)
		{
			FirstSceneController sc = SSDirector.getInstance().current as FirstSceneController;
			sc.score = sc.score + Mathf.CeilToInt(FirstSceneController.times/10) + add_score*Mathf.FloorToInt(120 / (transform.rotation.x + 30));
			destory = true;
		}
	}
}

最后可以再用上次作业学习的天空盒做一个场景,游戏运行的效果图如图:

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
传说中的龙书是也。。。 最好最新的DirectX游戏开发入门书籍 英文版+中文版+源代码 打包 非常适合初学者 内容提要 -------------------------------------------------------------------------------- 本书主要介绍如何使用DirectX 9.0开发交互式3D图形程序,重点是游戏开发。全书首先介绍了必要的数学工具,然后讲解了相关的3D概念。其他主题几乎涵盖了Direct3D中的所有基本运算,例如图元的绘制、光照、纹理、Alpha融合、模板,以及如何使用Direct3D实现游戏中所需的技术。介绍顶定点着色器和像素着色器的章节(包含了效果框架和新的高级着色语言的内容)对这些关键运算进行了较为集中的讨论。 本书内容深入浅出,内容广泛,可供从事3D游戏程序设计、可视化系统设计或其他图形应用程序开发的开发人员和大中专院校学生参考,也极适合各种游戏开发培训机构作为Direct3D编程的培训教程。 目录 -------------------------------------------------------------------------------- 第Ⅰ部分 基础知识 必备的数学知识\t 3D空间中的向量\t 矩阵\t\t 基本变换\t 平面(选读)\t 射线(选读)\t 小结\t\t 第Ⅱ部分 Direct3D基础 第1章 初始化Direct3D 1.1 Direct3D概述\t 1.2 COM(组件对象模型)\t 1.3 预备知识\t 1.4 Direct3D的初始化\t 1.5 例程:Direct3D的初始化 1.6 小结\t 第2章 绘制流水线\t 2.1 模型表示\t 2.2 虚拟摄像机 2.3 绘制流水线 2.4 小结\t 第3章 Direct3D中的绘制\t 3.1 顶点缓存与索引缓存 3.2 绘制状态\t 3.3 绘制的准备工作\t 3.4 使用顶点缓存和索引缓存进行绘制\t 3.5 D3DX几何体 3.6 例程:三角形、立方体、茶壶、D3DXCreate* 3.7 小结\t 第4章 颜色\t 4.1 颜色表示 4.2 顶点颜色 4.3 着色\t 4.4 例程:具有颜色的三角形\t 4.5 小结\t 第5章 光照\t 5.1 光照的组成\t 5.2 材质\t 5.3 顶点法线\t 5.4 光源\t 5.5 例程:光照 5.6 一些附加例程\t 5.7 小结\t 第6章 纹理映射 6.1 纹理坐标\t 6.2 创建并启用纹理\t 6.3 纹理过滤器 6.4 多级渐进纹理 6.5 寻址模式 6.6 例程:纹理四边形 6.7 小结\t 第7章 融合技术\t 7.1 融合方程\t 7.2 融合因子 7.3 透明度 7.4 用DirectX Texture Tool创建Alpha通道\t 7.5 例程:透明效果\t 7.6 小结\t 第8章 模板\t 8.1 模板缓存的使用\t 8.2 例程:镜面效果\t 8.3 例程:Planer Shadows\t 8.4 小结\t 第Ⅲ部分 Direct3D的应用 第9章 字体\t 第10章 网格(一)\t 第11章 网格(二)\t 第12章 设计一个灵活的Camera类 第13章 地形绘制基础\t 第14章 粒子系统\t 第15章 拾取\t 第Ⅳ部分 着色器和效果 第16章 高级着色语言(HLSL)入门\t 第17章 顶点着色器入门\t 第18章 像素着色器入门\t 第19章 效果框架\t 附录 Windows编程入门\t 参考文献 作者介绍 -------------------------------------------------------------------------------- Prank Luna是Hero lnteractive的程序员,从事交互式3D图形编程已有八年多。他最早接触DirectX可以追溯到DirectX5发布之时,目前居住在加州的洛杉矶市。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值