基于Unity3D的迷宫类解谜游戏的设计与实现

基于Unity3D的迷宫类解谜游戏的设计与实现

摘要

近年来,随着科学技术的飞跃发展,各种科技产物也进入了每家每户,例如:电视,电脑,手机等,也有越来越多的人使用这些电子产品来消遣和娱乐。游戏,是当今许多年轻人娱乐手段中占比重较大的一项,甚至被一些人称之为“第九艺术”。合理适度的游戏能够让人们在模拟的环境下进行挑战和克服障碍,有助于帮助人们开发智力、锻炼思维和反应能力、培养合理规划能力等,大型网络游戏甚至还能培养团队精神和领导组织能力。

本课题选择使用当今最热门之一的游戏开发引擎Unity3D来制作游戏。Unity成立至今,已经逐渐实现了大众化、开源化。现在,Unity已经从一个游戏引擎成长成为了一个创作平台,跨越了游戏、VR/AR、影视动画、人工智能等多个领域。因此,学习好Unity在未来无论是从事游戏开发、3D网页开发、动画或者人工智能等行业,都会起到无法估量的作用。

本文拟制作一款迷宫类解谜游戏,玩家使用第一人称在对称式迷宫中寻找线索来推进游戏的进程。整个游戏的开发需要完成设计地图、解谜要素、第一人称视角的操控、UI界面以及敌人的AI。游戏设计过程中需要运用到一些数学算法,会用到动画系统以及状态机,要求设计者需要一定的逻辑思维能力以及创新思想,也需要对Unity引擎有较为熟悉的使用能力。开发出来的游戏具有一定的可玩性,除了锻炼设计者的编程能力和逻辑能力,更是旨在去理解解谜要素的设计思路。因此,本课题具有一定的研究价值。

关键词:游戏,第九艺术,Unity3D引擎,迷宫类解谜游戏开发


Design and implementation of maze puzzle game based on Unity3D

Abstract

In recent years, with the rapid development of science and technology, a variety of scientific and technological products have entered every household, such as TV, computer, mobile phone, etc. more and more people use these electronic products for recreation and entertainment. Game is one of the most important means of entertainment for many young people today. It is even called "the ninth art" by some people. Reasonable and moderate games can help people to challenge and overcome obstacles in a simulated environment, help people develop intelligence, train thinking and reaction ability, cultivate rational planning ability, etc. Large scale online games can even cultivate team spirit and leadership and organizational ability.

This topic chooses to use unity3d, one of the most popular game development engines, to make games. Since its establishment, unity has gradually realized popularization and open source. Now, unity has grown from a game engine to a creative platform, spanning games, VR / AR, film and television animation, artificial intelligence and other fields. Therefore, learning unity will play an immeasurable role in the future, whether it is engaged in game development, 3D web development, animation or artificial intelligence.

This paper intends to make a maze puzzle game, players use the first person to find clues in the symmetrical maze to promote the process of the game. The development of the whole game needs to complete the design map, puzzle solving elements, first person perspective control, UI interface and the enemy's AI. In the process of game design, we need to use some mathematical algorithms, animation system and state machine. It requires designers to have certain logical thinking ability and innovative ideas, and also need to be familiar with unity engine. The developed game has a certain playability, in addition to training the designer's programming ability and logical ability, but also aims to understand the design ideas of puzzle solving elements. Therefore, this topic has a certain research value.

Key Words: Game, The ninth art, Unity3D engine, Maze Puzzle Game development 


目    录

第1章 绪论

1.1 电子游戏的积极意义

1.2 电子游戏的发展趋势

1.3 研究意义与设计内容

1.4 论文组织

第2章 相关知识介绍

2.1 Unity3D引擎介绍

2.2 C#脚本语言介绍

2.3 解谜游戏的设计理念

第3章 游戏主要功能的设计与实现

3.1 标题界面

3.1.1 UGUI和TextMeshPro插件

3.1.2 背景音乐和音效

3.1.3 鼠标移入移出的音效和字体效果

3.1.4 鼠标点击事件

3.1.5 音量设置

3.2 迷宫地图场景

3.3 第一人称控制器

3.3.1 角色的移动功能

3.3.2 角色的跳跃功能

3.3.3 第一人称自由视角

3.3.4 射线碰撞检测

3.4 敌人AI的设计

3.4.1 敌人动画的设置

3.4.2 敌人自动搜索敌人的功能

