cocos2d-objc 3.0+ 游戏开发学习手册(三): CCAction 的简单使用与触摸

图片来自网络

导语

在游戏中,角色(cocos2d中的术语为精灵)都是具有丰富的动作效果,合理的使用这些动作比如闪烁,跳跃,翻转,都会带来体验上的差异.cocos2d为我们提供了多种CCAction类,本文通过对CCAction的简单使用示例,帮助大家了解在实际应用中如何借助这些Action实现自己的动画效果.

CCActionMoveTo

cocos2d 3.0之前的版本中,位移动作是CCMoveTo,在3.0新版本之后所有的命名都发生了变化: CCAction+动作名称.

  • 示例1:(在MainScene.m的init 方法中添加代码)

    // 设置背景
    CCNodeColor *bg = [CCNodeColor nodeWithColor:CCColor.grayColor];
    [self addChild:bg];
    // 创建精灵
    CCSprite *qq = [CCSprite spriteWithImageNamed:@"qq.png"];
    qq.position = ccp(100, 100);
    [self addChild:qq];
    // 添加动画 : 用2秒的时间移动到位置(300,100)
    CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:2.0 position:ccp(300, 100)];
    [qq runAction:moveAction]; 
    

运行效果:


moveTo

CCActionSequence

根据示例我们看到,在cocos2d中实现动画非常简单! 但有时候我们需要游戏角色(精灵)执行的动画可能是比较复杂的,例如移动一段距离后翻转或者放大或者闪烁等,因此我们需要执行一组动作才可以,cocos2d已经为我们提供了一个CCActionSequence 动作队列来实现这种需求.

  • 示例2: 组合动画

    // 创建精灵
    CCSprite *qq = [CCSprite spriteWithImageNamed:@"qq.png"];
    qq.position = ccp(100, 100);
    [self addChild:qq];
    // 添加动画
    CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:2.0 position:ccp(300, 100)];
    
    // 添加动画2
    CCActionMoveTo *action2 = [CCActionMoveTo actionWithDuration:2.0 position:ccp(300, 300)];
    
    // 添加动画3
    CCActionMoveTo *action3 = [CCActionMoveTo actionWithDuration:2.0 position:ccp(150, 300)];
    
    // 添加动画4 : 闪烁3次
    CCActionBlink *action4 = [CCActionBlink actionWithDuration:2.0 blinks:3];
    
    // 添加动画5  : 放大2倍
    CCActionScaleTo *action5 = [CCActionScaleTo actionWithDuration:2.0 scale:2];
    // 创建动画执行队列,并添加需要执行的动作
    CCActionSequence *sequence = [CCActionSequence actions:moveAction,action2,action3,action4,action5, nil];
    // 运行动画  
    [qq runAction:sequence];
    

运行效果:


组合动画

CCActionCallFunc

游戏开发中我们经常需要在某个动作执行完毕后再做一些业务逻辑上的处理,这就需要我们监听某个动画的完成情况.cocos2d中我们常常使用CCActionCallFunc来监听一个动画结束后的回调处理.

  • 示例3: 监听动画完成

    // 创建精灵
    CCSprite *qq = [CCSprite spriteWithImageNamed:@"qq.png"];
    qq.position = ccp(100, 100);
    [self addChild:qq];
    // 添加动画
    CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:2.0 position:ccp(300, 100)];
    
    // 添加动画回调动作
    CCActionCallFunc *endAction = [CCActionCallFunc actionWithTarget:self selector:@selector(endMoveToAction)];
    
    // 创建动画执行队列
    CCActionSequence *sequence = [CCActionSequence actions:moveAction,endAction, nil];
    [qq runAction:sequence];
    
动画完成回调方法:
 - (void)endMoveToAction{
        CCLOG(@"动画执行完毕 ~~");
    }

运行效果:
动画完毕回调

Touch(触摸)

cocos2d中如果要响应触摸,需要在显示的场景类(MainScene)中开启用户交互:

// 设置开启触摸  
self.userInteractionEnabled = YES;

然后实现触摸响应的方法即可:

- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
         // 获取触摸位置
        CGPoint p = [touch locationInNode:self];
        // 创建动画
        CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:2 position:p];
        // 运行动画
        [self.qq runAction:moveAction];
  }

示例效果:
触摸移动效果

运行上面触摸的例子后,如果你多次连续点击屏幕,会发现精灵图片(本例中的qq图片)移动的最后结果与我们实际希望的并不相同,甚至会移出屏幕,不必担心,这是由于CCActionMoveTo类自身的原因: 它本身可以被同时多次调用,但某一刻的结果是每个单次调用的总和,下面我们通过stopAction来修正这个问题~

stopAction

cocos2d中我们可以任意的触发和停止action,经常用到的方法是:
stopAction:(CCAction * action) : 停止指定的action
stopActionByTag:(NSInteger) : 停止指定tag值的action
stopAllActions : 停止所有action
在我们的触摸示例中,我们可以用stopActionByTag的方式修正代码,只需要修改两个地方即可:
1. 在每次触摸事件开始(touchBegan)时停止上一个动画
2. 给动画设置一个tag值
修改后的代码如下:

- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
        // 移除上一个动画效果
        [self.qq stopActionByTag:0];

        CGPoint p = [touch locationInNode:self];
        CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:0.3 position:p];
         // 给动画设置tag值
        [moveAction setTag:0];
        [self.qq runAction:moveAction];
}

边界处理

如果点击触摸在屏幕边缘的时候,我们发现精灵会有一部分内容超出屏幕,导致显示不完整.例如下图:

精灵超出屏幕

另外,我们希望移动的时间可以根据距离变化而不同,最后的代码如下:

- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{

        [self.qq stopActionByTag:0];
        CGPoint p = [touch locationInNode:self];
        // 获取屏幕size
        CGSize screenSize = [CCDirector sharedDirector].viewSize;
        // 根据两点之间的距离计算移动时间
        CGFloat duration = ccpDistance(p, self.qq.position) / 200.0;
        // 限制边界值
        p.x = clampf(p.x, self.qq.contentSize.width / 2, screenSize.width - self.qq.contentSize.width / 2);
        p.y = clampf(p.y, self.qq.contentSize.height / 2,screenSize.height - self.qq.contentSize.height / 2);

        CCActionMoveTo *moveAction = [CCActionMoveTo actionWithDuration:duration position:p];
        [moveAction setTag:0];
        [self.qq runAction:moveAction];
   }

clampfcocos2d中提供的一个边界检测方法,只需要我们提供最大值最小值,它就会确保我们的值不会超过 这个范围,其实它的实现也非常简单:

 float clampf(float value, float min_inclusive, float max_inclusive) {
    if (min_inclusive > max_inclusive) {
        CC_SWAP(min_inclusive,max_inclusive);
    }
    return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive;
}

最终效果:


边界修正效果

结束语

我们简单介绍了游戏开发中会经常使用CCAction的用法,很多看似复杂的效果其实都是通过简单的动画组合而成.而cocos2d中提供的action也非常丰富,希望大家能够通过基本的练习可以触类旁通,因为它们都用法都十分相近,掌握起来也不会特别困难.例如大家可以思考一下如何实现一个始终运动的游戏背景,就像下面这样:

运动背景

悄悄提示: CCActionRepeatForever 可以实现不断重复的效果,然后再根据本文介绍的内容就完全可以实现这样的需求了,大家快动动手吧~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容