3D Game Programming & Design

An Introduction to Game Engine and OO Design Patterns

face

View the Project on GitHub

五、与游戏世界交互

It freed me to enter one of the most creative periods of my life

— Steve Jobs, Stanford Report, June 14, 2005

预计时间:2-3 * 45 min

 

课程相关资源

资源与代码下载

1、游戏交互与创新

游戏交互是玩家体验的基础。这里 交互模型 定义为建立输入设备的输入与游戏世界中的对象行为之间的关系,以及游戏世界状态与玩家感知(视觉、听觉、触觉、嗅觉等之间的关系)。在科幻电影中,玩家通过脑电波驾驶与控制装备;在现实的游戏中,通常使用操纵杆控制游戏中玩家扮演的角色。

1.1 游戏交互模式设计

Adams 认为交互设计是用户体验的核心内容,游戏输入装备的功能和性能会影响玩家在游戏中的行为选择。Adams 从游戏设计角度给出了交互设计的要点。游戏典型的交互模型包括:

Adams 对交互模型中常见的设计问题做了一些总结:

如果你对游戏交互设计感兴趣,请阅读游戏设计教材,Adams《游戏设计基础》!

1.2 游戏创新方法

游戏创新存在比较明显的鄙视链现象。用专业输入装备玩游戏的鄙视用手机玩游戏、Unreal开发者鄙视Unity开发者,这些容易理解,创新也分等级就难以理解了。 Quake engine的作者约翰·卡马克,为什么要加入 Oculus Rift 团队,并出任首席技术专家?

1、游戏创新第一层:交互装备创新

说到游戏交互装备创新,最厉害的参与者是 Apple、Microsoft、Nintendo、Sony,它们都是实力雄厚的大厂。在 AR/VR 与 物联网 时代 HTC、Oculus 以及其他厂商也积极融入其中。也许有一天,小米的各种 IoT 外设成为现代游戏元素的一部分。(IoT 游戏?2019年的预言,未来会不会流行呢?

以 Nintendo 的《口袋妖怪/精灵宝可梦》系列为例,第一代游戏掌机就配备的游戏;2006 年,任天堂发布了新一代游戏主机Wii,Wii配套的新款游戏手柄第一次将体感动作引入了游戏,体感装备出现后,用户们第一次发现原来除了传统的手柄按键控制之外,自己还可以直接用身体动作来控制屏幕上的游戏人物,《精灵宝可梦》出现了许多新玩法;2016年,《精灵宝可梦GO》更是现象级游戏,将现实地图与GPS位置引入游戏,预示 AR 游戏时代的到来。

Microsoft,首创带力反馈游戏手柄;人体识别体感装置 Kinect ;全息眼镜 HoloLens。这些装备改变了人机交互方式,游戏更好用于医疗、复杂环境的仿真与教学。

Apple 就不用说了。手机游戏几乎伴随智能手机成长。手机中许多传感器几乎就是为游戏而生。多点触摸、3d Touch,以及今天 Apple “奇丑无比” 的双肩屏(AR kit 需要这个传感器),哪个不瞄准游戏交互的制高点。

因此,运用现代交互与呈现技术是游戏创新的首选(仅对学生而言)。

2、游戏创新第二层:机制创新

通常游戏竞赛都是聚焦这个层面,具体包括:

3、游戏创新第三层:以客户为中心的创新

对于商业公司挣钱才是第一要素。因此,他们更希望是较小的风险和较高的收益,或者是砸钱易出效果类型。例如:“吃鸡”类游戏很流行,大家都忙推这类游戏。同类游戏,大家 PK 什么呢?

4、创新选择

体验、体验、新体验!!!

游戏基本形式:

1.3 常见游戏输入设备

1、经典“三宝”

2、手机游戏输入设备

3、IoT 与 其他设备

2、Unity 输入处理

维护中的章节

2.1 输入信息处理基本模型

2.2 JoyStick – 虚拟轴与按键

public class Joystick : MonoBehaviour {

	public float speedX = 10.0F;
	public float speedY = 10.0F;

	// Update is called once per frame
	void Update () {
		float translationY = Input.GetAxis("Vertical") * speedY;
		float translationX = Input.GetAxis("Horizontal") * speedX;
		translationY *= Time.deltaTime;
		translationX *= Time.deltaTime;
		//transform.Translate(0, translationY, 0);
		//transform.Translate(translationX, 0, 0);
		transform.Translate(translationX, translationY, 0);

		if (Input.GetButtonDown ("Fire1")) {
			Debug.Log ("Fired Pressed");
		}
	}
}

2.3 拾取游戏世界的对象

光标拾取物体程序

public class PickupObject : MonoBehaviour {

	public GameObject cam;

	// Update is called once per frame
	void Update () {
		if (Input.GetButtonDown("Fire1")) {
			Debug.Log ("Fired Pressed");
			Debug.Log (Input.mousePosition);

			Vector3 mp = Input.mousePosition; //get Screen Position

			//create ray, origin is camera, and direction to mousepoint
			Camera ca;
			if (cam != null ) ca = cam.GetComponent<Camera> (); 
			else ca = Camera.main;

			Ray ray = ca.ScreenPointToRay(Input.mousePosition);

			//Return the ray's hit
			RaycastHit hit;
			if (Physics.Raycast(ray, out hit)) {
				print (hit.transform.gameObject.name);
				if (hit.collider.gameObject.tag.Contains("Finish")) { //plane tag
					Debug.Log ("hit " + hit.collider.gameObject.name +"!" ); 
				}
				Destroy (hit.transform.gameObject);
			}
		}
	}
}

程序要点:

光标拾取多个物体程序

public class PickupMultiObjects : MonoBehaviour {

	public GameObject cam;

	// Update is called once per frame
	void Update () {
		if (Input.GetButtonDown("Fire1")) {
			Debug.Log ("Fired Pressed");
			Debug.Log (Input.mousePosition);

			Vector3 mp = Input.mousePosition; //get Screen Position

			//create ray, origin is camera, and direction to mousepoint
			Camera ca;
			if (cam != null ) ca = cam.GetComponent<Camera> (); 
			else ca = Camera.main;

			Ray ray = ca.ScreenPointToRay(Input.mousePosition);

			//Return the ray's hits
			RaycastHit[] hits = Physics.RaycastAll (ray);

			foreach (RaycastHit hit in hits) {
				print (hit.transform.gameObject.name);
				if (hit.collider.gameObject.tag.Contains("Finish")) { //plane tag
					Debug.Log ("hit " + hit.collider.gameObject.name +"!" ); 
				}
				Destroy (hit.transform.gameObject);
			}
		}		
	}
}

性能与优化

3、面向对象的游戏编程

场景单实例

运用模板,可以为每个 MonoBehaviour子类 创建一个对象的实例。Singleten<T> 代码如图所示:

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;  
		}  
	}
}

场景单实例的使用很简单,你仅需要将 MonoBehaviour 子类对象挂载任何一个游戏对象上即可。

然后在任意位置使用代码 Singleton<YourMonoType>.Instance 获得该对象。

4、小结

5、作业与练习

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

如果你的使用工厂有疑问,参考:弹药和敌人:减少,重用和再利用

2、编写一个简单的自定义 Component (选做

如果你想了解跟多自定义插件或编辑器的话题,请参考:Unity3d自定义一个编辑器组件/插件的简易教程