3.4.3 敌人运动的功能

3.5 本章小结

4章 游戏内解谜元素

4.1 解谜游戏特性

4.2 本课题解谜元素的设计思路与灵感

4.3 部分解谜元素的设计与实现

4.3.1 旋转雕像

4.3.2 按顺序熄灭蜡烛

5章 游戏讲解展示

总结

参考文献

谢辞

第1章 绪论

1.1 电子游戏的积极意义

近年来,全世界的经济在飞速发展,游戏产业也在逐渐的走向成熟。游戏也成为了当今青少年乃至青年当中的热门话题。但是,现在社会对电子游戏的争议也非常的大,许多家长认为,电子游戏会让孩子沉迷其中,变得无法自拔,变成一无是处的废人,甚至很多盗窃、抢劫之类的社会问题也都是由于当事人沉迷游戏而又没有经济条件所引发的,所以,电子游戏应该被禁止。

尽管电子游戏带来的不利影响已经饱受人们诟病,但是也有学者认为电子游戏不仅仅只有不利影响,以Ferguson为代表的众学者们进行了有关方面的研究,他们认为现在电子游戏的缺点被人们所放大了,而并没有注意到电子游戏的积极影响[1]。

随着积极心理学的兴起,有关电子游戏的研究也指向了如何利用电子游戏来促进个体的发展。目前,已有研究证明电子游戏能够促进个体的认知发展[2]。首先,很多电子游戏需要玩家在游玩时注意到很多方面,例如在赛车类游戏中,玩家需要时刻注意路径的选择以及道路上存在的障碍物。因此,电子游戏可以一定程度上锻炼玩家的注意集中能力。再者,电子游戏还可以锻炼玩家的逻辑思维以及推理能力,例如在解谜类游戏当中,玩家需要通过各种游戏中所提供的线索来进行演算以及推理,进行“推理-常识错误-继续推理”的循环操作,这对于玩家的推理能力方面能得到不错的提升。还有,电子游戏可以丰富玩家的创造能力,在游戏中,玩家可以在虚拟的环境中尝试很多现实生活中无法做到的事情,例如搭建房屋、制作服装等,并且玩家在游戏当中不必承担各种现实问题的后果,因此,这能够让玩家大胆的去尝试各种新鲜事物,满足好奇心。这些都有利于玩家创造力的发展。

1.2 电子游戏的发展趋势

最早有记录的电子游戏诞生于1952年,是由A.S.Douglas所制作的一款简易的图形版本的井字过关游戏,运行于真空管计算机上。电子游戏在20世纪70年代初开始以一种商业娱乐媒体被引入,成为了20世纪70年代末日本、美国和欧洲一个重要的娱乐工业的基础。在1983年美国游戏业萧条事件及继而恢复后的两年,电子游戏工业经历了超过两个年代的增长,成为了达100亿美金的工业,并与电影业竞争成为世界上最获利的娱乐产业之一。

现如今,电子游戏已不仅仅只能运行在电脑上,更是能运行在各种平台上,例如:掌机、游戏主机、手机等,并且游戏内容和种类也变得更加多样化,极大的丰富了玩家的业余时间。如今,在国内甚至全世界的游戏开发商都在研究有关电子游戏产业的新产品,为了应对人们对游戏多样化的需求。

随着科技的不断创新,VR与AR技术的广泛应用也为电子游戏的发展提供了不小的助力。尽管目前,在VR/AR技术的应用上,仍然存在着一些问题,但是,这项技术可以更好的让玩家体会到游戏的交互体验,激发玩家的游戏乐趣[3]。电子游戏正逐渐称为一种塑造与传播文化的途径,2020年上线的国产游戏《原神》,就曾向外国玩家展示了中国的春节,起到了宣传我国文化的作用。因此,在未来,国家应该更多的对电子游戏赋予教育以及文化的意义,使其成为一种传播文化的途径。

1.3 研究意义与设计内容

解谜游戏属于益智游戏类型之一,并融合了其他类型游戏的特性,与单纯的益智游戏不同,它更加注重情节的设计与人物的塑造,能够将其他游戏的元素完美的融合在一起,解谜类游戏可以锻炼人的逻辑分析能力和思维敏捷性。尽管当下,人们更加追求短暂的游戏时间以及紧张刺激的快感,但这并不代表解谜游戏不优秀,它仍然值得去设计与研究开发。

