一个iOS游戏,从原始传奇 武器升级升级到现代的,有两方,上面有一堆书,书能量满了就赢了,好像2d的

有哪些好玩且耐玩的 iOS 游戏? - 知乎<strong class="NumberBoard-itemValue" title="6被浏览<strong class="NumberBoard-itemValue" title=",455,018分享邀请回答
http://v.qq.com/page/f/o/q/f0013kfnvoq.html?start=51
我想说,看完这个视频你应该跃跃欲试了吧,好吧,那就快去玩吧,我不废话了。30.胶囊太空站(Rymdkapsel)好难的游戏!首先从画面上说,这款游戏真的做到了极简的程度。无关卡,无层级,整个画面一目了然,如同俄罗斯方块拖拽般的构建太空站的各个功能区,却真的没有想象那么简单。主动限制绝对会让你绞尽脑汁。31.单词解谜(Spelltower)好吧,这个是ios app store里暂时遇见的最好的拼词游戏。其他的不解释。32.爱犬大营救这是一款让你感觉像是在看一场真实动画电影的游戏,充满街机动作的温情冒险,这是一个小男孩儿与小狗的童话。好吧,那我也没必要说什么了。美工音效真的都很出色,只是还有个Bug没弄好,现在如何我不知道,还是觉得可以一玩。33.缤纷彩带(Strata)玩家使用多种颜色、多种丝带覆盖对应的小方块,最后编织出色彩艳丽的“网格”。一款简洁、精美、极富挑战性的益智游戏,带给您真正独一无二的动脑体验。34.纪念碑谷这是我所有女性死党超过八成评论说最符合她们少女情怀的游戏.....(?Д`)其他答案里应该也有推荐了,但为了她们的少女情怀...我还是写一下吧......35.纸境(Tengami)一款日系风大赞的解谜冒险类游戏,《Tengami纸境》正如它的名字一般,其最大的特色,就是将整个游戏做成了一本立体弹起式纸装书,里面的风景、建筑、人物、动物均是用纸的各种形态来形成,结合了剪纸、立体折纸以及纸雕等传统的工艺艺术,与其说是游戏,这更像是一件艺术品。36.多克罗(Dokuro)从电脑上移植过来的就不说了,谁都有电脑,但!PSV不是谁都有的,这款游戏也是其中一个佳作。游戏的整体素质相当不错,玩法简单但难度却不小,画面灰暗却又十分可爱有趣。37.战斗之心:传承(Battleheart Legacy)这款ARPG游戏绝13让我菊花一紧,游戏将以战斗开始,《传承》是一款庞大的,非线性的RPG游戏,更多的剧情和探索取代了以往的单调升级。游戏的操控也有所改变,因为本作中,战场将以华丽的3D形式展现,战斗也将会变得更为智能。另外一个变化是,在本作中,玩家将只能控制一个英雄,然而,“可制定的主角”可搭配游戏中的任何技能,每个玩家都可玩出自己的特色。38.海之号角(Oceanhorn)说道BattleHeart,就突然想起这款神作。好吧,其实我是冲着植松伸夫去的。游戏人物好好好萌啊!有木有! 39.暴力街区来一款爷们儿点的游戏,大四上的时候这游戏和同寝室的玩了N久,游戏的画面比较令人满意,战斗过程中的动画也做得很到位,虽然没有勇者之心的画面看起来那么有动感,但跟同类其他游戏相比已算是出色。操作方面没什么特别的,和勇者之心完全一样,只不过在技能系统上更加丰富,能组合出来的招数也更多。40.方块迷阵(Cuboid: 3D Puzzle)有朋友在前面答案里面推荐了类似滚方块儿入洞的游戏,既然推荐就推荐最棒的,就是这款。规则相同自然要用画面取胜。41.极速方块(dEXTRIS)一款街机风格的避让类游戏,控制绿红小方块不停地闯过障碍。玩家需要控制一绿一红两个小方块,以顺利地穿过前方各式的刺状障碍物为目标,尽可能久地保持下去。通道中的障碍物主要有两种布局方式,左右两边是突出的长刺状物,中间也会有菱形物体出现。遇到第一种情况,两个小方块是可以同时穿过去的,但后者就更加考验玩家的快速反应能力了,要快速地将两个方块都穿过去才行。42.节奏过山车Zero(Groove Coaster Zero)相比前作追加了歌曲包,我怎么之前没想到这个在我手机里足足停了半年的游戏!这款音乐游戏同样是心意之作!43.【多人5】指尖功夫(Bam fu)又从朋友pad上找到一款优秀的多人游戏。就是比手速看谁能把石头半数点成自己的颜色。44.爆破青蛙卡罗(Kero Blaster)又一个像素向游戏!千万别小看他!真的是佳作!!!别被这简陋的画面所迷惑!!45.拯救基瓦努卡(Kiwanuka)一款简单有趣的益智解谜游戏,玩家需要通过操作魔杖搭建桥梁拯救基瓦努卡人,虽然可以随意设置桥梁的长度和方向,但寻找最佳路径仍然是游戏的最终目标。这款游戏性堪比《纪念碑谷》的休闲解谜游戏一定能带给你不一样的惊喜.46.植物精灵(Botanicula)和机械迷城相同的厂商。却与《机械迷城》的工业元素不同,这款游戏有着色彩华丽的治愈系风格,同时该作也被称作环保题材游戏,描述有害的生物威胁森林的生态,5位精灵战士前来保护森林,守护植物种子。被有害生物污染的植物会以黑白来表现,非常细腻的艺术风格。47.孤独的托马斯(Thomas Was Alone)游戏以一个抑郁的背景展开,单调的色彩和灰色的阴影都体现了“孤独”这一主题。但事实上,游戏想要表达的是对于友情、爱情这类情感的歌颂。在游戏中玩家也能体会到相互依赖、互利共生这样的生活元素,让人对生活有更加积极的向往和追寻。游戏的玩法非常简单,两个方向键控制前后移动,加上一个跳跃键,初期关卡玩家全靠这三个按键完成。而随着关卡的递增,孤独的小方块终于遇见了新的伙伴,玩家可以通过屏幕两边的图标进行小伙伴间的切换。而游戏的益智性到此才算真正展开,从这里开始便不再是单纯的跳跃游戏。我是有多喜欢阴郁系的游戏(?Д`)........48.完美路径(Perfect Paths)达芬奇说过一句名言“Simplicity is the ultimate sophistication.”(至繁归于至简)也就是说简约才是复杂设计的最终目标,用这句话来形容Perfect Paths《完美路径》这个解谜游戏最恰当不过了。游戏的目的其实非常简单,在网格里,玩家需要绘制一条路径,引领小方块们找到自己对应的颜色。但是《完美路径》中的“完美”二字并不是摆设,也许有很多条路径都可以达成目标,但是要找到那条最佳路径还是有点难度的,同时也是充满挑战的。这是我最近上手且爱不释手的游戏,推荐给你。49.和谐2(Har mo ny 2)有一个让我觉得脑袋不够用的......真的是小清新,移动彩色方块使对应方块变成和谐色条,好吧,第三关已经就要死了。50.Folt一款有趣的小游戏,通过随机出现的方块指定步数路线,并消除自己所摆下方块的游戏。好吧,这游戏基本没啥人下,也推荐一下吧。51.蒙特祖玛的宝藏3(The Treasures Of Montezuma 3)这款游戏没人说是不是有点奇怪,难道这不是大多数女生爱玩的游戏吗?????????52.David53.冒险公司传奇(Tales of the Adventure Company)54.王国之路(Bardadum: The Kingdom Roads)55.地牢迂回战(Devious Dungeon)56.Quadblast57.Reckless Run58.Democracy 359.100m stunt60.梦幻之谜佐贺(Fantasy Puzzle Saga)61.Siralim62.Mad Bullets63.Swords & Poker Adventures64.Buzz Killem65.Z Hunter66.Bio Inc. - Biomedical simulator67.Red Ball 468.Zombie Commando69.Guardians of the Galaxy: The Universal Weapon70.Bladelords - fighting revolution71.Battle Fleet 2: WW2 in the Pacific72.Marble Drop73.Hellraid: The Escape74.Super Scrapped Robot75.Secret Files Tunguska76.daWindci Deluxe77.PlunderNauts78.Monsters Ate My Birthday Cake79.VVVVVV80.World of Tanks Blitz81.Desert Fox82.The Wolf Among Us83.Castle Doombad: Free to Slay84.TwoDots85.剑无生(苹果商店价格1元钱)这款游戏是苹果一元大抢购时候,我看图标随便买的8款游戏之一。玩了一会儿爱不释手,以至于两天废寝忘食到通关。作为中国独立游戏厂商——禹石游戏的开山大作,如此表现实在让我感动。以至于我希望推荐给各位,并恳请哪怕你是越狱党,也劳烦您就花一元钱表示支持。这款游戏未必能让你和我一样有感动,但一定不会让你失望。P.S.:这款游戏其实有一些人物选择与技能选择的连击小伎俩,如果有兴趣以后再议。86.世界2 魔物狩猎(苹果商店价格1元钱)动作手游《世界2 Online》的单机版本。在我看来,如今一个好游戏的不缺德表现就是本应该做成单机的游戏不仅弄成Online版本敛财,而所谓商业良心则是做了一个单机的精品游戏还没有内购!这边是我为何要推荐这款游戏的原因。当然,说它不缺德和有良心的前提是,这游戏本身足够出色。《世界2:魔物狩猎》游戏采用Unity引擎打造,画面均采用3D效果呈现,同时也模拟了几近真实的物理碰撞效果,怪物或玩家都可以破坏关卡中的物件,战斗场景和效果相当之酷炫。而游戏的操作则延续了ARPG的虚拟按键的传统,通过摇杆式的控制和技能释放来进行对战。87.魔塔(这貌似不是一个特别新的游戏,只是我今天才找到。)小时候玩的魔塔是童年之一,只是在苹果商店下载到的很多名字里带有“魔塔”的游戏都是老游戏的照搬照抄。这款由CatCap开发的游戏却是个同类游戏的重新精心设计,所以依然值得无聊打发时间。88.Hero Emblems首先,确实,这是一个三消游戏。很多人特别不喜欢,但问题是这款三消有些特别,在单机里的确比别的有趣,并且无内购。有媒体将其评为“三消游戏的救世之作”,体会下。我是玩了这个游戏才决定推荐给你们并且再一次表决心要重新更新这个答案的。(囧)我喜欢将三消游戏分为三类:换邻三消、连线三消和长移三消。这款属于换邻三消(相邻两块互换达到三消),之后推荐的三消游戏会用这三个种类子分类。89.Gemini Strike曾经被腾讯的雷霆战机每天的宝箱搞死,于是退出以回复真人体力,一直到现在我试过了近乎所有的类似雷电的手机飞行类游戏,但这款确实是最棒的。目前为止。有宝箱、有大招、有大量差别装备、有画面。90.卡牌萌兽横版跑酷+卡牌,这个的确是只得在Itunes商店首页推荐的。喜欢卡牌类游戏,玩了那么多,这款真的不算坑钱,只是对于我等无耐心的穷人而言,实在是要把人逼死。但这不影响这游戏的优秀。91.Tap Titans我特别懒,证明就是我懒得玩一个游戏自己有太多参与感,还TM想玩,于是就迷上了挂机类游戏,ios商店上的所有挂机类游戏,手游或是单机都下了玩了。这款真的是上乘之作,国内也有山寨货。挂机类游戏的意思就是:你什么都不用管,他自己打,然后如果你想刷存在感,就重复点击屏幕增加攻击次数,并且在适当的时候用攻击怪兽获得的金币升级攻击力技能和佣兵(听上去好傻......)所以如果你玩了觉得无聊别怪我,不是我的错,是挂机类游戏的错......%&_&%P.S.:上图是我自己的游戏截图,这么一看,我竟然无聊的坚持到了100多关,囧。92.万智牌2015我IPAD上现在有6个游戏,这个游戏算是唯一一个大游戏(对我而言300MB以上的都挺大的了(?Д`)),卡牌对战类游戏接触比较多的只有三个:万智牌、游戏王和炉石传说。说实话三个游戏的规则对比和卡牌设置来看,我最不喜欢的是炉石传说,因为游戏自由度是相对最低的。万智牌的规则稍微复杂,所以对于新手而言入门门槛稍高,但这也证明了规则制定的细化与不粗糙。其实真正上手之后,游戏起来还是更多乐趣的。所以如果你是和我一样的RP极低非RMB者,在炉石的世界每天卡包都几乎蓝天白云并且被吊打严重,建议你重新接纳一款游戏,会给你惊喜。唯一的缺点是,这款游戏在非正是游戏过程运行上稍微有一点慢(菜单进入等),所以稍微有些耐心。毕竟是300MB以上的大游戏o(╯□╰)o-------------------------------------待续---------------------------------------5.2K222 条评论分享收藏感谢收起2.8K147 条评论分享收藏感谢收起iOS cocos2d 2游戏开发实战&第3版&---你的第一个游戏&
随着苹果公司不断地创新与发展,新的iPhone 5、iPad 4以及iPad mini产品相继问世,包括iOS与Xcode在内的开发环境和开发工具也都有了更新和进步。相信有不少开发团队正紧锣密鼓地在iPhone 5和iPad mini上部署自己的应用,一切都是那么令人激动!而随着iOS 6的推出,cocos2d游戏引擎又有了新的发展。在IT行业,可谓唯一不变的便是变化。日新月异的技术需要同为开发者的你我保持强盛的好奇心和完美的学习状态,只有这样,才能不断进步,开发出更酷的游戏或应用。相信这本书的再版,一定能使你受益匪浅,帮助你实现梦想。
你的第一个游戏
在本章中,你将编写专属于你的第一个完整的游戏。它不会为你赢得什么奖项,但从中可以学到cocos2d基本要素的使用方法,而且这个游戏是很容易修改的。实际上,本书之前版本的读者已经制作了这个游戏的几个修改版并发布到了App Store中。
这个游戏是著名的“Doodle Jump”游戏的“倒版”,它被贴切地命名为“DoodleDrop”。玩家通过旋转屏幕尽可能躲避落下的障碍物。游戏的最终版本如图4-1所示,你可以在此提前了解一下将在本章创造的作品。
“DoodleDrop”游戏的最终版本
创建DoodleDrop项目
在第2章我们学习了如何创建支持ARC的Kobold2D和cocos2d项目。
Kobold2D从运行Kobold2D启动应用程序开始,然后选择Empty-Project 模板(见第2章中的图2-2)。使用DoodleDrop作为项目名称,基本工作就完成了。剩下的事就是选择应用程序的目标程序,选择Supported Device Orientation的portrait mode图标(见第3章中的图3-17)。由于DoodleDrop是设计在Portrait模式下玩的,因此不选择landscape mode图标。
下面的部分仅适于cocos2d用户——Kobold2D用户可以略过。
从一个支持ARC的cocos2d项目开始
cocos2d用户要创建支持ARC的cocos2d项目,就应该依照第2章中的指导内容来做。如果已经做过了,就只要把已经创建的项目复制一遍。这样做可以节省时间:保留一份由原始cocos2d项目模板转换得来的支持ARC的未修改版本,这样每次创建新项目时就会比较简单快捷。
在这本书的源代码中,可以在Cocos2D_ARC_Template_Projects文件夹下找到支持ARC的cocos2d模板项目。
在完成第2章中的指导内容之后,就有一个支持ARC的cocos2d项目了。我的项目取名为cocos2d-2.x-ARC-iOS。用Xcode打开之前先简单地将包含.xcodeproj文件的文件夹拷贝一份。但是不要自己重命名.xcodeproj文件,因为那样做会导致文件不可用。
现在你可以通过Xcode来重命名项目,这同样也会重命名.xcodeproj文件。在Project Navigator中选择cocos2d-2.x-ARC-iOS项目(第一个条目,见第2章中的图2-5),带延迟地双击来编辑该条目。就是单击一次,停顿两秒,再单击一次。这样项目名称就可以编辑了。输入DoodleDrop作为这个项目的名称。
按下Enter键确认修改之后,Xcode会问你是否确认重命名图4-2所示的那几项。确认则单击Rename。否则Xcode 仍然会重命名项目,但是其他名称不变。所以就算你这个时候发现了拼写错误,或者突然不喜欢这个名字了,也都应该单击Rename。重命名之后考虑到Prefix.pch文件,可能还会出现警告:“New name for file can not be the same”。无视这个警告即可,因为不会有什么问题。
还有最后一个需要手动重命名的条目:应用程序的计划方案。应该仍然名为cocos2d- 2.x-ARC-iOS,也就是你命名项目时用的那个名称。选择Product Manage Schemes来查看方案列表。延迟双击方案名称来选择并编辑,重命名为DoodleDrop。完成之后,关闭scheme列表。
确认重命名项目以及相关文件
由于DoodleDrop是Portrait模式应用程序,因此需要编辑AppDelegate.m 文件。修改shouldAutorotateToInterfaceOrientation方法,使之返回YES以仅用于Portrait模式:
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
现在,在Run和Stop按键右边的下拉菜单中选择DoodleDrop的项目方案,然后运行,确认一切工作正常,如图4-3所示。
开始游戏吧!DoodleDrop项目基于第2章中的cocos2d ARC
项目,Kobold2D的Empty-Project模板也不会有太大区别
创建DoodleDrop场景
下一步你要作如下决定:是使用已有的HelloWorldLayer作为起点,之后再把名字改成现在的项目名称呢?还是创建自己的场景?是我就选择后者。因为你迟早需要添加新的场景,所以还不如现在就学习如何从头创建新的场景。
请确定已选择你准备添加新场景类的组,然后选择File | New | New File或者右击Project Navigator树中的合适位置,在弹出的菜单中选择New File,打开如图4-4所示的New File 对话框。
添加新的CCNode派生类的最好方式是通过使用cocos2d或Kobold2D提供的类模板。
在这个例子中,因为我们要创建新的场景,所以选择的CCNode类是CCLayer的子类
cocos2d和Kobold2D为大多数重要的节点和类都提供了类模板,不使用它们太浪费了!另外,Xcode自带的Objective-C类也是很好的模板——只需要手动将基类由NSObject 改为CCLayer即可。在cocos2d v2.x的模板部分选择CCNode类,单击Next按钮,再次单击Next 按钮会弹出如图4-5所示的Save File对话框,在此之前,确认将该类设置为CCLayer 的子类。
我是将新建的文件命名为GamLayer.m。整个DoodleDrop游戏逻辑都在这个文件中实现,所以这个名字还十分合理。确保DoodleDrop目标程序复选框被选中(见图4-5)。
不检查目标设置的话可能会导致文件没有被添加到正确的目标程序里。这会引起一系列问题——其中编译错误和“file not found”错误是常见的典型错误。这种情况有时还会导致游戏运行时崩溃。把文件放进完全不需要这些文件的目标程序里,只会浪费空间。
给新场景命名,并且确保它被添加到正确的目标程序中
目前,我们的GameLayer类是空的,为了将它设置为场景,我们要做的第一件事是在里面添加+(id) scene方法。我们在这里插入的代码和第3章的基本上一样,只是层的类名不同而已。几乎在任何一个类中都需要-(id) init方法。添加-(void) dealloc方法也无伤大雅,要是能输出对象被正确销毁的日志就更好了。监视dealloc方法能有效提前做出系统预警,防止内存泄漏。
我也是一位很谨慎的程序员,决定将第3章中介绍的日志语句添加进来。程序清单4-1是完成后的GameLayer.h,程序清单4-2是完成后的 GameLayer.m。
程序清单4-1
带场景方法的GameLayer.h
#import & Foundation/Foundation.h&
#import "cocos2d.h"
@interface GameLayer : CCLayer
程序清单4-2
带场景方法以及一些标准方法的GameLayer.m
#import "GameLayer.h"
@implementation GameLayer
+(id) scene
CCScene *scene=[CCScene node];
CCLayer* layer=[GameLayer node];
[scene addChild:layer];
-(id) init
if ((self=[super init]))
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
-(void) dealloc
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
现在可以安全地删除HelloWorldLayer类。在弹出的对话框中选择Move to Trash选项,将文件彻底删除。选择HelloWorldLayer.h和HelloWorldLayer.m两个文件,在顶部菜单中选择Edit | Delete,或者右击选中的文件,在弹出的菜单中选择Delete选项。
Kobold2D用户现在只需要打开Resources组中的config.lua文件,修改FirstSceneClassName即可,如下所示:
FirstSceneClassName = "GameLayer",
但是在纯cocos2d应用程序中,必须修改AppDelegate.m,将文件中所有的HelloWorldLayer修改成GameLayer。程序清单4-3中已经突出显示了要对#import和pushScene语句进行的必要修改。
程序清单4-3
修改AppDelegate.m 文件,用GameLayer类代替HelloWorldLayer
// replace the line #import "HelloWorldLayer.h" with this one:
#import "GameLayer.h" - (BOOL)application:(UIApplication *)application??
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// replace HelloWorldLayer with GameLayer
[director_ pushScene:[GameLayer scene]];
编译并运行,应该能看到空白场景。成功了!如果碰到什么问题,请将你的项目与本书附带的DoodleDrop01项目进行比较。
应用程序成功生成但是运行失败?别忘了,一个Xcode 项目中有多个目标程序,甚至一个目标程序也会有多个方案。检查Xcode 工具栏中Run 和Stop 按钮右边的方案选择/部署目标程序下拉菜单(见图2-6)。下拉菜单的左边部分用于选择当前方案。要确保选择的是DoodleDrop。大多其他方案,比如cocos2d-library是静态库。你可以生成静态库,但是不能运行它们。删除、隐藏和选择方案这些都只能由用户自己设置完成。其他的问题我都已经为你解释清楚了。
添加Player Sprite
接下来将添加Player Sprite(玩家精灵)并使用加速计控制它们的动作。要添加玩家图像,请在Xcode中选择Resources组,然后选择File | Add Files to“DoodleDrop”,或者右击并从菜单中选择Add Files to“DoodleDrop”来打开选择文件的对话框。如果不小心把文件添加到了错误的组中,那么可以在Project Navigator中把它重新拖动到正确的组中。Resources组并没有什么特别的地方,它就是按照定义应该保存不是源代码的文件的地方。
玩家图像alien.png和alien-hd.png就在随书附带的DoodleDrop项目的Resources文件夹中。也可以挑选你自己的图像,只要图像的尺寸是64×64像素或128×128像素(HD格式,带有-hd后缀)即可。cocos2d自动为带有Retina显示屏的iPhone和iPod Touch设备使用HD文件,标准分辨率(SD)的文件只用于iPhone 3GS。cocos2d还能识别另外两种文件后缀:-ipad用于iPad和iPad 2,-ipadhd用于带有Retina显示屏的第3代(或更新的)iPad。
对于专用于Retina设备和iPad的资源,cocos2d默认使用带有-hd、-ipad和ipadhd后缀的文件。普通的iOS应用程序不会使用它们。这些应用程序要想使用高分辨率图像,必须使用苹果公司的@2x文件扩展名。虽然在cocos2d应用程序中也可以使用@2x扩展名,但是cocos2d的文档警告用户不要使用该扩展名。
一个常被问起的问题是在非Retina设备上简单地缩小HD图像是否合适。这么做是不合适的,原因有两个。一个原因是内存限制。即使最早的Retina设备的内存也是非Retina设备的2倍以上。让非Retina设备加载HD图像,占用的内存将是已被缩小并打包的SD图像的4倍。另一个原因是,加载Retina图像的时间要比加载SD图像长得多,在较老、较慢的设备(比如没有Retina显示屏的那些设备)上这个问题更加明显。
反过来,在应用程序中只使用标准分辨率的资源也不是十分合适。这样将无法利用Retina显示屏的高分辨率,而且应用程序的图像质量在Retina设备上不如高分辨率的图像。放大和图像处理算法再好,也不能让标准分辨率图像在Retina设备上呈现清晰而鲜明的效果。正因如此,应该将游戏的所有资源设计为使用高分辨率,然后在需要的时候再缩小其大小。唯一需要注意的是,尺寸大小应该能够被2整除。
Xcode随后会询问添加文件的方式和位置细节,如图4-6所示。确保在Add To Targets区域选中了所有会使用该文件的目标程序,当然在这里只有DoodleDrop,不过在Kobold2D项目中最好也把该文件添加到Mac OS X目标中。如果文件还没有存储到项目的文件夹中,就应该选中“Copy items into destination group’s folder(if needed)”复选框。如果无法确定,就选中该复选框,最坏的情况也就只是有相同文件的副本。如果不选中该复选框,那么最坏的情况会是把项目添加到源代码管理程序或者在压缩并分享项目时发生文件丢失错误。
iOS游戏首选的图像文件格式是PNG(Portable Network Graphic,便携式网络图像)。这是一种压缩文件格式,然而与JPEG文件不同的是,PNG采用了无损压缩,保留了原始图像的所有像素。你也可以保存不经压缩的JPEG文件,不过对于同一图像,PNG文件的大小明显要比未经压缩的JPEG文件小。但是这只会影响应用的大小,而不会影响纹理对内存(RAM)的使用。不使用JPEG文件的另一个原因是,cocos2d在iOS上加载这些文件的速度很慢。我上次测量的结果是它们比PNG文件慢8倍。第6章将介绍TexturePacker,一个用于管理图像的工具。它允许将图像转换为各种压缩格式或减少图像的色深,同时通过抖色和其他技术保留尽可能高的图像质量。
每次添加资源文件时都会出现这个对话框,大多数情况下你都应该使用默认设置
现在我们要向游戏场景中加入玩家精灵了。我会将它们作为CCSprite*类型的成员变量加入到GameLayer类中。就目前来看,这样做比较容易,而且游戏也足够简单,可以将所有组件都加入到相同的类中。通常不推荐这种方法,在之后的项目中我们将会创建单独的类来保存每个游戏组件,以符合好的代码设计要求。
程序清单4-4展示了如何在GameLayer的头文件中添加CCSprite*类型的成员变量。
程序清单4-4
将CCSprite*类型的成员变量添加到GameLayer类中
#import & Foundation/Foundation.h&
#import "cocos2d.h"
@interface GameLayer : CCLayer
程序清单4-5是加入到init方法中的代码,它的功能是初始化精灵,将精灵赋给成员变量,并设置精灵到屏幕底部中间的位置,同时还启用了加速计输入功能。
程序清单4-5
启用加速计输入,创建并定位玩家精灵
-(id) init
if ((self = [super init]))
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:@"alien.png"];
[self addChild:player z:0 tag:1];
CGSize screenSize = [CCDirector sharedDirector].winS
float imageHeight = player.texture.contentSize.
player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);
玩家精灵已添加为层的子节点,它的标记值是1,随后我们将使用这个标记值识别它并把它与其他的精灵区分开。这里的文件名使用了标准分辨率图像的文件名,即alien.png。在Retina设备上,cocos2d会自动加载alien-hd.png。如果没有对应的-hd文件,cocos2d会加载标准分辨率图像。此时,图像在Retina设备上看起来比在非Retina设备上小。提供所有图像资源的-hd版本是一种很好的做法。
记住,在iOS设备上文件名是区分大小写的。如果你试图加载Alien.png或ALIEN.PNG,在模拟器上会成功加载文件而在iOS设备上则不会,因为文件真正的名字是alien.png,字母全部小写。这就是坚持统一的命名约定——例如强制所有文件名使用小写字母——的意义所在。为什么要用小写?因为全部大写的文件名很难辨认。
我们将position属性的x值设为屏幕宽度的一半,从而使玩家精灵的初始位置水平居中。在垂直位置上,我们想使玩家精灵纹理的底端与屏幕底端对齐。如果你记得前一章的内容,就会知道精灵纹理是以其中心点作为位置坐标值的。将精灵的垂直位置设为0会导致纹理的下半边陷入屏幕底端。这不是我们想要的,我们要把它往上挪半个纹理的高度。
可以通过调用player.texture.contentSize.height返回精灵纹理的内容尺寸。什么是内容尺寸?在第3章中,我讲到iOS中纹理尺寸的大小只能是2的方幂。但是实际的图像尺寸可能会比纹理尺寸小。例如,如果原始图像的尺寸为100×100像素,那么纹理尺寸就是128×128像素。纹理的contentSize属性会返回原始图像的尺寸,也就是100×100像素。大部分情况下,处理的都是内容尺寸而不是纹理尺寸。即使图像是2的幂,也应该使用contentSize,因为纹理可能是包含多个图像的纹理图册。第6章将详细讨论纹理图册。
将图像高度的一半设为position属性的y值后,精灵图像恰好能与屏幕底端对齐。
无论何时都要尽量避免使用固定的位置值。如果你只是把玩家位置设为(160,32),此时你就做了两个本该避免的假定。第一,你假定了屏幕宽度为320像素,但并不是每个iOS设备都是这样的。第二,你假定了图像高度是64像素,然而那也是可能会改变的。一旦你开始像这样做假定,代码就会丧失一部分灵活性,修改起来需要很多时间。
我用了很多代码来定位对象,但长远来看这样做会节约大量时间。可以将项目部署到不同的设备,也可以使用不同尺寸的图像,无论如何项目都会正常运行。你不再需要修改这段特别的代码了。程序员面对的最费时的坏事情之一就是——不得不修改那些依据假定而编写的代码。
加速计输入
最后一步,我们来使玩家精灵能够左右倾斜。在第3章中我已经说明,应该为接收加速计输入的层添加accelerometer方法。这里我使用了acceleration.x参数,将它乘以10后加到玩家精灵的位置值上,从而加速玩家精灵的运动:
-(void) accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration
CGPoint pos = player.
pos.x + = acceleration.x * 10;
player.position =
注意到奇怪之处了吗?上面的三行代码用一行就能写好:
// ERROR: lvalue required as left operand of assignment
player.position.x += acceleration.x * 10;
然而,与其他编程语言(如Java、C++或C#等)不同,像player.position.x += value这样的语句对Objective-C中的属性是不起作用的。position属性的类型是CGPoint,这是一个普通的C结构体。Objective-C中的属性不能直接向结构体的域赋值。问题出在Objective-C中属性的工作方式,以及Objective-C所基于的C语言的赋值机制。
player.position.x语句实际上是调用了position的getter方法[player position],这意味着你实际上获得了一个临时的position值,并试图改变这个临时的CGPoint对象的x成员变量。但之后这个临时的CGPoint对象会被丢弃。于是position的setter方法[player setPosition]就不会自动被调用了。所以只能直接对player.position进行赋值,在本例中就是赋给它一个新的CGPoint对象。在使用Objective-C时,你必须接受这个令人遗憾的问题,而且如果你有过编写Java、C++或C#的经历,没准还得改变你的编程习惯。
因此,前面的代码必须创建一个临时的CGPoint对象,修改position的x域,然后把临时的CGPoint赋给player.position。在Objective-C中是必须这么做的。
首次测试运行
现在你的项目应与本章附带的DoodleDrop02项目不相上下。马上测试一下吧。你要确认已选择在设备上运行应用,因为模拟器不会获得加速计输入。检验当前版本中的加速计输入表现如何。
如果尚未在Xcode中为这个项目安装你的开发授权,将会产生“code sign”错误。在iOS设备上运行程序时需要代码签名证书。请查阅苹果公司的文档以了解如何创建和安装必要的开发授权文档(files/howto.action)。
注意到加速计输入哪里不正常了吗?是的,它反应迟缓,移动不畅。这是因为玩家精灵并没执行真实的加速和减速。让我们修改一下它。修改后的代码在DoodleDrop03项目里。
实现加速与减速的概念不在于直接改变玩家的位置值,而是使用单独的CGPoint变量作为速度矢量。每次接收到加速计事件时,速度矢量就加上从加速计得到的输入。当然,这意味着我们必须把速度限制在一个任意的最大值内,否则减速时就要花点时间了。不管有没有接收到加速计输入,在每一帧都把速度加到玩家位置上。
为什么不使用动作来移动玩家精灵呢?无论何时你需要频繁地——如每秒数次——改变对象的速度或方向,使用move动作都不是一个好的选择。动作适用于相对使用期较长的一次性对象,所以频繁创建新对象在分配和释放内存上增加了额外开销,这会使游戏性能大幅下降。
更糟糕的是,如果不为动作留出一点时间,动作是不会执行的。这就是在每帧添加新动作来替换前一个却没有任何效果的原因。很多cocos2d开发者都曾偶然发现过这个看似古怪的现象。
例如,如果在每帧都停止所有动作并为对象添加一个新的名为MoveBy的动作,对象不会有一丁点的移动!MoveBy动作只会在下一帧改变对象的位置。但是在下一帧你已经停止所有动作,并加入另一个新的MoveBy动作了。这样做下去只会让对象寸步不移。这就像老生常谈的关于驴的那一套故事:推得越使劲它就越犟,并且在原地不动弹。
让我们来看一下对代码所做的修改。在头文件中加入了playerVelocity变量:
@interface GameLayer : CCLayer
CGPoint playerV
你可能想知道为何使用CGPoint替代float。这是考虑到你以后可能会加速或减速一点点。为今后的扩展做些准备总没有坏处。
程序清单4-6是加速计的代码,其中使用速度代替了对玩家位置的直接修改。这段代码采用了三个设计参数:减速值、加速计灵敏度和最大速度。这些参数没有最优值;你需要调整数值,找到最适合你游戏的设置,因此得名“设计参数”。
减速是指减少当前速度,之后速度将加上新的加速计值与灵敏度相乘后的数值。减速值越低,玩家精灵操作外星人改变方向的速度就越快。灵敏度越高,玩家精灵对加速计输入的反应就越敏感。由于这些数值是对同一数值进行修改,它们相互作用且相互影响,因此一定记得每次只调整一个值。
程序清单4-6
通过GameLayer实现得到playerVelocity
-(void) accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration
// controls how quickly velocity decelerates (lower = quicker to change direction)
float deceleration = 0.4f;
// determines how sensitive the accelerometer reacts (higher = more sensitive)
float sensitivity = 6.0f;
// how fast the velocity can be at most
float maxVelocity = 100;
// adjust velocity based on current accelerometer acceleration
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * ?
// we must limit the maximum velocity of the player sprite, in both directions
if (playerVelocity.x & maxVelocity)
playerVelocity.x = maxV
else if (playerVelocity.x - maxVelocity)
playerVelocity.x = - maxV
现在playerVelocity能够改变了,但如何把速度加到玩家精灵的位置值上呢?可以在GameLayer的init方法中指定如下update方法:
// schedules the –(void) update:(ccTime)delta method to be called every frame
[self scheduleUpdate];
同样需要添加–(void) update:(ccTime)delta方法,如程序清单4-7所示。已指定的update方法在每一帧都会被调用,而那就是我们要在玩家精灵的位置值上加上速度的地方。这样我们就可以做到:无论加速计频率的大小如何,都能产生流畅平滑的运动。
程序清单4-7
用当前速度更新玩家精灵的位置
-(void) update:(ccTime)delta
// Keep adding up the playerVelocity to the player's position
CGPoint pos = player.
pos.x + = playerVelocity.x;
// The Player should also be stopped from going outside the screen
CGSize screenSize = [CCDirector sharedDirector].winS
float imageWidthHalved = player.texture.contentSize.width * 0.5f;
float leftBorderLimit = imageWidthH
float rightBorderLimit = screenSize.width - imageWidthH
// preventing the player sprite from moving outside the screen
if (pos.x & leftBorderLimit)
pos.x = leftBorderL
playerVelocity = CGPointZ
else if (pos.x & rightBorderLimit)
pos.x = rightBorderL
playerVelocity = CGPointZ
// assigning the modified position back
player.position =
边界检查可以防止玩家精灵显示在屏幕外。我们不得不再一次把玩家精灵纹理的contentSize(内容尺寸)考虑在内,因为玩家精灵是以精灵图像的中心为准计算位置的,我们不希望图像的任何一边离开屏幕。为此,计算imageWidthHalved的值,然后用它检查刚刚更新的玩家位置是否在左右边界之内。上面的代码稍显冗长,但这样更容易理解。现在构建并运行项目,体验能够控制玩家精灵的感觉。
如果玩过Tilt to Live之类的游戏,可能会注意到这里实现的简单的加速计控制无法像在那些游戏中一样有一种动态的感觉。这是因为要实现流畅、动态的加速计控制,需要对加速计输入进行过滤。在Kobolds2D中,使用KKInput类的属性可以获得高通(瞬时)和低通(平滑)过滤后的加速计输入:
float smoothed = [KKInput sharedInput].acceleration.smoothedX;
利用加速计控制的游戏通常会使用低通过滤器。“低通”意味着过滤掉加速度突然且极端的变化,从而使得到的结果值十分平滑。下面是由加速计输入值(rawX/rawY)和常量filterFactor(范围为0.0~1.0)得到新的smoothedX/smoothedY值(示例变量)的低通过滤器。0.1是一个不错的过滤因子,表示在新的平滑后的值中只考虑了10%的当前原始加速计值:
smoothedX = (rawX * filterFactor)
(smoothedX * (1.0 - filterFactor));
(rawY * filterFactor)
(smoothedY * (1.0 - filterFactor));
添加障碍物
在往游戏中加入一些让玩家躲避的东西之前,这个游戏还没有什么可玩性。接下来在项目里加入一些令人憎恶的东西:六足人造蜘蛛。有谁不想躲着它们吗?
与玩家精灵一样,需要把spider.png和spider-hd.png加入到Resources组中。然后在GameLayer.h的接口中加入3个新的成员变量:在程序清单4-9中出现的NSMutableArray类引用spiders,以及在程序清单4-12中使用的spiderMoveDuration和numSpidersMoved:
@interface GameLayer : CCLayer
CGPoint playerV
NSMutableArray*
float spiderMoveD
int numSpidersM
在代码中应该避免使用CCArray。CCArray是NSArray和NSMutableArray的快速替代版本,但是它只是快了一点点,使用它几乎不会对帧率产生影响。而它的一些方法(如insertAtIndex或removeObjects)要比NSMutableArray的相同方法慢得多。CCArray最大的问题是过去已经存在一些严重的bug,比如与ARC的兼容性问题。它也不能支持NSArray/NSMutableArray的全部功能。例如,无法枚举带有block对象的CCArray,这使得它不适合用于并行处理(例如,通过Grand Central Dispatch来完成)。整体上看,NSMutableArray要比CCArray更可靠,兼容性更好,并且缺陷更少。任何时候,我都愿意用降低一些性能来换取高可靠性。cocos2d在内部使用了CCArray,不过就内部使用来看,CCArray经过了大量测试,证明没有问题,所以这种用法我是可以接受的。
与此同时,在GameLayer的init方法中,在scheduleUpdate后面加上对initSpiders方法的调用,我们将在后面讨论它:
-(id) init
if ((self = [super init]))
[self scheduleUpdate];
[self initSpiders];
随后,我们会向GameLayer类中加入一大段代码,先从initSpiders方法开始,它创建了蜘蛛精灵,如程序清单4-8所示。
程序清单4-8
为了更好地进入,蜘蛛精灵被初始化并添加到NSMutableArray中
-(void) initSpiders
CGSize screenSize = [CCDirector sharedDirector].winS
// using a temporary spider sprite is the easiest way to get the image's size
CCSprite* tempSpider = [CCSprite spriteWithFile:@"spider.png"];
float imageWidth = tempSpider.texture.contentSize.
// Use as many spiders as can fit next to each other over the whole screen width.
int numSpiders = screenSize.width / imageW
// Initialize the spiders array using alloc.
spiders = [NSMutableArray arrayWithCapacity:numSpiders];
for (int i = 0; i & numS i++)
CCSprite* spider = [CCSprite spriteWithFile:@"spider.png"];
[self addChild:spider z:0 tag:2];
// Also add the spider to the spiders array.
[spiders addObject:spider];
// call the method to reposition all spiders
[self resetSpiders];
这里要说明的是,创建名为tempSpider的CCSprite对象只是为了获得精灵图像的宽度,然后用它决定蜘蛛精灵的数量。获得图像尺寸最简单的方法就是创建临时的CCSprite对象。注意,我没有把这个tempSpider对象作为子节点加到任何其他节点上,也没有把它分配给实例变量。这意味着当程序执行离开initSpiders方法后,ARC会知道tempSpider对象已经不再使用,并自动释放其内存。
与其形成对比的是名为spiders的数组,我用它来保存对所有蜘蛛精灵的引用。这个数组被分配给实例变量spiders,因此,在GameLayer对象本身被释放以前,ARC不会释放该数组对象。使用ARC时,不需要自己以任何方式释放spiders数组。
在程序清单4-8的结尾,调用了[self resetSpiders]方法,这个方法的代码在程序清单4-9中。将精灵的初始化和定位分开处理的原因在于:游戏总会结束,之后游戏将被重置。最为高效的做法就是将所有游戏对象移动到它们的初始位置。然而,一旦游戏趋于复杂,这种做法将不具备可行性。最终,最简单的做法就是以玩家的等待为代价重新加载全部场景。
在重新加载场景时,你可能想使用[[CCDirector sharedDirector] replaceScene: self];来重新加载同一场景。但是这会导致程序崩溃,因为self是当前正在运行的场景。在cocos2d中尝试用正在运行的场景替换其自身会导致程序崩溃。实际上,必须创建GameLayer类的新实例:[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];。
程序清单4-9
重设蜘蛛精灵的位置
-(void) resetSpiders
CGSize screenSize = [CCDirector sharedDirector].winS
// Get any spider to get its image width
CCSprite* tempSpider = [spiders lastObject];
CGSize size = tempSpider.texture.contentS
int numSpiders = [spiders count];
for (int i = 0; i & numS i++)
// Put each spider at its designated position outside the screen
CCSprite* spider = [spiders objectAtIndex:i];
spider.position = CGPointMake(size.width * i + size.width * 0.5f,?
screenSize.height + size.height);
[spider stopAllActions];
// Schedule the spider update logic to run at the given interval.
[self schedule:@selector(spidersUpdate:) interval:0.7f];
// reset the moved spiders counter and spider move duration (affects speed)
numSpidersMoved = 0;
spiderMoveDuration = 4.0f;
我再一次临时获取了某个已有的蜘蛛精灵,然后通过纹理的contentsize属性获得它的图像尺寸。这里我没有创建新的精灵,因为已有同类精灵存在了,并且由于所有的蜘蛛都使用相同尺寸大小的同一图像,我甚至不用关心获取的是哪个蜘蛛,因此我只是简单地获取了数组的最后一项。
接下来修改每个蜘蛛的位置,使它们整体横跨整个屏幕的宽度。还是同样的原因,蜘蛛精灵的纹理以其中心点作为位置,position属性的x值加上了图像宽度的一半。至于高度,每个蜘蛛也被设为高于屏幕顶端一个图像高度。这个数值是任意的,这里我要使图像不可见,能达此目的者均可。由于重置后蜘蛛仍然可能在移动,因此要停止它的全部动作。
如果不是绝对必要的话,为了节约CPU资源,最好不要在for或其他循环语句中使用方法调用作为循环条件。本例中创建numSpiders变量来保存[spiders count]的调用结果,然后将其用作for循环的循环条件。由于在循环过程中数组本身并未被修改,因此数组的计数值保持不变。这就是为何我能保存这个值并在for循环中省去对[spiders count]的重复调用。
我还指定spidersUpdate:选择器每0.7秒运行一次——这是另一个蜘蛛从屏幕顶端落下的时间间隔。如果选择器已被指定,cocos2d会用一条日志消息指出这一点,你可以忽略这条消息。cocos2d并不会再次指定选择器,而是会更新已指定选择器的时间间隔。如程序清单4-10所示,spidersUpdate:方法会随机挑选一个已经存在的蜘蛛,检查它是否空闲,然后使用一系列动作操作它从屏幕上方落下。
程序清单4-10
spridersUpdate:——让蜘蛛频繁下落的方法
-(void) spidersUpdate:(ccTime)delta
// Try to find a spider which isn't currently moving.
for (int i = 0; i & 10; i++)
int randomSpiderIndex = CCRANDOM_0_1() * spiders.
CCSprite* spider = [spiders objectAtIndex:randomSpiderIndex];
// If the spider isn't moving it won't have any running actions.
if (spider.numberOfRunningActions == 0)
// This is the sequence which controls the spiders' movement
[self runSpiderMoveSequence:spider];
// Only one spider should start moving at a time.
我还从未对任何程序清单置之不理,是吧?你也许想知道为什么这里我要循环迭代10次来得到一个随机的蜘蛛。原因在于,我不知道随机生成的索引值对应的蜘蛛是不是活动的,所以要确认最终随机选出的蜘蛛当前是空闲的。如果10次之后——当然,这个数字是任意的——仍然没有随机选出一个空闲的蜘蛛,就会跳过这次更新,然后等待下一次。
也可以使用do/while循环进行不断尝试,直到找到空闲的蜘蛛为止。但有一种可能,即此刻所有的蜘蛛都在移动——这取决于设计参数,如新蜘蛛落下的频率。游戏会为尝试寻找空闲的蜘蛛而无限循环,从而锁死。此外,我并不喜欢太卖力;对于这个游戏而言,另一个蜘蛛等个几秒再落下也并无大碍。虽然如此,如果查看DoodleDrop03项目,就会发现我加入了日志记录语句,输出找到空闲蜘蛛的重试次数。
由于蜘蛛执行的唯一动作就是一系列的运动,我只要检查蜘蛛当前是否执行任何动作即可。如果没有执行动作,我就假定它是空闲的。然后执行程序清单4-11所示的runSpiderMoveSequence方法。
程序清单4-11
通过动作序列控制蜘蛛的运动
-(void) runSpiderMoveSequence:(CCSprite*)spider
// Slowly increase the spider speed over time.
numSpidersMoved++;
if (numSpidersMoved % 8 == 0 && spiderMoveDuration & 2.0f)
spiderMoveDuration - = 0.1f;
// This is the sequence which controls the spiders' movement.
CGPoint belowScreenPosition = CGPointMake(spider.position.x,?
-spider.texture.contentSize.height);
CCMoveTo* move = [CCMoveTo actionWithDuration:spiderMoveDuration
position:belowScreenPosition];
CCCallBlock* callDidDrop = [CCCallBlock actionWithBlock:^void(){
// move the droppedSpider back up outside the top of the screen
CGPoint pos = spider.
CGSize screenSize = [CCDirector sharedDirector].winS
pos.y = screenSize.height + spider.texture.contentSize.
spider.position =
CCSequence* sequence = [CCSequence actions:move, callDidDrop, nil];
[spider runAction:sequence];
runSpiderMoveSequence方法记录下了落下的蜘蛛数目。每落下8个蜘蛛,spiderMove- Duration就降低,从而增加所有蜘蛛的速度。你也许不熟悉%,它被称为求模操作符。求模运算的结果是左操作数除以右操作数的余数,即如果numSpidersMoved可以被8整除,那么求模结果为0。
动作序列只包含了一个CCMoveTo动作和一个CCCallBlock动作。动作还有改进的空间,可以使它就像真正的六足蜘蛛人那样,下落一点点,停住,然后一路下到底。这个任务就留给你了,不过在最终版的DoodleDrop项目中,你可以找到一个示例实现。
到目前为止,唯一重要的是知道我选择了在传递给CCCallBlock动作的block函数中重置了蜘蛛的位置。这个block函数可以简单地使用与runSpiderMoveSequence方法相同的spider变量。它在蜘蛛的运动完成后调用,即蜘蛛已经掉到了玩家角色的下面。通过使用这个block函数,你就不需要花大力气找出正确的蜘蛛。而后,将蜘蛛的位置重置为屏幕上方。程序清单4-12将程序清单4-11中的block函数单独列了出来。
程序清单4-12
在CCCallBlock中重设蜘蛛位置,使之可以从屏幕上方重新落下
CCCallBlock* callDidDrop = [CCCallBlock actionWithBlock:^void(){
// move the droppedSpider back up outside the top of the screen
CGPoint pos = spider.
CGSize screenSize = [CCDirector sharedDirector].winS
pos.y = screenSize.height + spider.texture.contentSize.
spider.position =
到目前为止,一切顺利。我猜你一定迫不及待地想试玩一下。我想你会很快注意到游戏还是缺了些东西。小提示:看一下下面的标题。
《ios cocos2d 2 游戏开发实战(第三版)》试读电子书免费提供,有需要的留下邮箱。
Copyright (C) , All Rights Reserved.
版权所有 闽ICP备号
processed in 0.043 (s). 12 q(s)

我要回帖

更多关于 原始传奇道士升级攻略 的文章

 

随机推荐