游戏flash脚本代码如何查看其代码

Cocos2d-html5新手入门
Cocos2D-html5是最新从Cocos2D-X团队中剥离出来的分支引擎,由Javascript语言为支持HTML5的浏览器编写而成。该引擎API源于Cocos2d-X,所以如果你此前有任何Cocos2d游戏引擎的相关经验,你就已经知道如何使用Cocos2d-html5。如果此前从未使用过Cocos2d游戏引擎,请放心本文将教会你入门所需的所有知识。
因为Cocos2D-html5是基于网络的游戏引擎,所以只要你能够访问文本编辑器,就可以在任何平台上编写应用程序,而且你可以在有网络浏览器的任何设备上运行应用程序,只要该浏览器支持HTML5!多么方便啊,所以这也是为什么我们说“未来尽在你的浏览器中”。
Javascript? Java脚本?
尽管有人担心“脚本语言”的效率,当然Java脚本肯定比C++慢,但是包括V8 Javascript引擎和硬件加速画面渲染工具在内的技术使得游戏开发成为可能。现在,移动电话上的硬件仍然缺少一些有效运行javascript的“吸引力”,但是Cocos2d-x团队正在研究 “供Cocos2d JSB脚本绑定”,也就是说,你在Cocos2d-html5上运行的同样的代码也可以在Cocos2d-X 及Cocos2d-iPhone上完美的运行,无需或者只需少许修改。所有这一切都被我们称为“在移动电话上的速度几乎和本地一样快”。
未来,我们将看到移动电话会变得非常强大,你将看到越来越多运行四核几GHz CPU的手机,而且还配备有专门的图形芯片。我们预计html5游戏将在这些手机上运行的和电脑上一样棒。
WebGL如何?
网页图形库(WebGL)是一种供网络使用的开放式图形语言(OpenGL),也就是3d硬件加速。
在撰写本文之时,Cocos2d-html5还没有通过WebGL实现。
一旦移动电话采用WebGL作为标准,Cocos2d-html5游戏将完美的在这些移动电话上运行,只要游戏设计师想得到,就没有做不到!
Cocos2d-html5 2.1.0及以上版本将有WebGL支持。
安装Cocos2d-html5
安装Cocos2d-html5就像解压一样容易,只需运行&index.html&!
1. 从官方网址&html5.cocos2d-x.org&下载Cocos2d-html5
2. 解压文件至任一目录
3. 打开&index.html&运行项目Hello World
4. 如果你在页面上看到了HelloWorld
5. 安装成功!
如果Hello World卡住了,出现黑屏,请不要慌,你使用的浏览器可能因为安全原因拦截了本地文件中的某些API。
有两种解决办法:
使用Firefox 12 ,Opera或者Safari, 这些浏览器对本地文件更友好。
在你的电脑上安装网站服务器(webserver)。
安装网站服务器(非强制性)
你可以有多种选择:
XAMPP : for windows, Mac, Linux.
WAMP : for windows
MAMP : for mac
下载适合你的网站服务器,
按照说明进行安装,
找到安装目录,
找到根目录,文件名应该类似于&htdocs& 或者 &www&
将经压缩后的Cocos2d-html5文件复制到进来
将你的浏览器指向&localhost&
你应该能看到如下画面:
调试Javascript代码对于网络开发人员来说应该是再熟悉不过的了。如今的浏览器已经内编有工具来帮助你开发Javascript应用。
对于大多数浏览器而言,只需按F12 就能打开开发人员工具,
(在Opera上,按Ctrl+ Shift + i)
(在Safari上,在“preference”里找到“高级”,然后选择“在目录栏里显示开发目录”以打开开发人员工具,右击后选择“查看组件”)
我们推荐使用Google Chrome,因为该浏览器最为方便,而且配备有各种功能。
更多有关如何使用Chrome 开发人员工具(Chrome Developer Tools)的详情请参看以下网址文件:
在这里,你可以访问控制台,它能够输出游戏引擎内部的任何错误。你也可以在控制台中输入Javascript命令。
让Hello World更有趣
Hello World默认的样本代码里,背景是一个Cocos2d-html5标志以及“Hello World”的字样,实在是太单调乏味了。
这是一个Cocos2d-html5的迷你教程,可以让你将Hello World的模版变得更加有趣。
打开HelloHTML5World目录中的“src/myApp.js”。
你第一眼注意到的就是这个
第27行:var Helloworld = cc.Layer.extend()
这是Cocos2d-html5中对象继承的方式,来源于John Resig's javascript Inheritance,在这里表示我们在CCLayer中定义了一种新的被称为Helloworld的类。
其他的对于任何一个此前使用过Cocos2d的人来说都在熟悉不过了,除了
第38行:this._super()
它表示运行此函数的父类版本。
开始进入正题!
找到第74行初始化背景精灵的地方
第74行:this.sprite = cc.Sprite.create(&res/HelloWorld.png&);
我们在第74行后面添加this.sprite.setRotation(180);,将它旋转180度,让它倒过来
现在,我们让它变小一点。
// add &HelloWorld& splash screen&
this.sprite = cc.Sprite.create(&res/HelloWorld.png&);
this.sprite.setPosition(size.width / 2, size.height / 2);
this.sprite.setScale(0.5);
this.sprite.setRotation(180);
预览一下我们做出的改变,现在效果图应该是这样的
让精灵动起来
首先,我们需要定义动作,我们希望将它变回原来的大小,所以,我们先来定义这个动作:
var scaleToA = cc.ScaleTo.create(2, 1, 1);
然后,我们定义另一个动作,将它转回原来的方向。
var rotateToA = cc.RotateTo.create(2, 0);
在这里,我们定义了两个动作,持续时间为2秒,一个是将它的宽和高变回原来的大小,另一个是将它转回原来的方向
现在,你可以让精灵运行这一动作了
// add &HelloWorld& splash screen&
this.sprite = cc.Sprite.create(&res/HelloWorld.png&);
this.sprite.setPosition(size.width / 2, size.height / 2);
this.sprite.setScale(0.5);
this.sprite.setRotation(180);
var rotateToA = cc.RotateTo.create(2, 0);
var scaleToA = cc.ScaleTo.create(2, 1, 1);
this.sprite.runAction(rotateToA);
这个介绍很清晰详尽了吧!但是,如果我们希望播放连续的几个动画怎么办呢?这也不成问题
// add &HelloWorld& splash screen&
this.sprite = cc.Sprite.create(&res/HelloWorld.png&);
this.sprite.setPosition(size.width / 2, size.height / 2);
this.sprite.setScale(0.5);
this.sprite.setRotation(180);
var rotateToA = cc.RotateTo.create(2, 0);
var scaleToA = cc.ScaleTo.create(2, 1, 1);
this.sprite.runAction(rotateToA);
this.sprite.runAction(cc.Sequence.create(rotateToA, scaleToA));
//or at the same time
// this.sprite.runAction(cc.Spawn.create(rotateToA, scaleToA));
恭喜,你已经学会如何将一个单调乏味的HelloWorld样本代码变成一个至少不那么无趣的动画HelloWorld!现在,或许你都可以在Cocos2d-html5中编写ppt了!
我希望这份有关Cocos2d-html5的简介能够对你有帮助,也希望你感觉Cocos2d-html5的搭建、学习以及框架的使用都很容易。有了Cocos2d-html5,你可以高效的完成你的游戏,并在浏览器之间运行这些游戏。
如果你觉得满意,请登录推特: ,让我们知道,你的到访是我们前进的不竭动力。
Follow us:您现在的位置: &
PHP 编写的 25个游戏脚本
PHP 编写的 25个游戏脚本
无论是一个人玩简单的使用纸和笔的游戏,还是同一群人玩复杂的桌面角色扮演游戏,或者任意类型的联机游戏,  开始之前   作为一名游戏专家/设计者和开发人员,我经常发现自己在运行、规划和玩游戏时,很少编写有用的实用程序和脚本。有时我需要快速想出创意。其他时候,我只需要编出一大堆非玩家角色(Non-Player Character,NPC)的名称。偶尔,我还需要处理数字、处理一些异常或者将一些文字游戏集成到游戏中。只需事先完成一点脚本工作,就可以更好地管理这些任务。   本文将探究在各种游戏中可以使用的 10 个基本脚本。代码压缩包包含所讨论的每个脚本的完整源代码,并且可以在 chaoticneutral 查看脚本实际运行情况。   我们将快速地介绍这些脚本。有关如何查找主机或设置服务器的内容将不做介绍。有很多 Web 托管公司提供 PHP,并且如果需要安装自己的 PHP,XAMPP 安装程序使用起来也十分简单。我们将不会花费大量时间谈论 PHP 最佳实践或游戏设计技术。本文介绍的脚本易于理解、使用简单并可以快速掌握。   简单的掷骰器   许多游戏和游戏系统都需要骰子。让我们先从简单的部分入手:掷一个六面骰子。实际上,滚动一个六面骰子就是从 1 到 6 之间选择一个随机数字。在 PHP 中,这十分简单:echo rand(1,6);。   在许多情况下,这基本上很简单。但是在处理机率游戏时,我们需要一些更好的实现。PHP 提供了更好的随机数字生成器:mt_rand()。在不深入研究两者差别的情况下,可以认为 mt_rand 是一个更快、更好的随机数字生成器:echo mt_rand(1,6);。如果把该随机数字生成器放入函数中,则效果会更好。   清单 1. 使用 mt_rand() 随机数字生成器函数   复制代码 代码如下:  function roll () {   return mt_rand(1,6);   }   echo roll();   然后可以把需要滚动的骰子类型作为参数传递给函数。   清单 2. 将骰子类型作为参数传递   复制代码 代码如下:  function roll ($sides) {   return mt_rand(1,$sides);   }   echo roll(6); // roll a six-sided die   echo roll(10); // roll a ten-sided die   echo roll(20); // roll a twenty-sided die   从这里开始,我们可以继续根据需要一次滚动多个骰子,返回结果数组;也可以一次性滚动多个不同类型的骰子。但是大多数任务都可以使用这个简单的脚本。   随机名称生成器   如果正在运行游戏、编写故事或者一次性创建大批字符,有时会疲于应付不断出现的新名字。让我们看一看可用于解决此问题的一个简单随机名称生成器。首先,让我们创建两个简单数组 ― 一个用于名字,一个用于姓氏。 清单 3. 名字和姓氏的两个简单数组   复制代码 代码如下:  $male = array(   "William",   "Henry",   "Filbert",   "John",   "Pat",   );   $last = array(   "Smith",   "Jones",   "Winkler",   "Cooper",   "Cline",   );   然后就可以从每个数组中选择一个随机元素:echo $male[array_rand($male)] . ' ' . $last[array_rand($last)];。要一次性提取多个名称,只需混合数组并根据需要提取。 清单 4. 混合名称数组   复制代码 代码如下:  shuffle($male);   shuffle($last);   for ($i = 0; $i &= 3; $i++) {   echo $male[$i] . ' ' . $last[$i];   }   基于此基本概念,我们可以创建保存名字和姓氏的文本文件。如果在文本文件的每一行中存放一个名字,则可以轻松地用换行符分隔文件内容以构建源代码数组。 清单 5. 创建名称的文本文件   $male = explode('\n', file_get_contents('names.female.txt'));   $last = explode('\n', file_get_contents('names.last.txt'));   构建或查找一些好的名字文件(代码归档 中附带了一些文件),此后我们绝不再需要为名字烦恼。   场景生成器   利用构建名字生成器使用的相同基本原理,我们可以构建场景生成器。此生成器不但在角色扮演游戏中十分有用,而且在需要用到伪随机环境集合(可用于角色扮演、即兴创作、写作等情况)的情况下也十分有用。我最喜欢的游戏之一,Paranoia 在其 GM Pack 中包括了 “任务混合器(mission blender)”。任务混合器可用于在快速滚动骰子时整合完整任务。让我们整合自己的场景生成器。   考虑以下场景:您醒来后发现自己迷失于丛林中。您知道自己必须赶去纽约,但是不知道原因。您可以听到附近的狗叫声及清晰的敌方搜寻者的声音。您浑身发冷、不住颤抖,而且没有武器。该场景中的每一句话都介绍场景的特定方面:   “您醒来后发现自己迷失于丛林中” ― 这句话将建立设置。   “您知道自己必须赶去纽约” ― 这句话将描述目标。   “您可以听到狗叫声” ― 这句话将介绍敌人。   “您浑身发冷、不住颤抖,而且没有武器” ― 这句话将添加复杂度。   就像创建名字和姓氏的文本文件一样,首先分别创建设置、目标、敌人和复杂度的文本文件。代码归档中附带了样例文件。在拥有这些文件后,生成场景的代码与生成名称的代码基本相同。 清单 6. 生成场景   复制代码 代码如下:  $settings = explode("\n", file_get_contents('scenario.settings.txt'));   $objectives = explode("\n", file_get_contents('scenario.objectives.txt'));   $antagonists = explode("\n", file_get_contents('scenario.antagonists.txt'));   $complicati**** = explode("\n", file_get_contents('plicati****.txt'));   shuffle($settings);   shuffle($objectives);   shuffle($antagonists);   shuffle($complicati****);   echo $settings[0] . ' ' . $objectives[0] . ' ' . $antagonists[0] . ' '   . $complicati****[0] . "&br /&\n";   我们可以通过添加新文本文件向场景中添加元素,也可能希望添加多重复杂度。添加到基本文本文件中的内容越多,场景随时间的变化就越多。   牌组创建器(Deck builder)和装备(shuffler)   如果您要玩纸牌并且要处理与纸牌相关的脚本,我们需要用装备中的工具整合一副牌组构建器。首先,让我们构建一副标准纸牌。需要构建两个数组 ― 一个用于保存同花色的组牌,而另一个用于保存牌面。如果稍后需要添加新组牌或牌类型,则这样做将获得很好的灵活性。 清单 7. 构建一副标准扑克牌   复制代码 代码如下:  $suits = array (   "Spades", "Hearts", "Clubs", "Diamonds"   );   $faces = array (   "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",   "Nine", "Ten", "Jack", "Queen", "King", "Ace"   );   然后构建一副牌数组来保存所有纸牌值。只需使用一对 foreach 循环即可完成此操作。 清单 8. 构建一副牌数组   复制代码 代码如下:  $deck = array();   foreach ($suits as $suit) {   foreach ($faces as $face) {   $deck[] = array ("face"=&$face, "suit"=&$suit);   }   }   在构建了一副扑克牌数组后,我们可以轻松地洗牌并随机抽出一张牌。 清单 9. 洗牌并随机抽出一张牌   复制代码 代码如下:  shuffle($deck);   $card = array_shift($deck);   echo $card['face'] . ' of ' . $card['suit'];   现在,我们就获得了抽取多副牌或构建多层牌盒(multideck shoe)的捷径。   胜率计算器:发牌   由于构建扑克牌时会分别跟踪每张牌的牌面和花色,因此可以通过编程方式利用这副牌来计算得到特定牌的几率。首先每只手分别抽出五张牌。 清单 10. 每只手抽出五张牌   复制代码 代码如下:  $hands = array(1 =& array(), 2=&array());   for ($i = 0; $i & 5; $i++) {   $hands[1][] = implode(" of ", array_shift($deck));   $hands[2][] = implode(" of ", array_shift($deck));   }   然后可以查看这副牌,看看剩余多少张牌以及抽到特定牌的机率是多少。查看剩余的牌数十分简单。只需要计算 $deck 数组中包含的元素数。要获得抽到特定牌的机率,我们需要一个函数来遍历整副牌并估算其余牌以查看是否匹配。 清单 11. 计算抽到特定牌的几率   复制代码 代码如下:  function calculate_odds($draw, $deck) {   $remaining = count($deck);   $odds = 0;   foreach ($deck as $card) {   if ( ($draw['face'] == $card['face'] && $draw['suit'] ==   $card['suit'] ) ||   ($draw['face'] == '' && $draw['suit'] == $card['suit'] ) ||   ($draw['face'] == $card['face'] && $draw['suit'] == '' ) ) {   $odds++;   }   }   return $odds . ' in ' $   }   现在可以选出尝试抽出的牌。为了简单起见,传入看上去类似某张牌的数组。我们可以查找特定的一张牌。 清单 12. 查找指定的一张牌   复制代码 代码如下:  $draw = array('face' =& 'Ace', 'suit' =& 'Spades');   echo implode(" of ", $draw) . ' : ' . calculate_odds($draw, $deck);   或者可以查找指定牌面或花色的牌。 清单 13. 查找指定牌面或花色的牌   复制代码 代码如下:  $draw = array('face' =& '', 'suit' =& 'Spades');   $draw = array('face' =& 'Ace', 'suit' =& '');   简单的扑克发牌器   现在已经得到牌组构建器和一些工具,可以帮助计算出抽出特定卡的机率,我们可以整合一个真正简单的发牌器来进行发牌。出于本例的目的,我们将构建一个可以抽出五张牌的发牌器。发牌器将从整副牌中提供五张牌。使用数字指定需要放弃哪些牌,并且发牌器将用一副牌中的其他牌替换这些牌。我们无需指定发牌限制或特殊规则,但是您可能会发现这些是非常有益的个人经验。   如上一节所示,生成并洗牌,然后每只手五张牌。按数组索引显示这些牌,以便可以指定返回哪些牌。您可以使用表示要替换哪些牌的复选框来完成此操作。 清单 14. 使用复选框表示要替换的牌   foreach ($hand as $index =&$card) {   echo "&input type='checkbox' name='card[" . $index . "]'&   " . $card['face'] . ' of ' . $card['suit'] . "&br /&";   }   然后,计算输入 array $_POST['card'],查看哪些牌已被选择用于替换。 清单 15. 计算输入   复制代码 代码如下:  $i = 0;   while ($i & 5) {   if (isset($_POST['card'][$i])) {   $hand[$i] = array_shift($deck);   }   }   使用此脚本,您可以尝试找到处理特定一组牌的最佳方法。   Hangman 游戏   Hangman 实质上是一款猜字游戏。给定单词的长度,我们使用有限的几次机会猜这个单词。如果猜出了出现在该单词中的一个字母,则填充该字母出现的所有位置。在猜错若干次(通常为六次)后,您就输了比赛。要构建一个简陋的 hangman 游戏,我们需要从单词列表开始。现在,让我们把单词列表制作成一个简单的数组。 清单 16. 创建单词列表   复制代码 代码如下:  $words = array (   "giants",   "triangle",   "particle",   "birdhouse",   "minimum",   "flood"   );   使用前面介绍的技术,我们可以把这些单词移动到外部单词列表文本文件中,然后根据需要导入。   在得到单词列表后,需要随机选出一个单词,将每个字母显示为空,然后开始猜测。我们需要在每次进行猜测时跟踪正确和错误的猜测。只需序列化猜测数组并在每次猜测时传递它们,就可实现跟踪目的。如果需要阻止人们通过查看页面源代码侥幸猜对,则需要执行一些更安全的操作。   构建数组以保存字母和正确/错误的猜测。对于正确的猜测,我们将用字母作为键并用句点作为值填充数组。 清单 17. 构建保存字母和猜测结果的数组   复制代码 代码如下:  $letters = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',   'p','q','r','s','t','u','v','w','x','y','z');   $right = array_fill_keys($letters, '.');   $wrong = array();   现在需要一些代码来评估猜测并在完成猜字游戏的过程中显示该单词。 清单 18. 评估猜测并显示进度   复制代码 代码如下:  if (stristr($word, $guess)) {   $show = '';   $right[$guess] = $   $wordletters = str_split($word);   foreach ($wordletters as $letter) {   $show .= $right[$letter];   }   } else {   $show = '';   $wrong[$guess] = $   if (count($wrong) == 6) {   $show = $   } else {   foreach ($wordletters as $letter) {   $show .= $right[$letter];   }   }   }   在 源代码归档 中,可以看到如何序列化猜测数组并将该数组从一次猜测传递到另一次猜测中。   纵横字谜助手   我知道这样做不合适,但是有时在玩纵横拼字谜时,您不得不费劲地找出以 C 开头并以 T 结尾、包含五个字母的单词。使用为 Hangman 游戏构建的相同单词列表,我们可以轻松地搜索符合某个模式的单词。首先,找到一种传输单词的方法。为了简单起见,用句点替换缺少的字母:$guess = "c...t";。由于正则表达式将把句点处理为单个字符,因此我们可以轻松地遍历单词列表以查找匹配。 清单 19. 遍历单词列表   复制代码 代码如下:  foreach ($words as $word) {   if (preg_match("/^" . $_POST['guess'] . "$/",$word)) {   echo $word . "&br /&\n";   }   }   根据单词列表的质量及猜测的准确度,我们应当能够得到合理的单词列表以用于可能的匹配。您必须自己决定 “表示 ‘不按规则玩' 的由五个字母组成的单词” 的谜底是 “chest” 还是 “cheat”。   米德里比斯   米德里比斯是一款文字游戏,玩家在游戏中得到一个简短的故事并用同一类型的不同单词替换主要类型的单词,从而创建同一个故事的更无聊的新版本。阅读以下文本:“I was walking in the park when I found a lake. I jumped in and swallowed too much water. I had to go to the hospital.” 开始用其他单词标记替换单词类型。开始和结束标记带有下划线用于阻止意外的字符串匹配。 清单 20. 用单词标记替换单词类型   $text = "I was _VERB_ing in the _PLACE_ when I found a _NOUN_.   I _VERB_ed in, and _VERB_ed too much _NOUN_. I had to go to the _PLACE_.";   接下来,创建几个基本单词列表。对于本例,我们也不会做得太复杂。 清单 21. 创建几个基本单词列表   复制代码 代码如下:  $verbs = array('pump', 'jump', 'walk', 'swallow', 'crawl', 'wail', 'roll');   $places = array('park', 'hospital', 'arctic', 'ocean', 'grocery', 'basement',   'attic', 'sewer');   $nouns = array('water', 'lake', 'spit', 'foot', 'worm',   'dirt', 'river', 'wankel rotary engine');   现在可以重复地评估文本来根据需要替换标记。 清单 22. 评估文本   复制代码 代码如下:  while (preg_match("/(_VERB_)|(_PLACE_)|(_NOUN_)/", $text, $matches)) {   switch ($matches[0]) {   case '_VERB_' :   shuffle($verbs);   $text = preg_replace($matches[0], current($verbs), $text, 1);      case '_PLACE_' :   shuffle($places);   $text = preg_replace($matches[0], current($places), $text, 1);      case '_NOUN_' :   shuffle($nouns);   $text = preg_replace($matches[0], current($nouns), $text, 1);      }   }   echo $   很明显,这是一个简单而粗糙的示例。单词列表越精确,并且花在基本文本上的时间越多,结果就越好。我们已经使用了文本文件创建名称列表及基本单词列表。使用相同原则,我们可以创建按类型划分的单词列表并使用这些单词列表创建更加变化多端的米德里比斯游戏。   乐透机   全部选中乐透的六个正确号码 ―― 退一步说 ―― 在统计学上是不可能的。不过,许多人仍然花钱去玩,而且如果您喜欢号码,则查看趋势图可能很有趣。让我们构建一个脚本,该脚本将允许跟踪赢奖号码并在列表中提供选择次数最少的 6 个号码。   $picks = array(   array('6', '10', '18', '21', '34', '40'),   array('2', '8', '13', '22', '30', '39'),   array('3', '9', '14', '25', '31', '35'),   array('11', '12', '16', '24', '36', '37'),   array('4', '7', '17', '26', '32', '33')   );   很明显,这不足以成为绘制统计数据的基本文件。但是它是一个开端,并且足以演示基本原理。   设置一个基本数组以保存选择范围。例如,如果选择 1 到 40 之间(例如,$numbers = array_fill(1,40,0);)的号码,则遍历我们的选择,递增相应的匹配值。 清单 24. 遍历选择   复制代码 代码如下:  foreach ($picks as $pick) {   foreach ($pick as $number) {   $numbers[$number]++;   }   }   最后,根据值将号码排序。此操作应当会把最少选择的号码放在数组的前部。 清单 25. 根据值将号码排序   复制代码 代码如下:  asort($numbers);   $pick = array_slice($numbers,0,6,true);   echo implode(',', array_keys($pick));   通过有规律地向包含中奖号码列表的文本文件添加实际的乐透中奖号码,可以发现选号的长期趋势。查看某些号码的出现频率十分有趣。
&&&主编推荐
&&&热门试卷
&&&最新视频
&&&热门阅读
&&&最新问答
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-Unity 2D 系列教程 疯狂喷气机 添加激光 脚本 GUI
1055 次浏览 |
原文地址:/69675/make-game-like-jetpack-joyride-unity-2d-part-3
泰然翻译组:小荄、Verky。校对:glory。
如何用Unity 2D制作一个像疯狂喷气机的游戏——第三部分
这是关于如何用Unity 2D制作一个像疯狂喷气机的游戏的系列教程的最后一个部分。如果你落下了教程之前的部分,你最好先去完成之前教程的学习。它们分别是:和。
就像我在上个部分的结尾提到的那样,这个部分我们将享尽所有的乐趣。这将是走到这里的奖励。:)
在这个部分你将添加激光,硬币,音效,音乐甚至是视差滚动。好了,聊了够多了,让我们开始享受乐趣吧!
你可以继续使用你在第二部分创建的工程或者你也可以下载这个部分的初始工程。它们几乎是相同的。
如果你想要下载初始工程,请使用这个链接:
当你已经准备好打开RocketMouse.unity场景,就让我们开始吧!
老鼠飞过房间是很棒的,但是这个游戏的挑战在哪里呢?是时候添加一些障碍物了,还有什么比激光更酷的呢?:)
激光将被随机生成,以一个与生成房间的相同方式,所以你需要创建一个活动房屋。你还需要创建一个小脚本来控制激光。
这里是创建一个激光对象所需的步骤:
1.在Project视图找到laser_on精灵并且拖动它到这个场景。
注意:由于激光活动房屋将仅由激光它自己组成,你不需要将它放在原点或者类似于原点的其它地方。
2.在Hierarchy中选中它并且将它重命名为laser。
3.设置它的Sorting Layer为Objects。
4.添加Box Collider 2D要素。
5.将Box Collider 2D要素的Is Trigger属性设为可用的。
当Is Trigger属性是可用的,碰撞机将触发碰撞事件,但会被物理引擎忽视。换句话说,如果老鼠触碰到激光你将会被通知到。然而,激光不能阻止老鼠的移动。
这是非常方便的,这里可以给出很多理由。举个例子,如果老鼠在激光的顶部挂了,它将躺在激光上悬挂在空中。或者那老鼠也可以在触碰到激光后因为惯性再向前移动一小段距离,而不是从激光那里反弹回去。
除此之外,真的激光不是一些难的对象,所以通过将这个属性设置为可用的,你只是模仿真的激光。
6.设置碰撞机的尺寸,X设为0.18,Y设为3.1。
注意:这里创建了一个碰撞机仅当激光存在的时候,留下两端的发射器是完全安全的。
7.创建一个新的C# 脚本命名为LaserScript,并且将它附加到laser。
这里是完整的步骤清单的演示:
通过脚本控制激光的开关
在MonoDevelop上打开LaserScript并且加上以下实例变量:
public Sprite laserOnS
public Sprite laserOffS
public float interval = 0.5f;
public float rotationSpeed = 0.0f;
private bool isLaserOn =
private float timeUntilNextT
这可能看起来有很多变量,但是实际上每个变量都是相当不重要的。
1.激光将可能是两个状态:On和Off。每个状态都有单独的图片。你可以仅在一瞬间就能详细说出每张状态图。
2.这些属性允许你加上一些随机的波动。你可以设置不同的interval*的激光在这个层面上不能运作。通过设置一个低的interval,你可以创建一个可以很快开关的激光,而通过设置一个高的interval**你可以创建一个激光在它的状态持续很久,而且谁知道呢,也许那老鼠甚至可以在它关闭时候飞越激光。
变量rotationSpeed提供相同的目的。它详细说明了激光旋转的速度。
3.最后有两个私有变量用来切换激光状态。
这里是激光的一个例子。每个激光都有一个不同的interval和rotationSpeed。
在Start里添加以下代码:
timeUntilNextToggle =
这将会设置时间直到第一次激光可以设置它的状态。
用以下代码加上FixedUpdate来切换和旋转激光:
void FixedUpdate () {
timeUntilNextToggle -= Time.fixedDeltaT
if (timeUntilNextToggle &= 0) {
isLaserOn = !isLaserOn;
collider2D.enabled = isLaserOn;
SpriteRenderer spriteRenderer = ((SpriteRenderer)this.renderer);
if (isLaserOn)
spriteRenderer.sprite = laserOnS
spriteRenderer.sprite = laserOffS
timeUntilNextToggle =
transform.RotateAround(transform.position, Vector3.forward, rotationSpeed * Time. fixedDeltaTime);
这里是这些代码做了什么:
1.缩短到下一次切换剩下的时间。
2.如果timeUntilNextToggle是零或者甚至小于零,那就到了切换激光状态的时间了。
3.在私有变量中设置正确的激光状态。
4.激光碰撞机只有在激光是开着的时候是可用的。这意味着老鼠可以在它关着的时候自由飞越激光。
5.将更通用的Renderer类加到SpriteRenderer,因为你知道激光是一个Sprite。它也设置了正确的激光精灵。这将在激光开着的时候显示laser_on精灵,在激光关着的时候显示laser_off精灵。
6.当激光刚刚切换的时候重置timeUntilNextToggle变量。
7.通过激光的rotationSpeed让激光绕z轴旋转。
注意:你可以仅仅通过设置rotationSpeed为零来让旋转不可用。
设置激光脚本参数
切回到Unity并且在Hierarchy中选择laser。确保激光脚本组成是可见的。
从工程视图将laser_on精灵拖到在检查工具中的激光脚本组成的Laser On Sprite属性中。
然后将laser_off精灵拖到Laser Off Sprite属性中。
设置Rotation Speed为30。
现在设置激光Position为(2, 0.25, 0)。这是为了测试一切是否正常运作。
运行这个场景。你需要看到激光能够很好地旋转。
现在,将激光转到活动房屋。
这里面是解决方案:创建一个激光活动房屋是否需要帮助?
只需在工程视图从分层视图拖动laser到Prefabs文件夹。
现在老鼠可以很轻松地在可用的激光中穿过,当没有很多弯曲的胡须的时候。这不是小孩的一个好榜样。小孩可以看到玩激光的结果。:)
最好去修好它。
打开MouseController脚本并且添加dead实例变量。
private bool dead =
这个实例变量代表一只死老鼠。一旦这个变量的值是true,你将不能激活喷气机,向前移动等等。
现在在MouseController类中的某处添加以下两个方法:
void OnTriggerEnter2D(Collider2D collider)
HitByLaser(collider);
void HitByLaser(Collider2D laserCollider)
当老鼠和任何一道激光相撞,OnTriggerEnter2D方法将被调用。现在,它只是标记老鼠的死亡。
注意:这可能看起来有点奇怪为什么你需要为了一行代码创建一个单独的方法,但是你将添加更多的代码到OnTriggerEnter2D和HitByLaser,所以这只是将未来的变化变得更加方便的一种方法。
现在,当老鼠死掉,它不能向前移动或者用喷气机飞行。你不能拍摄飞行的死去的老鼠,不是吗?:)
在FixedUpdate中做以下变化来确保这种事不会发生:
void FixedUpdate ()
bool jetpackActive = Input.GetButton(&Fire1&);
jetpackActive = jetpackActive && !
if (jetpackActive)
rigidbody2D.AddForce(new Vector2(0, jetpackForce));
if (!dead)
Vector2 newVelocity = rigidbody2D.
newVelocity.x = forwardMovementS
rigidbody2D.velocity = newV
UpdateGroundedStatus();
AdjustJetpack(jetpackActive);
注意现在jetpackActive总是false,当老鼠死亡的时候。这意味着没有向上的力施加于老鼠,并且,由于jetpackActive被传到AdjustJetpack,粒子系统将变成不可用的。
还有,你不能设置老鼠velocity,如果它已经死去,这是相当明显的。
切回到Unity并且运行场景。让老鼠飞进激光。
嗯..,看起来你不能再使用喷气机并且老鼠不能向前移动,但是为什么老鼠像疯了一样在跑?
猜猜?任何人?Bueller?Bueller?
这个怪异行为的原因是你的老鼠有两个状态:跑和飞,而且当老鼠掉落到地板它变成在地上的,所以跑的动画被激活了。
由于游戏不能这样结束,你需要添加一些状态来显示老鼠已经死亡。
添加掉落和死掉的老鼠动画
在Hierarchy中选择老鼠GameObject,并且打开动画视图。
创建新的动画叫做die。保存新的动画到Animations文件。
在这之后,跟着这些步骤来完成这个动画:
1.在工程视图中打开Sprites文件夹。
2.选中并且拖动mouse_die_0和mouse_die_1精灵到Animation视图的时间线。
3.设置Samples到8来让动画变慢些。
4.注意记录模式是打开的。注意它的最简单的方法是看着已经变成红色的回放按钮。点击记录按钮来停止记录。这将使回放按钮变成正常颜色。
这是简单的。实际上我认为你可以自己创建fall动画。这次只要使用一个帧的mouse_fall精灵。但是,如果你遇到困难,随意展开以下段落来获取详细的介绍。
这里面是解决方案:创建fall动画需要帮助吗?
1.在Hierarchy中选中mouse。
2.在Animation视图中展开动画下拉框并且选中[Create New Clip]。
3.创建一个叫做fall的新动画并且保存在Animations文件夹中。
4.在Project视图中确保Sprites文件夹是打开的并且Animation视图是可见的。将mouse_fall精灵拖到Animation视图时间线。
5.点击record按钮停止记录。
变换到Fall和Die动画
在创建动画之后,你需要适时将Animator切换到对应的动画。为了达到这个效果,你可以通过一个特殊的状态叫做Any State来进行变换,因为当老鼠触碰到激光时候它当前是处在什么状态是没有关系的。
由于你创建了两个动画(fall和die),老鼠是在空中触到激光还是在地上跑时触到激光,两者是不一样的。对于前者来说,老鼠应该切换到fall动画状态并且仅在触到地面之后执行die动画。
不管怎样,这两种可能性你都需要一个新的参数。打开Animator视图并且创建新的Bool参数叫做dead。
然后Make Transition从Any State到fall。
选中这个变换并且在Conditions中,设置dead为true并且点击+来加上第二个参数grounded。设置grounded的值为false。
选中这个变换并且在Conditions中,设置dead和grounded参数的值为true。
这个方法有两个可能的组合:
1.dead但是没有grounded
2.dead并且grounded
这样的话,如果老鼠死掉了,但是仍然在空中(没有触地),状态被切换到fall。然而,如果老鼠死掉了并且触地了,或者死掉了并且在落到地板后变成触地的了,状态切换到die。
还剩唯一一件要做的事是从MouseController脚本更新dead参数。
打开MouseController脚本并且添加以下这行代码到HitByLaser底部:
animator.SetBool(&dead&, true);
这将设置Animator组成的dead参数为true。
运行场景并且飞入激光。
就像你看到的,当老鼠触到激光,脚本设置dead参数为true并且老鼠切换到fall状态(因为grounded还是false)。不管怎样,当老鼠到达地面时,脚本设置grounded参数为true。现在,所有条件指向切换到die状态。
使用Trigger来让老鼠死亡一次
古语有云,每个动物都只有一条命,但是这里老鼠却一直在死去。你可以通过在老鼠死亡后审查Animator视图来自己检查这个错误。
这样的事情发生是因为从Any State变换到die一直在发生。从Any State触发animator的变换的grounded和dead参数总是true,
为了修复这个bug,你可以使用一个特殊的参数类型叫做Trigger。Trigger参数类型非常类似于Bool,除了它们是在使用后自动重置。这是Unity 4.3新增的相对比较新的特性。
打开Animator视图,添加一个新的Trigger参数叫做dieOnceTrigger。通过选中它旁边的复选框来设置它的状态为On。
接下来,切换Any State到die,并且在Conditions段中添加dieOnceTrigger。
运行这个场景并且再一次飞向激光。
我不能说这样把事情变得更好,但是幸运的是这非常容易修复。这件事发生仅仅因为die动画被设置为默认循环。
在Project视图中打开Animations文件夹并且选中animation。在Inspector中取消选中Loop Time。这样可以阻止动画循环。
运行场景并且碰撞激光
这次老鼠在死亡后躺在地板上了。
当致命的激光有趣地被实现,加上一些硬币给老鼠收集怎么样。
创建硬币活动房屋
创建一个硬币活动房屋是很简单的,就和创建激光一样,所以你应该尝试自己动手。只需要使用硬币精灵并且跟着这些步骤来做:
*不要为硬币创建任何脚本。
*用Circle Collider 2D来代替Box Collider 2D。
*Enable是碰撞机的Trigger option,因为你不想要硬币阻止老鼠的活动。
如果你有任何问题只要看一看下方的展开的段落。
这里面有解决方案:创建硬币活动房屋
1.在Project视图打开Sprites文件夹
2.将一个coin精灵到场景并且在Hierarchy中选中它。
3.在Inspector中设置它的Sorting Layer到Objects。
4.添加Circle Collider 2D组成。
5.将碰撞机的Is Trigger属性设为可用的。
6.设置碰撞机的Radius为0.23。
这里是展示所有所需步骤的图片:
在创建硬币GameObject之后,将它从Hierarchy中拖到Project视图的Prefabs文件夹来创建一个硬币活动房屋。
现在通过拖曳coin Prefabs到Scene视图来添加一些硬币到场景。像这样创建一些东西:
运行场景。
等等——老鼠在它触到硬币的那一刻死亡了?它们是被毒死的吗?
不是的,硬币是正常的。老鼠死掉是因为MouseController脚本里的代码操作任何一个碰撞机就像一个含有激光的碰撞机。
用Tags来区分硬币和激光
你可以使用Tags来区分硬币和激光,Tags专门为了这个目的而产生的。
选中Project视图中的Prefabs文件夹右边的coin Prefab。这将打开Inspector中的Prefab属性。找到name字段的正下方的Tag下拉框,打开它,并且选择Add Tag…
这将打开已经熟悉的Inspector中的Tags & Layers编辑器。在Tags段中添加一个叫做Coins的标签。
注意:它将Size自动增长到2并且添加Element 1,但是这些都是OK的。
现在再次在Project视图选中coin Prefab并且设置它的Tag为Inspector中的Coins
当然,仅仅只是设置Tag属性不能让脚本区分硬币和激光,你仍然需要修改一些代码。
更新MouseController脚本来使用Tags
打开MouseController脚本并且添加一个coins计数器变量:
private uint coins = 0;
这是我们存储硬币数量的地方。
然后添加CollectCoin方法:
void CollectCoin(Collider2D coinCollider)
Destroy(coinCollider.gameObject);
这个方法增加硬币数量并且从场景中移除硬币以致于你不能第二次碰撞到它。
最后,在OnTriggerEnter2D中做以下变化:
void OnTriggerEnter2D(Collider2D collider)
if (pareTag(&Coins&))
CollectCoin(collider);
HitByLaser(collider);
有了这个变化,你调用CollectCoin以防硬币和其它情况下的HitByLaser。
注意:在这个游戏里,只有两种类型的对象,所以为激光使用其它情况是OK的。在一个真正的游戏里,你应该将标签分配给所有对象类型并且暗中检查它们。
运行场景。
现在好多了。老鼠收集硬币并且在它触碰到激光的时候死亡。看起来你已经准备好用脚本生成激光和硬币。
生成硬币和激光
生成硬币和激光和生成房间的做法类似。算法基本相同,但是在写这个代码之前,你需要改善下硬币的生成以便为玩家提供更多乐趣。
现在你有一个只有一个硬币组成的活动房屋,所以如果你写生成代码你将在这个水平面的各个地方只简单地生成一个硬币。这是很无趣的!何不从硬币上创建不同的轮廓并且一下子生成一堆硬币呢?
创建一堆硬币的活动房屋
在Project视图中打开Prefabs文件夹并且用硬币活动房屋在场景中创建9个硬币。它应该看起来像这样:
选中任何一个硬币并且设置它的Position为(0, 0, 0)。这将成为中心硬币。你将添加所有的硬币到Empty GameObject,所以你需要在原点周围建立你的轮廓。
在放置中心硬币后,在硬币周围建立一个倒三角形的轮廓。别忘记你可以通过V键来使用Vertex Snapping。
现在通过选择GameObject\Create Empty创建一个Empty GameObject。在Hierarchy中选中它并且重命名为coins_v。
设置它的Position为(0, 0, 0)使得它和中心硬币有相同的位置。然后在Hierarchy中选中所有硬币并且将他们添加到coins_v。你应该像这样在Hierarchy中获取一些东西:
在Hierarchy中选中coins_v并且将它拖到Project视图中的Prefabs文件夹来创建活动房屋。
注意:你可以创建你想要的任意多的不同的硬币组合,就像房间一样,生成脚本将提供一个属性,在这个属性里,你将指定所有可能的对象来生成。
你已经完成了。现在从场景中移除所有的硬币和激光因为他们将在脚本中生成。
在生成脚本中添加新的参数
打开GeneratorScript并且添加以下实例变量:
public GameObject[] availableO
public List&GameObject&
public float objectsMinDistance = 5.0f;
public float objectsMaxDistance = 10.0f;
public float objectsMinY = -1.4f;
public float objectsMaxY = 1.4f;
public float objectsMinRotation = -45.0f;
public float objectsMaxRotation = 45.0f;
availableObjects数组存放了脚本生成的所有对象(也就是说不同硬币群和激光)。对象清单将存储创建的对象,所以你可以检查你是否需要添加更多player在前面或者当他们离开屏幕时候移除他们。
注意:就像房间一样,你可以在这个层级的开始创建一些激光或者硬币,在这里你不想依赖于随机生成代码。只是不要忘记将他们添加到对象清单。
变量objectsMinDistance和objectsMaxDistance被用来在最后一个对象和当前添加的对象中挑选一个随机距离,以致于对象在固定时间间隔中不显示。
通过使用objectsMinY和objectsMaxY你可以在放置的每一个对象中配置最大高度和最小高度,并且通过使用objectsMinRotation和objectsMaxRotation你可以配置旋转角度。
添加方法到新添加的对象中
新对象被添加到AddObject,和添加房间的方法相似。
添加以下代码:
void AddObject(float lastObjectX)
int randomIndex = Random.Range(0, availableObjects.Length);
GameObject obj = (GameObject)Instantiate(availableObjects[randomIndex]);
float objectPositionX = lastObjectX + Random.Range(objectsMinDistance, objectsMaxDistance);
float randomY = Random.Range(objectsMinY, objectsMaxY);
obj.transform.position = new Vector3(objectPositionX,randomY,0);
float rotation = Random.Range(objectsMinRotation, objectsMaxRotation);
obj.transform.rotation = Quaternion.Euler(Vector3.forward * rotation);
objects.Add(obj);
这个方法接收最后(最右边)一个对象的位置,然后在随机的位置(给定范围内)创建一个新的对象。通过调用此方法,每次当最后的一个对象要显示的时候-你创建一个新的对象消失在屏幕上,然后保持一个无尽的新硬币和镭射激光。
以下为这段代码的详细说明:
1. 创建一个随机索引,以创建这个对象。这个可能是一个激光或者一个硬币组。
2. 创建一个被选择对象的实例。
3. 设置这个对象的位置,在一定范围内随机与随机的高度。这个是由脚本参数控制的。
4. 给这个新放置对象一个随机的旋转角度。
5. 将这个新生成的对象放到跟踪对象列表中去,最后再移出(当它离开屏幕后)。
代码已经好了,剩下的就是使用它了。
在必要的时候生成并移除对象
将下面的代码添加到GeneratorScript中:
void GenerateObjectsIfRequired()
float playerX = transform.position.x;
float removeObjectsX = playerX - screenWidthInP
float addObjectX = playerX + screenWidthInP
float farthestObjectX = 0;
List&GameObject& objectsToRemove = new List&GameObject&();
foreach (var obj in objects)
float objX = obj.transform.position.x;
farthestObjectX = Mathf.Max(farthestObjectX, objX);
if (objX & removeObjectsX)
objectsToRemove.Add(obj);
foreach (var obj in objectsToRemove)
objects.Remove(obj);
Destroy(obj);
if (farthestObjectX & addObjectX)
AddObject(farthestObjectX);
这个在GeneratorScript类里德方法会检查对象是否应该添加或者移除。
下面我们来一起剖析一下:
计算这个层的前后的关键点数。如果这个激光或者硬币组在 removeObjectsX 的左侧,那么它已经离开屏幕,并且已经很远,你必须将它移除。如果在 addObjectX 的右侧,没有对象,那么你需要添加更多对象,因为最后的一个生成对象进入屏幕。这个 farthestObjetX 变量是用来找到最后(最右侧)的对象,以便于 addObjectX 比较。
因为你不能从当前的序列中删除对象,你将需要删除的对象放入另一个数组,然后在循环结束之后进行删除。
这是对象的位置(硬币或者激光)。
通过对 objX 执行这段代码,在循环结束后,你获得一个farthestObjectX中的最大objX值(或者初始值0,如果所有的对象都在左侧,但是在这里不会)。
如果当前对象已经在后面了,那么标记它为即将删除,以便减少资源占用。
删除标记为需要删除的对象。
如果玩家即将看到最后一个物体,并且没有更多物体在前面,那么脚本会增加一些。
为了让这个方法有效,在 FixedUpdate 的末尾增加一个对 GenerateObjectsIfRequires 的调用。
GenerateObejctsIfRequired()
这个方法会在每一次固定更新被调用,确保随时在玩家前面都会有新的物体出现。
设置脚本的参数
为了让 GeneratorScript 生效,你需要设置一些参数。 切换回Unity,然后在 Hierarchy 视图选择 mouse 游戏对象。
在 Inspector 中找到 Generator Script 组件,然后确保 Prefabs 在Project视图中处于打开状态。
从Project视图界面拖拽coins_v Prefab到GeneratorScript中的Available Objects列表。然后,从Project视图中拖拽laser Prefab同样到GeneratorScript中的Available Objects。
就是这样,运行场景。
注意:在GIF动画中,镭射激光并不会选装,因为我把LaserScript中的rotationSpeed设置为0。如果激光旋转的话,我很难录到一个好的游戏演示视频了。
现在,看上去它已经是一个完整的游戏了!
增加GUI元素
如果你看不到你当前收集了多少金币,那有什么意思?此外,玩家在他们死去后也无法重启这个游戏。现在是时候通过添加一些图形化组件来解决这些问题了。
显示金币数量
在MonoDevelop中打开MouseController脚本,然后添加以下实例变量:
public Texture2D coinIconT
然后添加DisplayConisCount方法:
void DisplayCoinsCount()
Rect coinIconRect = new Rect(10, 10, 32, 32);
GUI.DrawTexture(coinIconRect, coinIconTexture);
GUIStyle style = new GUIStyle();
style.fontSize = 30;
style.fontStyle = FontStyle.B
style.normal.textColor = Color.
Rect labelRect = new Rect(coinIconRect.xMax, coinIconRect.y, 60, 32);
GUI.Label(labelRect, coins.ToString(), style);
这个方法使用GUI.DrawTexture来在屏幕的左上角绘出金币的图标。然后它为标签撞见了一个GUIStyle来改变它的尺寸,设置粗体,然后改变字的颜色为黄色。还是我应该说是金色?:)
最终,它使用GUI.Label来显示当前采集的金币数量在金币符号的右侧。
所有用来显示GUI元素的代码都应该从被Unity调用的OnGUI方法中被调用,所以接下来添加一个OnGU方法,只是简单的调用以下DisplayConsCount。
void OnGUI()
DisplayCoinsCount();
切换回Unity,然后在Hierarchy视图中选择mouse。在Project视图中打开Sprites文件夹,然后拖拽coin片段到Inspector中Mouse Controller的Coin Icon Texture字段。
运行这个场景。你应该可以在左上角看到金币的数量了。
将死的复活
再次打开MouseController脚本,这次我们添加一个DisplayRestartButon方法:
void DisplayRestartButton()
if (dead && grounded)
Rect buttonRect = new Rect(Screen.width * 0.35f, Screen.height * 0.45f, Screen.width * 0.30f, Screen.height * 0.1f);
if (GUI.Button(buttonRect, &Tap to restart!&))
Application.LoadLevel (Application.loadedLevelName);
这个方法的大部分只有在mouse对象是死的并且着地了。你不希望玩家错过这个老鼠坠地的动画,毕竟我们花了那么多心思在创造这些动画上。
当这个老鼠死了,并且掉在地上后,你在屏幕中央现实一个写有“Tap to restart!”标签的按钮,如果玩家点击这个按钮,你只需简单的刷新一下当前加载的场景即可。
现在只要在OnGUI的末尾增加一个对DisplayRestartButton的调用,你就做完了。
DisplayRestartButton();
切换到Unity,然后重新运行场景。撞上激光来自杀。当按钮出现时,点击一下,游戏就会重新开始。
注意:你可以通过创建一个实例变量来自定义这个按钮的样式,如下所示:
public GUIStyle restartButtonS
然后你可以自定义这个按钮的样子。
关于自定义按钮的样子和感觉,你可以通过查看这个文档了解更多信息。 记住,随着Unity 4.6的到来,新的GUI会提供一种全新的GUI工具互动方式,你可以从了解更多的信息。
添加音乐和音效
当前的游戏很安静,当你添加完游戏音乐和音效后,你一定会它所带来的改善的效果惊讶到。
触碰激光的声音
在Project视图中打开Prefabs文件夹,然后选择laser Prefab。
在Inspector中,通过点击Add Component,然后选择Audio/Audio Source来添加一个声音来源组件。 然后打开Project视图中的Audio文件夹,然后将laser_zap音效拖入Audio Clip字段。
不要忘了去掉Play On Awake的勾选。否则激光的撞击声会在游戏一开始自动播放,就像老鼠从激光的地方开始一样。
噢,如果玩家一开始就死了,那将是一个过于残酷的游戏,对此玩家无能为力。或许它还能打破App Store的记录,因为这样应该比Flappy Bird还要难玩。
这是你应该得到的结果:
注意,确保你选择的是laser Prefab,而不是Hierarchy中的laser instance。否则你可能需要额外点击Apply按钮,以便将Instance中的改变应用到Prefab中去。
现在在MonoDevelop中打开MouseController,然后在HitByLaser的开头中添加以下代码:
if (!dead)
laserCollider.gameObject.audio.Play();
注意:将这个方法放在开头很重要,必须要在你将dead设为true之前,否则这个音效将永远不会被播放。
当Mouse碰到激光,你会在OnTriggerEnter2D中或得激光的碰撞事件的引用。通过访问laserCollider的gameObject属性,我们可以获得laser对象自身。然后你就可以访问它的Auido Source组件,然后就可以播放音效了。
运行场景。你会在老鼠触碰到任何激光器时发出嚓声。
只是,这个嚓的一声太过于安静,并且如果你有一个立体声扬声器或者二级,你会发现这个声音有点偏左边。这是因为Audio Listener组件默认情况下被放在Main Camera。此外,Audio Source 组件放在激光上。幸运的是,这很容易解决。
注意:别忘了Unity最初被设计用来创建3D游戏。在3D游戏中,你需要3D的音效(例如,可以听出你是被正面袭击还是背面袭击的)。
此外,尽管你可能依然想在2D游戏中使用3D音效,大部分情况下,你可能只是希望声音左右都一样,与音源无关。
禁用3D音效模式
打开Project视图中的Auido文件夹,然后选择laser_zap文件。然后在Inspector的打开Import Settings。去掉3D Sound的勾选,然后点击应用。
对接下来的声音文件应用同样的步骤。
– coin_collect
– footsteps
– jetpack_sound
– music
收集金币的声音
尽管你对于金币可以采取同样的方法,但是有些地方不太一样。
打开MonoDevelop中的MouseController,然后添加下面的实例变量:
public AudioClip coinCollectS
滚动到Collection方法,然后在这个方法的末尾增加下面的这行代码:
AudioSource.PlayClipAtPoint(coinCollectSound, transform.position);
这样,你就可以在老鼠处于金币位置时,使用AudioSource类的静态方法来播放金币被采集的音效。
切换回Unity,在Hierarchy中选择mouse GameObject。将coin_collect从Project视图中拖拽至MouseController脚本中的Coin Collect Sound字段。
运行场景,你应该可以在采集金币的同时听到音效。
飞行器和脚步声
接下来你需要添加飞行器和脚步发出的声音。这会和之前有些不同,因为老鼠将会同时拥有两个Audio Source Component。
添加Audio Sources
从Hierarchy视图中选择mouse GameObject,然后添加两个Audio Source组件。将footsteps从Projects视图中拖拽至第一个Audio Source组件的Audio Clip字段。然后拖拽jetpack_sound到第二个Audio Source组件的Auido Clip字段。
将两个Audio Source的启动就播放和循环属性都开启。
如果你运行场景,你会听到两个声音同时播放,不管老鼠是在飞还是在地上跑。你可以通过代码来修正这个问题。
在飞行器与脚步音效中切换
在MonoDevelop中打开MouseController脚本,然后添加以下2个实体变量:
public AudioSource jetpackA
public AudioSource footstepsA
这些将用于引用你新创建的2个Audio Sources。
现在添加AdjustFootstepsAndJetpackSound方法:
void AdjustFootstepsAndJetpackSound(bool jetpackActive)
footstepsAudio.enabled = !dead &&
jetpackAudio.enabled =
!dead && !
jetpackAudio.volume = jetpackActive ? 1.0f : 0.5f;
这个方法控制脚步声与飞行器音效的开启和关闭。脚步声只有在老鼠处于非死状态并且在地上的时候开启,而飞行器的音效只有在老鼠非死且不在地上的时候开启。
此外,这个方法调整飞行器音效的音量,以对应飞行器的例子特效。
最后我们在FixedUpdate的末尾添加对AdjustFootstepsAndJetpackSound的调用。
AdjustFootstepsAndJetpackSound(jetpackActive);
现在你需要在mouse GameObject中分配Audio Source组件的到stepsAuido和jetpackAudio变量。
设置FootSteps和Jetpack 脚本变量
切换回Unity,然后在Hierarchy中选择mouse GameObject。你只需要在Inspector中做一些操作。折叠除了Mouse Controller的所有其他组件。
现在将顶部的Audio Source组件拖拽到Mouse Controller脚本中的FootSteps Audio。
注意:就我所知,在Inspector中的第一个Audio Source是footsteps声音剪辑,但是你可能想临时展开声音组件栏来确认。
随后,再拖拽第二个Audio Source组件到Mouse Controller脚本中额Jetpack Auido。
运行场景。现在你应该可以在老鼠跑动在地板时听到脚步声,在飞行时,听到飞行器的轰鸣声。同样飞行器的声音会变得越来越大声,如果你一直按着左键的话。
添加背景音乐
为了添背景音乐,你需要以下几个简单的步骤:
1. 在Hierarchy中选择Main Camera。
2. 在Inspector中添加一个Audio Source组件。
3. 从Project浏览器中拖拽music资源到Audio Clip 属性。
4. 确保Play On Awake 和Loop属性处于开启状态。
5. 降低音量到0.3,因为背景音乐相对于其他音效来说会已经大声了。
就这样,运行场景,享受音乐吧!
添加多层背景
当前这个房间的景象很无聊。
有2个解决方式:
1. 在窗外创建一些可以展示的东西。
2. 不要用窗户。
当然,我们采用第一种办法,但是我们会采用一个动态背景,而不是一个一动不动的背景图。
注意:为了实现视差滚动,我使用在中提到技巧。
首先你需要添加2个Quads,一个用来作为背景,一个用来作为前景。
注意:你可以在中了解更多有关Quads的内容。为了简化,你可以将他们认为是一个矩形附带一个拉伸过的材质。至少这里可以这么认为。
你可能会好奇为什么这里使用Quad,而不是典型的Sprite?是由于你不能改变Sprite的图像wrappinp模式。至少在这里不行。然后你需要改变wrapping模式来确保材质是无缝的进行连接,当我们图片不断向右移动时,一会你会更清楚这一点。
你需要为每一个Quad设置一个材质,不用异动Quads来模拟异动,你只要在Quad内异动材质,对于北京和前景层采用不同的速度。
准备背景图片
为了在Quads上使用背景图片,你需要调整他们导入Unity的方式。
打开Project视图中的Sprites文件夹,然后选择window_background。在Inspector中,将Texture Type从Sprite改为Texture。这会改变Inspector的样子。
随后,将Wrap Mode属性设置为Repeat,点击应用。
对于window_foreground图片,重复一遍。
创建另一个Camera
等一下,另一个Camera?主Camera被保留用来跟踪mouse。这个新的Camera将被用来渲染交差背景,并且不会移动。
创建一个新的Camera,通过选择GameObject\Create Other\Camera。在Hierarchy中选择它,然后在Inspector中做一下改变:
重命名为ParallaxCamera.
将位置设置为(0,10,0)
将Projection设置为Orthographic
将尺寸设置为3.2,与主Camera同样的尺寸。
既然你有了2个Cameras,那么你也会有2个声音监听器。禁用ParallaxCamera中的Audio Listener,否则你会得到以下警告。
There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene.
创建两个Quad对象,通过选择GameObjet\Create Other\Quad。命名第一个Quad为parallaxBackground,然后第二个为ParallaxForeground。拖动两个Quads到ParallaxCamera,添加他们为子项。
选择parallaxBackground,然后将它的Position设置为(0,0,10),Scale为(11.36,4.92,0)。
注意:你使用这个scale,因为背景图的尺寸为px。
选择parallaxForeground,然后设置Position为(0,0,9),Scale为(11.36,4.92,0).
注意:这次你设置了z轴的位置。因为你不能在quads上使用Sorting Layers,你需要将background quad放在foreground quad后面。
设置Quad Textures
打开Project视图中的Sprite文件夹,在Hierarchy中,将window_background拖动至parallaxBackground, window_foreground至parallaxForeground。
然后,在Hierarchy中选择parallaxForeground。你会看到一个Mesh Render的组件被添加了进来。点击Shader下拉框,选择Unlit\Transparent。
在parallaxBackground上重复以上步骤.
随后,你就可以看到如下图的效果:
如果你禁用了2D模式,并且旋转了场景,你看到将会是这样:
运行场景,你会看到背景图片显示在了所有界面的最前面。这对于调试交叉滚动很有用,一旦你调试完毕,可以将它重新移回至背景。
让Texture移动起来
你不需要移动Quads。取而代之的是,你需要移动Quad所附加的Textures,通过改变材质的便宜量。因为你设置了WrapMode至Repeat属性,它会自动连接。
注意:并不是所有图片都适用这种情况,这些背景图片设计的时候就可以被用来相互连接。也就是说,如果你将背景图片水平串起来,图像的左边和右边会很自然的连接在一块。
创建一个命名为ParallaxScroll的C#脚本,并将它与ParallaxCamera关联起来。
在MonoDevelop中打开该ParallaxScript,然后添加以下实例变量:
public float backgroundSpeed = 0.02f;
public float foregroundSpeed = 0.06f;
这些Render变量会保持每个到Quads中Mesh Render组件的引用,这样你就可以调整他们的Texture属性。这个backgroundSpeed和foregroundSpeed定义了每个背景的速度。
然后在Update中添加以下代码:
float backgroundOffset = Time.timeSinceLevelLoad * backgroundS
float foregroundOffset = Time.timeSinceLevelLoad * foregroundS
background.material.mainTextureOffset = new Vector2(backgroundOffset, 0);
foreground.material.mainTextureOffset = new Vector2(foregroundOffset, 0);
这个代码会定期更新Quad中texture的偏移量,也就是移动它们。它们的速度将会不同,因为这个脚本中用了backgroundSpeed和foregroundSpeed作为参数去计算偏移量。
切换回Unity,然后在Hierarchy中选择ParallaxCamera。拖拽ParallaxBackground Quad到ParallaxScroll脚本中的Background字段,以及ParallaxForeground到Foreground字段。
运行场景,你会看到很漂亮的视差滚动的背景图。
但是主背景呢,你看不到了?
修正Camers的次序。
在Hierarchy中选择ParallaxCamera,然后在Inspector中,寻找Camera组件,然后将Depth属性设置为-2.
注意:ParallaxCamera的Depth属性应该比Main Camera的Depth小,所以检查你的Main Camera Depth,然后据此保证Parallax Camera更小一些。
不过,随后运行游戏,你会发现你从窗户看不到视差滚动的背景。
为了解决这个问题,在Hierarchy中选择Main Camera,然后将Clear Flags设置为Depth Only。这样它就不会清楚由Parallax Camera绘出的背景。
运行游戏,现在你可以从窗户中看到外面的风景了!
尽管你可以看到从窗户看到树尖和云,但是最好将背景移动的更高一些,这样你就可以看到山了。
另外一个事情就是背景在老鼠停止移动后,还在异动。
当老鼠死后停止背景滚动
在MonoDevelop中打开ParallaxScroll脚本,然后添加以下公共偏移变量:
public float offset = 0;
你会使用它,而不是Time.timeSinceLevelLoad,所以在Update中,使用以下代码替换掉你计算偏移量的代码。
float backgroundOffset = offset * backgroundS
float foregroundOffset = offset * foregroundS
现在,打开MouseController脚本,然后添加以下公共变量:
public ParallaxS
然后添加以下代码到FixedUpdate的末尾:
parallax.offset = transform.position.x;
这样子,你就可以使用Mouse的Position来作为偏移量而不是时间。
切换回Unity,然后选择Hierarchy中的Mouse GameObject。确保MouseController Script在Inspector可见。
将ParallaxCamera从Hierarchy中拖动至Inspector里德Parallax字段。
这样就允许MouseController来控制ParallaxScroll脚本中的offset变量。
将背景移的更高一些
将parallaxBackground和parallaxForeground Quads的Position中的Y属性设置为0.7,这会让他们高一些,这样你就可以看到山了。
运行游戏,现在背景会在老鼠死后停止滚动,并且你也可以从窗看到更多外面的景色。
注意:事实上,老鼠不一定要死了才能停止背景滚动。只要老鼠停下了,背景就应该停止滚动,如果出于某种原因,老鼠往回飞了,背景也应该反过来滚动。
好吧,结束这个教程让我有一些忧伤,所以我决定添加一幅小猫的图片,:)
接下来,还有什么
我希望你会喜欢这个教程。
你可以从下载这个项目的完整代码。
如果你想了解更多与真正制作Jetpack JoyRide游戏的内容,可以看一下视频。
创建一个视差滚动的背景,很大程度上是由的启发。
这个小猫的图片是由拍摄的,你可以在Flickr上看到这幅。
谢谢你完整的阅读这篇教程。
ceshi ceshi ceshi ceshi ceshi ceshi ceshi ceshi ceshi ceshi ceshi
2 2 1 1 1 1 1 1 1 1
3771 2989 2711 2622 2375 2231 2222 1947 1906 1898
22 杰鹏的梦
18 泰然处之

我要回帖

更多关于 flash脚本代码 的文章

 

随机推荐