Unity是当下开发创作当中最受欢迎的引擎之一,它已经从一个开发引擎成长成为了一个创作平台,跨越了游戏,VR/AR、影视动画、人工智能等多了领域,一直走在这些领域变革的前沿。因此,学习和了解有关Unity的相关技术操作,能够更好得跟上未来的3D发展潮流和趋势。

本课题是基于Unity3D的迷宫类解谜游戏的设计实现,按照课题的要求,必须充分了解Unity3D的各个组件,以及对脚本语言C#的基本知识,了解Unity3D游戏引擎的开发以及该引擎实现的功能。解决迷宫以及解谜系统的设计,完成对系统的需求分析、敌人的AI设计、解谜要素的分析设计、UI设计、代码实现以及测试。

主要的实现内容有:

(1)游戏的标题界面;

(2)迷宫地图的设计;

(3)解谜要素的设计;

(4)玩家与场景物体之间的交互功能;

(5)解谜的可视化UI界面;

(6)敌人的AI设计;

(7)游戏的完整打包,可以脱离Unity3D进行游玩。

1.4 论文组织

本文由五个章节所组成:

第一章:绪论。包括了电子游戏的积极意义、电子游戏的发展趋势、本课题的研究意义与设计内容以及本篇论文的论文组织。

第二章:相关知识介绍。介绍了设计实现迷宫类解谜游戏所使用到的Unity3D引擎、游戏所使用的C#脚本语言。简述了解谜游戏的设计理念。

第三章:游戏主要功能的设计与实现。分别对系统主要的功能包括标题界面、地图场景、第一人称控制器、敌人AI的设计与实现进行了阐述。

第四章:游戏内解谜元素。简述了解谜游戏的特性和本课题解谜元素的设计灵感。并介绍了本课题部分解谜元素的设计与实现。

第五章:游戏讲解展示。以文字配上部分图片,展示了本课题游戏。

论文的最后做了总结以及谢辞。


第2章 相关知识介绍

2.1 Unity3D引擎介绍

Unity是由Unity Technologies开发一个能轻松创建3D游戏、建筑可视化、实时三维动画等互动内容的、多平台的综合型游戏开发工具,是一个技术全面的专业游戏引擎。通过Unity简单的用户操作界面,用户可以完成很多工作[4]。

Unity3D是现如今大多数游戏开发团队的首选3D引擎,它不仅能制作3D游戏,在2D游戏的开发表现上也极为优秀。Unity3D不仅仅在游戏领域有广泛的应用,现在还广泛运用于虚拟现实、医学、动画影视等领域中,可以说其应用领域非常的广泛。

任何一个游戏开发,都需要给予物体合理性,Unity3D为开发人员准备了大量的包括光源、特效、贴图、动画、音效等一系列方便使用的组件,使用这些组件,可以很轻松的实现真实的光影效果。并且还可以赋予物体刚体、碰撞体等组件,使物体拥有重力、摩擦力等真实的自然物理特性,逼真的效果会让玩家觉得这是一个真实的物体。

2.2 C#脚本语言介绍

Unity支持多种语言作为脚本语言,因为目前Unity开发中,C#语言使用最为广泛,因此,本课题使用C#语言编写脚本。与其他平台的脚本语言不同,Unity的脚本需要附加在游戏对象上,以此来实现特定的功能。

Unity中的C#脚本基于开源的.NET平台Mono,在语法上与微软公司的标准C#语言相似,但是两者之间仍然存在着一些差别。首先,Unity中的绝大多数脚本需要绑定在GameObject游戏对象上去控制对象的行为,并且脚本需要继承MonoBehaviour类。其次,C#脚本中类名与文件名必须一致,否则当脚本挂载到游戏对象上时会报错。然后,应尽量避免使用构造函数,并且不要在构造函数中初始化任何变量,要在Awake和Start方法中初始化变量[5]。在Unity中使用的C#脚本语言与标准的C#语言仍然还有许多不同,这里便不一一列举。

2.3 解谜游戏的设计理念

解谜游戏的设计不是一件简单的事情,好的解谜游戏设计能够让玩家解开谜题时有巨大的成就感,并且让玩家能够享受解谜的过程。设计出好的解谜游戏往往需要注意到一些容易被忽视的细节。

