cocos2d小游戏之躲便便(初学者)(二)

时间:2023-02-09 09:11:50

先看效果图:(必须在真机上)

源码地址:点击打开链接

cocos2d小游戏之躲便便(初学者)(二)

直接贴代码,所有注释和解释在代码里:

GameScene.h

#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface GameScene : CCLayer{
    CCSprite *player;           //玩家精灵
    CGPoint playerVelocity;     //速率
    
    CCArray *shits;             //所有便便集合
    float shitMoveDuration;     //便便之间距离
    int numShitsMoved;          //便便活动数量
    
    CCLabelTTF *scoreLabel;     //得分标签
    double totalTime;           //总时间
    int score;                  //成绩
    
    CCLabelBMFont *gameLabel;
    CCLabelTTF *taplabel;
}
+(id) scene;
@end

GameScene.m

#import "GameScene.h"
#import "SimpleAudioEngine.h"

@implementation GameScene
+(id)scene
{
    CCScene *scene = [CCScene node];
    CCLayer *layer = [GameScene node];
    [scene addChild:layer];
    return scene;
}
-(id)init
{
    if ((self = [super init])) {
        //创建背景音乐
        [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"background.mp3" loop:YES];
        CCLOG(@"%@,%@",NSStringFromSelector(_cmd),self);
        //设置加速器,并添加accelerometer方法
        [self setAccelerometerEnabled:YES];
        //触摸事件,调用ccTouchesEnded:(NSSet *)touches事件
        [self setTouchEnabled:YES];
        //初始化精灵
        player = [CCSprite spriteWithFile:@"Icon.png"];
        //添加精灵
        [self addChild:player z:0 tag:1];
        //屏幕大小
        CGSize screenSize = [[CCDirector sharedDirector] winSize];
        //精灵高度
        float imageHeight = [player texture].contentSize.height;
        //精度位置,position是精灵的中间坐标在哪里
        player.position = CGPointMake(screenSize.width/2, imageHeight/2);
        
        //成绩标签
        //scoreLabel = [CCLabelTTF labelWithString:@"0" fontName:@"Arial" fontSize:48];
        scoreLabel = [CCLabelBMFont labelWithString:@"0" fntFile:@"font01.fnt"];//位置显示
        //标签位置,屏幕中间顶部
        scoreLabel.position = CGPointMake(screenSize.width / 2, screenSize.height);
        //对于标签上对齐
        scoreLabel.anchorPoint = CGPointMake(0.5f, 1.0f);
        //添加成绩标签
        [self addChild:scoreLabel z:-1];
        
        //更新精灵的位置,每一帧都会调用方法update
        [self scheduleUpdate];
        //初始化所有便便
        [self initShits];
    }
    return self;
}
//加速器方法
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
//    CGPoint pos = player.position;
//    pos.x += acceleration.x * 10;
//    player.position = pos;
    //减速值
    float deceleration = 0.4f;
    //加速值灵敏度
    float sensitivity = 6.0f;
    //最大速度
    float maxVelocity = 100;
    //改变坐标位置
    playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
    //越界判断
    if (playerVelocity.x > maxVelocity) {
        playerVelocity.x = maxVelocity;
    }else if(playerVelocity.x < -maxVelocity)
    {
        playerVelocity.x = -maxVelocity;
    }
}
//每一帧更新玩家精灵位置
-(void)update:(ccTime)delta
{
    //精灵当前位置
    CGPoint pos = player.position;
    //加上速率
    pos.x += playerVelocity.x;
    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;
    }else if(pos.x > rightBorderLimit){
        pos.x = rightBorderLimit;
        playerVelocity = CGPointZero;
    }
    //改变精灵位置
    player.position = pos;
    
    //时间做为玩家的成绩
    totalTime += delta;
    int currentTime = (int)totalTime;
    if (score < currentTime) {
        score = currentTime;
        [scoreLabel setString:[NSString stringWithFormat:@"%i",score]];
    }
    
    //检测碰撞
    [self checkForCollision];
}
//初始化便便
-(void)initShits
{
    CGSize screenSize = [[CCDirector sharedDirector] winSize];
    CCSprite *tempShit = [CCSprite spriteWithFile:@"shit.png"];
    //便便的宽度
    float imageWidth = [tempShit texture].contentSize.width;
    //一屏能显示总共多少个便便
    int numShits = screenSize.width/imageWidth;
    shits = [[CCArray alloc] initWithCapacity:numShits];
    for (int i = 0; i < numShits; i++) {
        CCSprite *shit = [CCSprite spriteWithFile:@"shit.png"];
        [self addChild:shit z:0 tag:2];
        [shits addObject:shit];
        
    }
    //重新设置所有便便的位置
    [self resetShits];
}
//重新设置所有便便的位置
-(void)resetShits
{
    CGSize screentSize = [[CCDirector sharedDirector] winSize];
    CCSprite *tempShit = [shits lastObject];
    CGSize size = [tempShit texture].contentSize;
    int numShits = [shits count];
    for (int i = 0; i< numShits; i++) {
        CCSprite *shit = [shits objectAtIndex:i];
        shit.position = CGPointMake(size.width * i + size.width * 0.5f,screentSize.height + size.height);
        //停止所有动作
        [shit stopAllActions];
    }
    //更新停止
    [self unschedule:@selector(shitsUpdate:)];
    //每隔0.7秒运行一次shitsUpdate
    [self schedule:@selector(shitsUpdate:) interval:0.7f];
    numShitsMoved = 0;
    shitMoveDuration = 4.0f;
    
}
//隔0.7秒下落的便便
-(void)shitsUpdate:(ccTime)delta
{
    //为什么循环10次,因为,我不知道随机生成的索引值 对应的便便是不是活动的,所以要确认最终随机选 出的蜘蛛当前是空闲的,当然这个数字是做任意随机的,如果没有随机选出一个空闲的蜘蛛,就会 跳过这次更新,然后等待下一次。
    for (int i = 0; i < 10; i++) {
        int randomShiteIndex = CCRANDOM_0_1() * [shits count];
        CCSprite *shit = [shits objectAtIndex:randomShiteIndex];
        //某个便便是不是在活动
        if ([shit numberOfRunningActions] == 0) {
            //如果空闲,就使它运动
            [self runShitMoveSequence:shit];
            break;
        }
    }
}
//通过动作控制便便的运动
-(void)runShitMoveSequence:(CCSprite*)shit
{
    numShitsMoved++;
    //每落下八个就加速,加速是让便便之间的距离减少
    if (numShitsMoved % 8 == 0 && shitMoveDuration > 2.0f) {
        shitMoveDuration -= 0.1f;
        
    }
    //下降到的位置
    CGPoint belowScreenPosition = CGPointMake(shit.position.x, -[shit texture].contentSize.height);
    //动作
    CCMoveTo *move = [CCMoveTo actionWithDuration:shitMoveDuration position:belowScreenPosition];
    CCCallFuncN *callDidDrop = [CCCallFuncN actionWithTarget:self selector:@selector(shitDidDrop:)];
    //动作循环
    CCSequence *sequence = [CCSequence actions:move, callDidDrop, nil];
    [shit runAction:sequence];
}
//重设便便位置
-(void)shitDidDrop:(id)sender
{
    //保证sender参数属于正确的类
    NSAssert([sender isKindOfClass:[CCSprite class]], @"sender is not a CCSprite!");
    CCSprite *shit = (CCSprite*)sender;
    
    CGPoint pos = shit.position;
    CGSize screenSize = [[CCDirector sharedDirector] winSize];
    pos.y = screenSize.height + [shit texture].contentSize.height;
    //改变便便位置
    shit.position = pos;
    
}
//碰撞检测
-(void) checkForCollision
{
    //用精灵和便便的半径来判断是否碰撞
    float playerImageSize = [player texture].contentSize.width;
    float shitimageSize = [[shits lastObject] texture].contentSize.width;
    
    float playCollisionRadius = playerImageSize * 0.4f;
    float shitCollisionRadius = shitimageSize * 0.4f;
    //最大碰撞距离
    float maxCollisionDistance = playCollisionRadius + shitCollisionRadius;
    
    int numShits = [shits count];
    for (int i=0; i < numShits; i++) {
        CCSprite *shit = [shits objectAtIndex:i];
        if ([shit numberOfRunningActions] == 0) {
            continue;
        }
        //ccpDistance方法判断是否碰撞
        float actualDistance = ccpDistance(player.position, shit.position);
        if (actualDistance < maxCollisionDistance) {
            //Game over!!
            [[SimpleAudioEngine sharedEngine] playEffect:@"007.mp3"];
            //[self resetShits];
            [self gameOver];
            break;
        }
    }
}
-(void)gameOver
{
    //屏幕大小
    CGSize screentSize = [[CCDirector sharedDirector] winSize];
    CCSprite *tempShit = [shits lastObject];
    CGSize size = [tempShit texture].contentSize;
    int numShits = [shits count];
    for (int i = 0; i< numShits; i++) {
        CCSprite *shit = [shits objectAtIndex:i];
        shit.position = CGPointMake(size.width * i + size.width * 0.5f,screentSize.height + size.height);
        //停止所有动作
        [shit stopAllActions];
    }
    //更新停止
    //[self unschedule:@selector(shitsUpdate:)];
    [self unscheduleAllSelectors];

    gameLabel = [CCLabelBMFont labelWithString:@"GAME OVER!" fntFile:@"font01.fnt"];
    gameLabel.position = CGPointMake(screentSize.width / 2, screentSize.height / 2);
    
    [self addChild:gameLabel];
    taplabel = [CCLabelTTF labelWithString:@"tap screen to play again" fontName:@"Arial" fontSize:20];
    taplabel.position = CGPointMake(screentSize.width / 2, screentSize.height / 2 - [gameLabel texture].contentSize.height / 2);
    [self addChild:taplabel];
    
}
//点击事件
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (gameLabel != nil) {
        [self removeChild:gameLabel];
        [self removeChild:taplabel];
        taplabel = nil;
        gameLabel = nil;
        totalTime = 0.0f;
        [self scheduleUpdate];
[self resetShits]; }}
- (void)dealloc{
 CCLOG(@"%@,%@",NSStringFromSelector(_cmd),self); shits = nil;
 [super dealloc];
}@end