首先申明
1.游戏原始demo和资源来自博客家园的子龙山人http://www.cnblogs.com/zilongshanren/。力荐该博客,有兴趣的可以自己上上面去看,资料很多
2.我等会上传的一个demo是自己配合前面的例子,添加了一些首页菜单,过渡场景,以及过渡动画的简单运用。
首先,本人是没有正紧做过游戏,无论是j2me活或着是android。
也就是纯粹按照自己的一个思路来表达和设计下一个最简单游戏该有的雏形,
以下内容都是以打地鼠为例而展开。
其实很多时候我们开发一个应用或着游戏时,很难下手的一点就是身边没有素材和资源,然后导致自己迟迟没有动手,这也导致我有想学下ps和ai的冲动。
上面提到的子龙山人的博客既提供了资源,同样还有源码。当然这对于你学习初期,你自己动手来完成一个游戏是很有帮组性,而对于能自己完成一个简单游戏,
对于新手也是很有意义和成就感。
好了,说说正题
我们按打地鼠游戏几个效果图来细说吧
1.进入游戏菜单
当然,四个选项卡只是一个模拟,只有“开始新游戏”是有点击监听的,该界面和简单就一层menu。
2.点击进入新游戏,进入过渡场景
我们知道在菜单选择后进入游戏场景时,有一个过渡场景,一是可以很好的帮组我们解决场景切换时内存过高的问题,
二是帮我加载下个场景所需要的数据,加载完成后才跳转到游戏场景,这样可以避免因数据加载造成用户视觉上的延时和卡顿。
3.无聊添加的一个场景过渡效果
游戏场景从上而下推入
4.正式的游戏场景
游戏场景就是整个demo最主要的部分。
这边说下,这部分代码逻辑可能会和山人的有点不一样。
因为本身我是在网上搜索TexturePacker也就是纹理集合制作工具,一开始看到的是这个工具的教程那篇,也就是打地鼠的第一篇
(第二天我浏览他的其他博文发现打地鼠还有下篇~~~)。
然后山人提供了基本整个游戏的资源,我才安下心来决定也跟着做一下这个小游戏。
好了,现在我们来看下这个界面上元素的分布。
1.背景的绿色草地,这个草地其实是按照洞的圆一半分了两块,一开始我拿到资源看着很纳闷,为毛分成了两块。
后来才知道,当你的地鼠出来时,整个地鼠感觉是处于在草地前面(地鼠背后绿地部分被遮盖了),但是当地鼠下地时,
怎么才能做到地鼠下地的状态呢?当然我们可以用隐藏什么的属性么,但是我们都知道,无论是设置属性或是即时动画,鼹鼠都是瞬间没了,
我们希望做的是鼹鼠慢慢的下到地下去,用延时动画下地,那我们总不能说计算和剪裁地鼠,把下地那部分处理吧(反正我是不会)。
因此,利用深度就很好的解决了遮盖问题
//添加草地,注意,主要是add时候的深度参数,因为等会还有鼹鼠要出来,精灵的深度应该是,前面的一个块草地,鼹鼠,后面的草地 CGSize winSize = [[CCDirector sharedDirector] winSize]; CCSprite *grassUp = [CCSprite spriteWithSpriteFrameName:@"grass_upper.png"]; grassUp.position = CGPointMake(winSize.width/2, winSize.height/2); grassUp.anchorPoint = CGPointMake(0.5, 0); [self addChild:grassUp z:-1]; CCSprite *grassLow = [CCSprite spriteWithSpriteFrameName:@"grass_lower.png"]; grassLow.position = CGPointMake(winSize.width/2, winSize.height/2); grassLow.anchorPoint = CGPointMake(0.5, 1); [self addChild:grassLow z:1];
2.鼹鼠。
这最复杂的元素,这边我把鼹鼠设计成独立的一个精灵类。
分析下,鼹鼠可能含有的属性和行为
1.是否处于活动中的属性,这个属性是为了间隔的随记让鼹鼠跑出来准备的,就是我们在遍历所有地鼠时,检测当前被抽中的地鼠是否处于活动状态,
而来决定是否让他跑上地面。
2.是否处于地面嘲笑你。这个是后来才添加进去的一个属性,因为鼹鼠只有在活动,并且处于地面,并且嘲讽你的0.X秒时间呢,你可以beat it。
3.鼹鼠的行为,一次出洞嘲讽你的活动:这边需要分析,这个出动行为的涉及到的一些变化。
首先,逻辑一但执行到让该鼹鼠出动啦,那么,他的活动属性被激活—》从底下钻到地面—》嘲讽属性激活—》嘲笑动画
—》嘲讽结束后,嘲讽属性冷却—》下地动作—》活动属性冷却。(当然,一开始可能不会想到这么多逻辑处理,试几次慢慢解决)。
-(void)popMole { [self unschedule:@selector(popMole)]; [self stopAllActions]; CCAnimation* anim = [CCAnimation animationWithFrame:@"mole_laugh" frameCount:3 delay:0.2f]; CCAnimate* laughAn = [CCAnimate actionWithAnimation:anim]; CCCallFunc *setLaugh = [CCCallFunc actionWithTarget:self selector:@selector(setLaguhingU:)]; CCCallFunc *quitLaugh = [CCCallFunc actionWithTarget:self selector:@selector(quitLaguhingU:)]; CCMoveBy *up = [CCMoveBy actionWithDuration:0.5 position:ccp(0, self.contentSize.height)]; CCEaseInOut *es = [CCEaseInOut actionWithAction:up rate:5.0]; id moveDown = [es reverse]; CCCallFunc *endCall = [CCCallFunc actionWithTarget:self selector:@selector(keepQuiet)]; [self runAction:[CCSequence actions:es, setLaugh,laughAn, quitLaugh,moveDown, endCall, nil]]; }
有了上面的,这个理解起来就比较简单了。此刻能发生该行为的情况是地鼠在上面嘲笑你,
beat it,好了,很简单,此刻停止他的整个动作序列—>嘲笑属性冷却(为了简单,我顺便把它的活动属性也冷却了,但是,想要好的效果,最好在下地后冷却)
—>被敲打后苦逼表情动画—》缓缓晕倒下地
//敲打到鼹鼠 - (void)thumpMole { [self stopAllActions]; [self keepQuiet]; CCAnimation* anim = [CCAnimation animationWithFrame:@"mole_thump" frameCount:3 delay:0.2f]; CCAnimate* thumps = [CCAnimate actionWithAnimation:anim]; id thumAc = [CCRepeatForever actionWithAction:thumps]; [self runAction:thumAc]; [self schedule:@selector(moleHide:) interval:0.2]; }
4.游戏场景逻辑控制,主要的逻辑场景就是控制地鼠的出洞,这边出洞逻辑算法是demo中的
#pragma mark 鼹鼠走起 -(void)moleStartPop:(ccTime)dt { for (Mole *mole in moles) { if (arc4random() % 3 == 0) { if (!mole.active) { mole.active = YES; [mole popMole]; } } } }
arc4random()%3会返回 0到2,判断是否等于0,也就是每个地鼠都是1/3机会被选中,选中后在判断是否是在地下的,然后让他出地。
当然,很快我们就会发现这个算法的会造成问题,(在没有敲打的情况下)有时候很多地鼠出洞,很多时候地上一个地鼠也没有~
按我们的思路或着关卡设计,可能说希望保持整个场景至少需要N个地鼠处于活跃状态,这就需要新添加一个数组来保存当前场景中在地下的地鼠,
遍历时从这里面来取出(N-活动地鼠个数)等等,当然,这样对于快速数组中数据的更新什么的,是一个不小的系统开销。
这边,我们就用demo提供给我们这个方法好了,毕竟我们的目的是跑通流程。
例外一个情况我挺纳闷的,我在这个demo编写时,就仅仅书写了添加玩草地时,fps突然就只有30了,不知道什么情况。
5.场景中对于地鼠的敲打监听
本身我觉得这个监听按照功能划分应该设计和放在地鼠类中,但是后来会遇到一个问题,此时监听发生在地鼠对象中,但是得分计数器的引用是在场景类里。
那么敲打玩地鼠后需要刷新就会很麻烦,当然,解决的方法可能我们能想到很多,一个回调,通知以及如果你看过
《Learn iPhone and iPad Cocos2D Game Development》前几章,会提到一种将游戏场景设计成伪单例的手法,那么我们在地鼠类得到对象并且操作里面这个
得分器刷新。
后来考虑到游戏的简单性,我们就直接将点击事件放在了游戏场景类中
- (void)registerWithTouchDispatcher { [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO]; }
然后
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { // UITouch *touch = [touches anyObject]; // CGPoint toucgPoint = [touch locationInView:[touch view]]; CGPoint toucgPoint = [self convertTouchToNodeSpace:touch]; for (Mole *mole in moles) { if (mole.isLaguh) { // CGRect moleRect = CGRectMake(mole.position.x - (mole.contentSize.width/2), // mole.position.y - (mole.contentSize.height/2), // mole.contentSize.width, // mole.contentSize.height); if (CGRectContainsPoint(mole.boundingBox,toucgPoint)) { [mole thumpMole]; score++; scoreLabel.string = [NSString stringWithFormat:@"击中了 %d 只鼹鼠",score]; } } } return YES; }上面代码很简单,主要提下坐标点的转化, CGPoint toucgPoint = [self convertTouchToNodeSpace:touch];
一开始我没有用这句,然后发现当我点击地鼠头时,检测到的点击点不是在地鼠包围圈中。第二天看了山人那篇下时,才得以注意到这个。
第二点要提及的是,判断有个点是否在某个矩形包围圈内,当然,这个直接于方法了~‘
最后记得处理玩这个点击事件后返回YES,这样才是将此次分发touch事件处理,不会传递到下一层。
好了,基本整个简单游戏就完成了。
当然,还能做很多改进,因为我本身只是初涉这块几天,说实话,真正如何来设计一个游戏框架逻辑都不懂,
毕竟我还要拿钱给公司干活,基本花了一个下午来学习和编码了这个demo。
最后
1.进入游戏画面时,可以多添加一个开始,暂停等等,控制场景逻辑方法的按钮标签(我是场景进入后几秒后自动执行逻辑)
2.有兴趣可以把草地缩小已被,然后3*4 = 12只地鼠,哈哈,这个应该好玩点,不过这样你的资源西药改动和自己打包,
免费版本的TP工具,会将部分图片打上水印的文字~~~~
3.从《Learn iPhone and iPad Cocos2D Game Development》引入的那个动画帮助类很好用~
4.可以设置一个游戏资源加载和释放的帮组类
NSString *bgPlist = @"background.plist"; NSString *fgPlist = @"foreground.plist"; NSString *spPlist = @"sprites.plist"; NSString *sSheet = @"sprites.pvr.ccz"; //加载当前场景需要用到的图片资源到精灵帧缓存 [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:bgPlist]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:fgPlist]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:spPlist];
5.还是自己动手码一遍吧,我觉得,有了素材,做起来还是比较有动力的。
这是我上面这个demo资源地址
http://download.csdn.net/detail/nono_love_lilith/4443857
需要看原版的可以前往子龙山人博客