主要需要注意到以下几点:一、需要让玩家清楚的了解解谜的目标。这一步是非常重要的,如果忽视了这一点,会使得玩家无法确定为什么他们需要做这些,无法理解设计者的意图,丧失游戏兴趣。二、让玩家了解到解谜物品和大致解决方案。在玩家面对一个谜题时,设计者需要让玩家知道解决问题的原理,否则的话玩家会像无头苍蝇一样不知所措,并且可能在胡乱尝试中偶然解开谜题,导致玩家无法体验到解谜的乐趣。三、需要把握好平衡点,让谜题难道逐渐提升。在刚开始谜题和解谜过程不需要过于繁琐和困难,这会让很多还不熟练的新手玩家望而却步,逐渐提升谜题的难度,可以让玩家获得成长的喜悦[6]。

总而言之,在设计解谜游戏的时候,设计者需要站在玩家的角度去思考问题,如何设计谜题能够让玩家得到最大的享受。游戏从来都不是设计者的个人表现,而是需要把玩家和设计者看作一个整体来设计,这样设计出来的游戏,才能够吸引玩家。


第3章 游戏主要功能的设计与实现

本章根据主要功能模块的划分来进行介绍,主要功能模块有:(1)标题界面;(2)地图场景;(3)第一人称控制器;(4)敌人AI;这几个部分。下面是功能模块划分图。

图3-1 功能模块划分图

3.1 标题界面

标题界面就是玩家点开游戏运行的时候展示的界面,界面包括游戏标题、开始游戏、加载游戏、设置和退出游戏这几个部分。标题界面的设计如图3-2所示:

图3-2 标题界面

此界面在Start场景中,使用UGUI系统制作而出,下面将详细介绍该界面的实现方法。

3.1.1 UGUI和TextMeshPro插件

在Unity4.6以前的原生GUI系统中,除了GUIText、GUITexture和3D Text可以在编译器直接编译外,其他的GUI控件都只能通过静态成员函数在脚本中添加,非常的不方便。因此,许多Unity开发者往往借助第三方插件来完成UI界面的设计,比如NGUI等。

但是从Unity4.6版本开始,Unity重新设计了GUI系统,并且将新版的GUI系统命名为UGUI系统。这套系统参考了NGUI的设计方式,提供了非常丰富的GUI组件并且可以直接在Inspector视图上为GUI控件绑定事件。因此,现在大部分的Unity开发者都选择使用UGUI这套方便快捷的UI制作系统。

而TextMeshPro就是基于UGUI系统所衍生出来的一个插件。比起传统的UGUI中的Text控件,TextMeshPro能够为开发者带来更好的开发体验。首先,TextMeshPro拥有优秀的渲染功能,能够让文本在不同分辨率和不同位置下都渲染出清晰的效果,并且它还能够不同的着色器来实现对其、描边、阴影等效果,表现更加出色且使用方便快捷。

3.1.2 背景音乐和音效

在游戏标题界面中,背景音乐是必不可少的一项,并且为了让玩家有点击、移动鼠标的反馈,本课题也同时制作了鼠标移动和鼠标点击的音效。下面是背景音乐的Inspector视图:

图3-3 背景音乐Inspector视图

其中最主要的就是Audio Source控件,这里只说明关键的部分。

(1)Play On Awake属性是当其为true时,则在场景运行时便播放音频,因为这里时背景音乐,所以勾选,但是鼠标的点击声不勾选。

(2)Loop属性是当其为true时,则循环播放音频,背景音乐需要勾选,鼠标点击声不勾选。

(3)Volume属性是播放音频时的音量大小。

3.1.3 鼠标移入移出的音效和字体效果

在标题界面需要玩家通过鼠标移入或者点击不同的选项,需要完成字体颜色的变化和不同的音效,让其拥有互动性。以下是关键代码和操作:

首先要引用命名空间TMPro,同时该类还需要继承IPointerEnterHandler, IPointerExitHandler, IpointerClickHandler

  1. 定义变量:

//鼠标移入声音

private AudioSource mouseEnterAudio;

//鼠标点击声音

private AudioSource mouseClickAudio;

(2)在Awake方法中通过物体名称获取到鼠标的AudioSource组件:

private void Awake()

{

mouseEnterAudio = GameObject.Find("MouseEnter_audio").GetComponent<AudioSource>();

mouseClickAudio = GameObject.Find("MouseClick_audio").GetComponent<AudioSource>();

}

(3)鼠标点击的方法,当鼠标点击的时候,获取点击的文本组件,修改字体颜色,并且播放鼠标点击音效,鼠标移入和移出的方法同理:

