cocos2d 学习 第四章


#import <Foundation/Foundation.h> #import "cocos2d.h"
@interface GameScene : CCLayer
{
     CCSprite* player;
}
+(id) scene;
@end

启用加速计输入,创建并定位玩家精灵

-(id) init

{

   if ((self = [super init]))
   {

      self.isAccelerometerEnabled = YES;                          // 支持重力加速

            player = [CCSprite spriteWithFile:@"alien.png"];            // 由图片文件生成一个CCSprite对象作为主角

            [self addChild:player z:0 tag:1];                           // 将主角添加到当前场景中

            CGSize screenSize = [[CCDirector sharedDirector] winSize];  // 通过CCDirector对象得到设备尺寸

            float imageHeight = [player texture].contentSize.height;    // 通过CCSprite对象得到主角图片的高度

            player.position = CGPointMake(screenSize.width/2, imageHeight/2);  // 将主角的位置设置为屏幕下方中心

            [self initSpiders];                       // 初始化蜘蛛对象

            [selfscheduleUpdate];                    // 是一个CCLayer对象定义的方法,它将在每桢调用update方法

    }

     return self;
}

注意,我没有保留玩家精灵。因为我们已将其添加为层 的子节点,所以 cocos2d 会保留它。另外由于玩家精灵永远不会从层中移除,因而现在这 样做就足够了,不需要特意对它进行保留。不保留一个内存被其他类或对象管理的对象称 为“保持弱引用”。 

通过调用[player texture].contentSize.height 返回精灵纹理的内容尺寸。 我讲到 iOS 中纹理尺寸的大小只能是 2 的方幂。但是实际的图像尺寸可能会比纹理尺寸小。 

-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration   