public void OnPointerClick(PointerEventData eventData)  //鼠标点击button事件

{

//修改颜色(R,G,B,A)为(236, 67, 0, 255)

textColor.GetComponent<TMP_Text>().color = new Color32(236, 67, 0, 255);

//播放鼠标点击声音   

    mouseClickAudio.Play(0);

}

(4)将脚本挂载到对应的Button上,并且将Button下的Text组件拖入TextColor中,如图3-4所示:

图3-4 挂载到Button上的脚本设置

这样便可以实现鼠标移入移出点击时对应选项字体颜色变化,并且移入和点击时会播放音频的效果。

3.1.4 鼠标点击事件

现在需要完成的是当玩家点击不同选项的时候,需要执行不同的鼠标点击内容。首先,当玩家点击“New Game”时,需要完成场景的切换。关键代码和操作如下:

第一步需要引用命名空间UnityEngine.SceneManagement,并且将需要切换的场景放入File->Build Setting->Scenes In Build中。然后写一个跳转界面的方法:

//点击"New Game"切换场景

public void OnNewGameClick()

{

SceneManager.LoadScene("Main");

}

最后在New Game的Button控件下的Onclick方法中,添加绑定了该脚本的组件,并选中上面的OnNewGameClick方法。如图3-4所示。

图3-5 Button控件上的Onclick方法设置

这样,当玩家点击New Game时,界面将会跳转到游戏场景。下面是关闭游戏的关键代码:

//点击"Quit"退出游戏

public void OnQuitClick()

{

UnityEditor.EditorApplication.isPlaying = false;

Application.Quit();

}

当玩家点击Option时,需要进入音量设置界面,这就需要点击时关闭当前UI界面,打开设置UI界面。关键代码如下:

//点击"Options"进入设置界面

public void OnOptionsClick()

{

//关闭标题界面

titleInterface.SetActive(false);

//打开设置界面 

settingInterface.SetActive(true);

}

3.1.5 音量设置

当玩家点击Options时,切换至音量设置界面,在这个界面中,玩家可以自由调节背景音乐和音效的大小,同时可以选择是否静音。音量设置界面如下:

图3-6 音量设置界面

具体实现操作如下:

(1)添加一个Panel组件作为载体,设置半透明的背景颜色,将场景作为背景;

(2)添加Text组件,包括显示音量和音效、音量音效大小百分比数字、静音这几个文本,放在合适的位置上;

(3)添加Slider和Toggel组件分别来控制音量音效的大小和是否静音的勾选框;

(4)创建管理音量的脚本,在脚本中获取到音量音效的大小和是够静音的参数;

(5)通过获取的Toggel组件的参数来判断是否关闭音乐,代码如下:

//静音背景音乐

public void SetMainMusicMute(bool arg0)

{

if (isMuteMainMusic)

{

isMuteMainMusic = false;

}

else

{

sMuteMainMusic = true;

   }

mainMusic.mute = isMuteMainMusic;

}

(6)将获取到的Slider组件的值赋值给音量大小,并修改显示在界面上的音量大小数值,代码如下:

//调节背景音乐大小

public void MainMusicValueChangeCheck()

{

mainMusic.volume = mainMusicSlider.value;

mainMusicVolumeText.text = string.Format("{0:F1}%", mainMusicSlider.value * 100);

}

(7)将脚本挂载到对应组件上,并设置对应控件的事件即可完成操作。

3.2 迷宫地图场景

迷宫类解谜游戏当中必要元素之一便是迷宫,由于本人技术有限,在搭建迷宫场景时,使用的方法是,下载小模块化的地图元素,然后将其一个一个拼接在一起完成整张地图。整张地图称左右对称分布。地图总览如下:

图3-7 地图总览

3.3 第一人称控制器

本课题中,玩家所使用的是第一人称视角的操控方式,因此,需要完成的功能有:角色移动、跳跃、以及随着鼠标的自由视角 。

第一人称角色的控制,主要使用了CharacterController组件,该组件是Unity为了使开发者能方便的开发第一人称视角的游戏而封装的一个组件,相当于一个刚体,会表现出一些物体效果。通过这个组件可以很方便的开发出第一人称视角的操控。

3.3.1 角色的移动功能

想让玩家通过按下键盘的按键来操控角色的移动,只需要监控玩家按下对应按键时按照一定比例移动角色即可。我们需要先设定好玩家的移动速度,然后当玩家按下方向键时,将获取到的输入值分别以水平和垂直方向乘以移动速度,Input.GetAxis()函数可以完成监听键盘方向键获取移动参数的功能,然后再按照对应的方向移动角色模型。具体关键代码如下:

//水平方向移动值

horizontalMove = Input.GetAxis("Horizontal") * moveSpeed;  

//垂直方向移动值

verticalMove = Input.GetAxis("Vertical") * moveSpeed;

//将方向信息存储到dir变量中      

dir = transform.forward * verticalMove + transform.right * horizontalMove;  

cc.Move(dir * Time.deltaTime);

当角色处于地面并且产生了水平或者垂直方向的位移时,需要播放脚步声的音频,代码如下:

//管理音频的播放

void AudioManagement(bool isGround, float horizontalMove, float verticalMove)

{

    AudioSource audioSource = GetComponent<AudioSource>();

//当角色处于地面,且存在水平或垂直方向位移时,播放音频

    if (isGround && (horizontalMove != 0 || verticalMove != 0))  

    {

        if (!audioSource.isPlaying)

        {

            audioSource.Play();

        }

    }

    else

    {

        audioSource.Stop();

    }

}

3.3.2 角色的跳跃功能

当玩家按下空格键时,首先需要检测玩家是否在地面上且处于可以跳跃的地面,然后赋予角色一个向上的跳跃速度,并设定好重力值,按照时间和重力改变向上的加速度。这需要给地面设置层级,如图3-8所示:

图3-8 层级设置

检测角色是否在地面上的代码:

//触碰地面则返回true,否则返回false

isGround = Physics.CheckSphere(groundCheck.position, checkRadius, groundLayer);

当检测到玩家按下空格键时,且角色处于地面上,则给角色一个向上的加速度,然后根据重力逐渐减小加速度,关键代码如下:

//跳跃

if (Input.GetButtonDown("Jump") && isGround)

{

    velocity.y = jumpSpeed;

}

//根据重力 每秒物体往下掉落的值

velocity.y -= gravity * Time.deltaTime;

cc.Move(velocity * Time.deltaTime);

最后将脚本挂载到角色物体上即可,如图3-9:

图3-9 角色移动和跳跃脚本挂载设置

3.3.3 第一人称自由视角

通过鼠标的转动来实现摄像机视角的转动,需要监听鼠标的移动,并且通过转动角色的模型,让摄像机的视角跟着一起转动。关键代码如下:

mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;

mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

player.Rotate(Vector3.up * mouseX);

当通过Quaternion.Euler()函数来将视角上下移动时,因为这个函数会返回-1到1之间的参数,当鼠标不动时则会回弹到0,因此会导致无法上下移动视角,并且上下转动视角时会产生卡顿,所以需要写一个防止回弹的方法。关键代码如下:

xRotation -= mouseY;

//限制视野旋转范围

xRotation = Mathf.Clamp(xRotation, -70f, 70f);  

transform.localRotation = Quaternion.Euler(xRotation, 0, 0);

将脚本挂载到主摄像机上就可以完成视角的控制,如图3-10所示:

图3-10 视角控制脚本挂载设置

3.3.4 射线碰撞检测

3D场景与2D场景不同,系统需要判断玩家所触发的物品是否在可执行的范围内,这就需要运用到空间当中的射线检测。当玩家按下交互键时,从角色主视角摄像机发出一条检测射线,由此可以获取到玩家想要交互的对象,从而进行操作[7]。关键代码:

if (Input.GetKeyDown(KeyCode.E))

{

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

//设置碰撞变量

RaycastHit hit;

if (Physics.Raycast(ray, out hit, 0.8f))

{

print("发生了射线碰撞:" + hit.transform.name);

}

}

3.4 敌人AI的设计

在冒险类、迷宫类游戏中,敌人是不可缺少的模块之一,有了敌人这一要素之后,会让游玩体验变得更加紧张与刺激。在设计敌人的时候,需要考虑到很多因素,包括敌人动画设置,敌人如何搜寻玩家以及敌人的运动功能,可以说,敌人AI的设计是相对来说较为复杂的一个模块。

3.4.1 敌人动画的设置

想要敌人在运动起来的时候展现出奔跑的动作,这就需要运用到Unity的Mecanim动画系统。