{

        CGPoint pos = player.position;
        pos.x += acceleration.x * 10;
        player.position = pos;

注意到奇怪之处了吗?上面的三行代码用一行就能写好:

// ERROR: lvalue required as left operand of assignment

player.position.x += acceleration.x * 10; 

position 属性的类型是 CGPoint,这是一个 普通的 C 结构体。Objective-C 中的属性不能直接向结构体的域赋值。 

注意到加速计输入哪里不正常了吗?是的,它反应迟缓,移动不畅。这是因为玩家精灵并没执行真实的加速和减速。 

实现加速与减速的概念不在于直接改变玩家的位置值,而是使用单独的 CGPoint 变量 作为速度矢量。每次接收到加速计事件时,速度矢量就加上从加速计得到的输入。当然, 这意味着我们得把速度限制在一个任意的最大值内,否则减速时就要花点时间了。不管有没有接收到加速计输入,在每一帧都把速度加到玩家位置上。 

为什么不使用动作来移动玩家精灵呢?无论何时你需要频繁地——如每秒数次——改 变对象的速度或方向,使用 move 动作都不是一个好的选择。动作适用于相对使用期较长 的对象,所以频繁创建新对象在分配和释放内存上增加了额外开销,这会使游戏性能大幅 下降。

更糟糕的是,如果不为动作留出一点时间,动作是不会执行的。这就是在每帧添加新 动作来替换前一个却没有任何效果的原因。 

-(void) accelerometer:(UIAccelerometer *) acceleromete didAccelerate:(UIAcceleration *)acceleration

{
  float deceleration = 0.4f;            // 减速值

      float sensitivity = 6.0f;               // 明感度

      float maxVeloctiy = 100;            // 最大速度

    

    playerVelocity.x = playerVelocity.x * deceleration + acceleration.x *sensitivity;

    // 新的玩家速度=原有速度*减速值+加速计*明感度值

    CCLOG(@"playVelocity.x = %f",playerVelocity.x);

    if(playerVelocity.x > maxVeloctiy)

    {

        playerVelocity.x = maxVeloctiy;

    }

    else if(playerVelocity.x < -maxVeloctiy)

    {

        playerVelocity.x = maxVeloctiy;

    }


现在 playerVelocity 能够改变了,但如何把速度加到玩家精灵的位置值上呢?可以在 GameScene init 方法中指定如下 update 方法:

(void) update:(ccTime)delta

method to be called every frame [self scheduleUpdate];

同样需要添加“(void) update:(ccTime)delta”方法 

- (void)update:(ccTime)delta

{

    CGPoint pos = player.position;          // 得到主角当前位置pos

    pos.x += playerVelocity.x;              // posX值加上速度playerVelocity的值

    CGSize screenSize = [[CCDirector sharedDirector] winSize];          // 得到设备尺寸

    float imageWidthHalved = [player texture].contentSize.width * 0.5f; // 得到主角图片宽度的一半

    float leftBorderLimit = imageWidthHalved;                       // 左边界

    float rightBorderLimit = screenSize.width - imageWidthHalved;   // 右边界

    if(pos.x <leftBorderLimit)          // 如果新位置小于左边界

    {

        pos.x = leftBorderLimit;        // 新位置等于左边界

        playerVelocity = CGPointZero;   // 速度重置为0

    }

    else if(pos.x >rightBorderLimit)    // 如果新位置大于右边界

    {

        pos.x = rightBorderLimit;       // 新位置等于右边界

        playerVelocity = CGPointZero;   // 速度重置为0

    }

    player.position = pos;              // 如果新位置没有超出范围,则将移动主角到新位置

}

添加障碍物

  CCArray *spiders;               // 蜘蛛

    float spiderMoveDuration;       // 

    int numSpidersMoved;            // 已经移动过的蜘蛛数量

 

#pragma mark 初始化所有蜘蛛对象

- (void)initSpiders

{

    CGSize screenSize = [[CCDirectorsharedDirector] winSize];

    CCSprite *tempSpider = [CCSpritespriteWithFile:@"spider.png"]; // 由图片文件生产CCSprite蜘蛛对象

    float imageWidth = [tempSpider texture].contentSize.width;      // 得到蜘蛛对象图片宽度

    int numSpiders = screenSize.width/imageWidth;                   // 由设备宽度/图片宽带得到可以容纳蜘蛛的数量

    spiders = [[CCArray alloc] initWithCapacity:numSpiders];        // 生成相应的数组

    for (int i = 0; i<numSpiders; i++)

    {

        CCSprite *spider = [CCSpritespriteWithFile:@"spider.png"];     // 循环生成每个蜘蛛的CCSprite

        [self addChild:spider z:0 tag:2];                               // 将蜘蛛放到场景中

        [spiders addObject:spider];                                     // 将蜘蛛对象放到数组中

    }

    [self resetSpiders];                                                // 重置所有蜘蛛的位置

}

 

#pragma mark 重置所有蜘蛛对象的位置

- (void)resetSpiders

{

    CGSize screenSize = [[CCDirectorsharedDirector] winSize];

    int numSpiders = [spiders count];                                   // 得到现有蜘蛛数组中的个数

    if(numSpiders>0)                                                    

    {

        CCSprite *tempSplider = [spiders lastObject];                   // 取得最后一个蜘蛛对象

        CGSize size = [tempSplider texture].contentSize;                // 得到蜘蛛对象的尺寸

        for (int i = 0; i<numSpiders; i++)                              

        {

            CCSprite *spider = [spiders objectAtIndex:i];               // 循环每个蜘蛛对象

            spider.position = CGPointMake(size.width * i + size.width * 0.5f

                                      , screenSize.height+size.height); // 将蜘蛛下移一个图片高度

            [spider stopAllActions];                                    // 停止蜘蛛对象的所有动作

        }

    }

    [self unschedule:@selector(spidersUpdate:)];                        // 停止所有循环动作

    [self schedule:@selector(spidersUpdate:) interval:0.7f]; // 重现启动所有循环动作,每隔0.7秒循环蜘蛛下落动作

    numSpidersMoved = 0;                                                // 重置移动过的蜘蛛数量为0

    spiderMoveDuration = 4.0f;                                          // ??????

}

 

#pragma mark 每隔0.7秒,随机挑选一个蜘蛛,检查它是否有空,如果是则更新它的位置

- (void)spidersUpdate:(ccTime)delta

{

    for (int i = 0; i<10; i++)

    {

        // CCRANDOM_0_1() == ((random() / (float)0x7fffffff ))

        float rf = CCRANDOM_0_1();      // 生成01之间的某个随机数

        int randomSpiderIndex = rf*[spiders count];

        CCLOG(@"random = %f,spiderCount = %d,randomSpiderIndex = %d",rf,[spiderscount],randomSpiderIndex);

        CCSprite *spider = [spiders objectAtIndex:randomSpiderIndex]; // 根据随机数选取某只蜘蛛

        if([spider numberOfRunningActions] == 0)        // 判断这只蜘蛛是否在执行动作

        {

            [self runSpiderMoveSequence:spider];        // 如果这只蜘蛛没有动作,则让它执行动作

            break;                                      // 退出循环

        }

    }

}

 

#pragma mark 通过动作序列控制某个蜘蛛的运动

- (void)runSpiderMoveSequence:(CCSprite *)spider

{

    numSpidersMoved ++;             // 下落蜘蛛数加1

    if(numSpidersMoved %8 == 0 && spiderMoveDuration > 2.0f)

    // 每落下 8 个蜘蛛,spiderMove - Duration 就降低,从而增加所有蜘蛛的速度。

    {

        spiderMoveDuration -= 0.1f;

    }

    CGPoint belowScreenPosition = CGPointMake(spider.position.x

                                              , -[spider texture].contentSize.height); // 下落一个蜘蛛位置

    CCMoveTo *move = [CCMoveToactionWithDuration:spiderMoveDuration

                                          position:belowScreenPosition]; // 下落动作

    CCCallFuncN *call = [CCCallFuncNactionWithTarget:self

                                             selector:@selector(spiderDidDrop:)];

    CCSequence *sequence = [CCSequence actions:move,call,nil];  // 动作序列

    [spider runAction:sequence];    // 执行动作序列

}

 

- (void)spiderDidDrop:(id)sender

{

    NSAssert([sender isKindOfClass:[CCSpriteclass]],@"sender is not a CCSprite");

    CCSprite *spider = (CCSprite *)sender;

    CGPoint pos = spider.position;

    CGSize screenSize = [[CCDirectorsharedDirector] winSize];

    pos.y = screenSize.height + [spider texture].contentSize.height;

    spider.position = pos;

}

#pragma mark 碰撞测试

-(void) checkForCollision

{

    float playerImageSize = [player texture].contentSize.width;                 // 主角宽度

    float spiderImageSize = [[spiders lastObject] texture].contentSize.width;   // 蜘蛛宽度

    float playerCollisionRadius = playerImageSize * 0.4f;       // 主角半径

    float spiderCollisionRadius = spiderImageSize * 0.4f;       // 蜘蛛半径

    

    float maxCollisionDistance = playerCollisionRadius + spiderCollisionRadius;

    // 主角与蜘蛛之间的最大的安全距离

    

    int numSpiders = [spiders count];

    for (int i = 0; i < numSpiders; i++)

    {

        CCSprite* spider = [spidersobjectAtIndex:i];

        if ([spider numberOfRunningActions] == 0// 如果蜘蛛没有发生动作

        {

            continue;

        }

        

        float actualDistance = ccpDistance(player.position, spider.position); // 主角与蜘蛛之间的距离

        if (actualDistance < maxCollisionDistance)  // 如果主角与蜘蛛之间的距离小于安全距离,说明他们碰撞了

        {

            [self resetSpiders];

            totalTime = 0;

            score = 0;

            [scoreLabelsetString:@"0"];

            break;

        }

    }

}

 

CCLabelBMFont 简介 

CCLabelBMFont 的特色就是以占用更多内存为代价加快标签的更新,这与其他任何 CCSprite 类相似。 

原文地址:https://www.cnblogs.com/sell/p/2852767.html