Mecanim动画系统是Unity公司从Unity4.0版本以后开始引入的新的动画系统。它提供了动画重定向模式,可以很方便的将动画从一个模型移到另一个模型上。并且还提供了可视化的Animator编辑器,可以直观地看到动画参数和状态之间的过渡[8]。

本课题用到了Animator组件简单地使用了2个动画来完成敌人的站立状态和奔跑状态,状态机如图所示:

图3-11 动画状态机

在Transition中需要将Has Exit Time属性取消勾选,这个属性为true时,会将当前运行的动画执行完毕之后,再执行下一个动画。但是在游戏中,无法确定敌人会在什么时候开始运动,所以将其属性设为false。

3.4.2 敌人自动搜索敌人的功能

在设计敌人AI的时候,设置敌人的仇恨值范围,并且能够察觉到角色的位置是最为重要的功能。首先,我们需要运用到Unity3D导航系统Navigation。Navigation是实现物体动态自动寻路的一种技术,它将游戏中的场景分析简化成网格,然后通过网格的关键点来实现自动寻路的功能。用户需要给需要导航的对象添加Nav Mesh Agent组件,然后设置好需要导航的范围,并烘焙场景[9]。

然后是需要完成敌人的仇恨值的设置,首先,可以给敌人对象添加一个Sphere Collider组件,勾选上Is Trigger属性用来当作触发器。但是,仅仅设置球形的仇恨范围并不完全合理,因为正常情况下,敌人是无法看到身后的,因此,还需要模拟设置敌人的视野范围。假设敌人的视野范围是角度为110°的扇形范围,当玩家进入球形的触发器后,可以通过从敌人身上发射一条射线用来计算玩家与敌人正前方直线之间的夹角度数,若这个度数小于110°的一半也就是55°时,则玩家进入了敌人的视野范围。

图3-12 当Player进入了Enemy触发器时的状态

这时设置一个变量代表角色是否在敌人视野范围内,方便后面进行操作和判断。有关实现Enemy视野触发器的关键代码如下:

void OnTriggerStay(Collider other)

{

//当角色进入敌人触发器时

if (other.gameObject == player)

{

direction = other.transform.position - transform.position;

angle = Vector3.Angle(direction, transform.forward);

//当angle小于fieldOfViewAngle的一半时,表示Player对象在Enemy的观测区

if (angle < fieldOfViewAngle * 0.5f)

{

RaycastHit hit;

//用Physics.Raycast做线性探测,若找到Player对象则设置playerInSight为true

if (Physics.Raycast(transform.position , direction.normalized, out hit, col.radius))

if (hit.collider.gameObject == player)

playerInSight = true;

}

}

}

3.4.3 敌人运动的功能

当完成敌人的自动搜寻角色之后,就需要完成敌人的运动功能来完成大部分敌人模块的功能。具体步骤如下:

(1)需要让敌人在发现角色的时候转动方向来面对角色,而不会造成侧着跑步甚至倒着跑步的情况。这需要分别去获取敌人当前的角度、面向角色的角度,然后通过Mathf.MoveTowardsAngle方法实现敌人对象的旋转。代码如下:

    void RotationTo()

{

//当前角度

Vector3 oldAngle = enemyTransform.eulerAngles;  

//面向角色的角度

enemyTransform.LookAt(playerTransform);    

//目标的方向,Y轴方向

float target = enemyTransform.eulerAngles.y;  

//旋转的速度,时间乘旋转角度

float speed = enemyRotSpeed * Time.deltaTime;  

//获得旋转角度

float angle = Mathf.MoveTowardsAngle(target, target, speed);  

//旋转

enemyTransform.eulerAngles = new Vector3(0, angle, 0);  

}

(2)获取到敌人当前的动画状态,当敌人处于静止(Idle)状态,并且没有处于转换状态时,这时可以将Idle动画状态设置为false,一方面因为已经将Unity动画设置里面的Has Exit Time属性设置为了false,另一方面是为了避免和后面的动画冲突。当发现角色的时候,获取角色的坐标位置,并激活指向奔跑(Run)状态的通道。代码如下:

//当敌人处于Idle状态 且 没有处于转换状态

if (stateInfo.fullPathHash == Animator.StringToHash("Base Layer.Idle") && !anim.IsInTransition(0))

{

    anim.SetBool("Idle", false);

    timer -= Time.deltaTime;  

    if (timer > 0)

    {

        return;

    }

//发现角色    

if (enemySight.playerInSight)

    {

        //把计时器重置为1

timer = 1f;

//重新获取自动寻路的位置  

        nav.SetDestination(playerTransform.position);

//激活指向run的通道  

        anim.SetBool("Run", true);  

    }

}

(3)当敌人处于奔跑状态且没有处于转换状态时,关闭Run的状态,通过寻路组件中nav.Move方法实现敌人的寻路移动。

//敌人的自动寻路

void MoveTo()

{

//定义敌人的移动量

    float speed = enemyMoveSpeed * Time.deltaTime;

//通过寻路组件的Move方法实现寻路移动 

    nav.Move(enemyTransform.TransformDirection(new Vector3(0, 0, speed)));  

}

当角色不在仇恨范围且敌人不在初始位置时,则让敌人返回初始位置。

if (!enemySight.playerInSight && !isMoveBack)

{

nav.SetDestination(initialEnemyPostion.transform.position);

timer = 1f;

anim.SetBool("Run", true);

}

当角色不在仇恨范围内并且敌人已经回到了初始的位置,就将敌人切换到Idle状态,当均不满足上述条件时,代表敌人仍然在追踪角色,则保持Run的状态。

(4)当敌人正在追踪角色的时候,将背景音乐切换成紧张的音乐,以此来营造氛围,可以通过Mathf.Lerp线性插值的方式来实现音量大小的渐变,使切换背景音乐时不会显得很突兀。关键代码如下:

void MusicFading()

{

//当敌人看见了角色,即进入了危险状态,此时播放panicAudio,同时使music静音

if (enemy.playerInSight)  

{

music.volume = Mathf.Lerp(music.volume, muteVolume, musicFadeSpeed * Time.deltaTime);

panicAudio.volume = Mathf.Lerp(panicAudio.volume, normalVolume, musicFadeSpeed * Time.deltaTime);

}

//角色处于安全位置时,播放正常的背景音乐music

else  

{

music.volume = Mathf.Lerp(music.volume, normalVolume, musicFadeSpeed * Time.deltaTime);

panicAudio.volume = Mathf.Lerp(panicAudio.volume, muteVolume, musicFadeSpeed * Time.deltaTime);

}

}

3.5 本章小结

本章主要从游戏的主要模块功能进行了展示、设计与实现,主要分为以下几个部分:

(1)标题界面,其中运用了UGUI系统和TextMeshPro文本插件,主要实现了场景的切换功能、音乐的控制功能和鼠标事件;

(2)地图场景,展示了本迷宫的场景鸟瞰图;

(3)第一人称控制器,主要实现了移动、跳跃、视角移动、射线碰撞检测的功能;

(4)敌人AI,主要实现了敌人动画设置,自动搜索与寻路系统、运动功能。


第4章 游戏内解谜元素

4.1 解谜游戏特性

解谜游戏按照不同的应用情况分析,主要具有娱乐性、逻辑性、创造性、教育性四个特性[10]。

(1)娱乐性

解谜游戏本身属于游戏范畴,游戏的初衷就是为了丰富人们的娱乐生活,通过在游戏中设计目标,让玩家尝试与现实生活不同的体验,并最后完成游戏目标,可以让玩家获得很大的成就感,这一过程就可以给玩家带来娱乐性。

解谜游戏还可以通过视觉、听觉等元素,并结合解谜要素,让玩家在推理游戏内容的同时,感受到游戏的氛围,拥有很高互动性的同时也给了玩家电影式的体验享受。

(2)逻辑性

解谜游戏主要区别于其他类型游戏的要素就是谜题,任何的谜题都需要具有逻辑性,没有逻辑的谜题不会让玩家有很好的游戏体验。

(3)创造性

游戏的创造性往往是一个游戏吸引玩家的主要元素之一,解谜类游戏可以通过在剧情、谜题本身以及解谜过程等内容上做出创新,达到吸引玩家的目的。一般来说,解谜游戏的创造性基于游戏内容的开放度,一个开放度很低的游戏,很难让玩家拥有不同的解谜手段与过程。

(4)教育性

一般而言,游戏对于玩家的教育性体现在对玩家逻辑思维以及反应速度之类的锻炼上,优秀的游戏更是能够让玩家获得知识的累积甚至是道德情操的教育。解谜游戏更加锻炼了玩家的逻辑思维能力,并且在玩家解谜的过程中,往往需要一定的基础知识,这无形之中增加了玩家的知识储备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值