SpriteKit项目——消灭怪兽、效果图及详细代码,

一、注意
1.新建项目并改为横屏运行
2.导入游戏素材
3.创建GameSence
4.添加忍者
5.隐藏状态栏,配置游戏场景大小

#pragma mark - 隐藏状态栏

- (BOOL)prefersStatusBarHidden

{

    return YES;

}

二、添加忍者

// 1. 设置背景颜色

self.backgroundColor = [SKColor colorWithWhite:1.0 alpha:1.0];

 

// 2. 创建忍者

SKSpriteNode *player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];

CGPoint location = CGPointMake(0, self.size.height / 2);

 

[player setPosition:location];

 

// 3. 添加到场景

[self addChild:player];

三、iOS中视图大小变化简述

•系统加载完成nib文件后,会立即给应用程序发送viewDidLoad消息。此时,该视图尚未被加载至视图的层次结构。因此此时的视图大小并不会根据设备的方向重新调整大小
•视图的frame是相对其父视图坐标空间的,对于根视图而言,父视图是UIWindow,UIWindow负责处理旋转并调整子视图的变化
•在横屏应用中,shouldAutorotate和supportedInterfaceOrientations方法会被多次调用,而视图的bounds大小变化为横屏的尺寸,发生在第一次调用viewWillLayoutSubviews时
 
四、配置游戏场景大小

 

{

    [super viewWillLayoutSubviews];

 

    // 1. 获取根视图

      SKView * skView = (SKView *)self.view;

    // 2. 判断场景是否已经创建

      if (!skView.scene) {

        // 2.1 配置SK视图

             skView.showsFPS = YES;

        skView.showsNodeCount = YES;

        // 2.2 创建并配置游戏场景

             SKScene * scene = [GameScene sceneWithSize:skView.bounds.size];

        // 2.3 展现游戏场景

        [skView presentScene:scene];

    }

}

 

五、忍者登场

CGPoint location = CGPointMake(player.size.width / 2,

self.size.height / 2);

 

六、添加妖怪

 

SKSpriteNode *monster = [SKSpriteNode spriteNodeWithImageNamed:@"monster"];

 

// 2. 计算怪物出现的位置

NSInteger maxY = self.size.height - monster.size.height;

NSInteger randomY = arc4random_uniform(maxY);

NSInteger monsterY = randomY + monster.size.height / 2;

NSInteger monsterX = self.size.width - monster.size.width / 2;

 

monster.position = CGPointMake(monsterX, monsterY);

 

// 3. 添加妖怪

[self addChild:monster];

 

// 4. 妖怪从右向左移动

CGFloat duration = arc4random_uniform(4) + 2.0;

CGPoint to = CGPointMake(-monster.size.width / 2, monsterY);

SKAction *move = [SKAction moveTo:to duration:duration];

SKAction *moveDone = [SKAction removeFromParent];

 

[monster runAction:[SKAction sequence:@[move, moveDone]]];

七、示意图

八、不断添加妖怪

// 4.1 添加一个妖怪的Action

SKAction *addMonster = [SKAction runBlock:^{

    [self addMonster];

}];

// 4.2 等待Action

SKAction *waitAction = [SKAction waitForDuration:1.0f];

// 4.3 系列Action

SKAction *seqence = [SKAction sequence:@[addMonster, waitAction]];

// 4.4 循环执行Action,不断添加妖怪

[self runAction:[SKAction repeatActionForever:seqence]];

 

九、滚滚不断地妖怪大军来啦~~~

 

十、发射飞镖示意图

 

十一、发射飞镖

 

CGPoint from = CGPointMake(_player.size.width + projectile.size.width / 2, self.size.height / 2);

CGPoint offset = CGPointMake(location.x - from.x, location.y - from.y);

// 仅允许向右侧发射

if (offset.x <= 0) return;

 

// 3. 计算目标点

CGFloat toX = projectile.size.width / 2.0 + self.size.width;

CGFloat toY = offset.y / offset.x * toX + from.y;

CGPoint to = CGPointMake(toX, toY);

 

// 4. 通过飞镖距离,计算飞行时间

CGPoint p = CGPointMake(to.x - from.x, to.y - from.y);

CGFloat distance = sqrtf(powf(p.x, 2.0) + powf(p.y, 2.0));

CGFloat volcity = self.size.width;

NSTimeInterval duration = distance / volcity;

 

十二、多点触摸支持

// 多点触摸支持

for (UITouch *touch in touches) {

    [self addProjectileAtPoint:[touch locationInNode:self]];

}

十三、消灭妖怪在场景更新方法中做碰撞检测

 

for (SKSpriteNode *projectile in _projectiles) {

    NSMutableSet *monsterToDelete = [NSMutableSet set];

    for (SKSpriteNode *monster in _monsters) {

        if (CGRectIntersectsRect(monster.frame, projectile.frame)) {

            [monsterToDelete addObject:monster];

        }

    }

    for (SKSpriteNode *monster in monsterToDelete) {

        [_monsters removeObject:monster];

 

        SKAction *rotate = [SKAction rotateToAngle:-M_PI_2 duration:0.1];

        [monster runAction:rotate completion:^{

            [monster removeFromParent];

        }];

    }

    if (monsterToDelete.count > 0) {

        [projectileToDelete addObject:projectile];

    }

}

 

十四、游戏结束处理

 

_killedMonster++;

if (_killedMonster > 10) {

    GameOverScene *gameOver = [[GameOverScene alloc] initWithSize:self.size won:YES];

    SKTransition *transition = [SKTransition doorsOpenHorizontalWithDuration:0.5f];

 

    [self.scene.view presentScene:gameOver transition:transition];

}

 

// 在用户触摸事件中遍历用户点击的节点

SKNode *node = [self nodeAtPoint:[touch locationInNode:self]];

 

if ([node.name isEqualToString:@"click"]) {

    GameScene *gameScene = [GameScene sceneWithSize:self.size];

    SKTransition *transition = [SKTransition doorsCloseHorizontalWithDuration:0.5f];

 

    [self.scene.view presentScene:gameScene transition:transition];

}

十五、碰撞检测(1——设置类别掩码,并设置物理世界

tic uint32_t projectileCategory = 1 << 0;

static uint32_t monsterCategory = 1 << 1;

 

// 1) 物理仿真世界的重力方向

self.physicsWorld.gravity = CGVectorMake(0, 0);

// 2) 仿真世界的关联代理

self.physicsWorld.contactDelegate = self;

十六、碰撞检测(2——设置妖怪的物理刚体属性

// 1.2 设置妖怪的物理刚体属性

// 1) 使用妖怪的尺寸创建一个矩形刚体

monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size];

// 2) 标示物体的移动是否由仿真引擎负责

monster.physicsBody.dynamic = YES;

// 3) 设置类别掩码

monster.physicsBody.categoryBitMask = monsterCategory;

// 4) 设置碰撞检测类别掩码

monster.physicsBody.contactTestBitMask = projectileCategory;

// 5) 设置回弹掩码

monster.physicsBody.collisionBitMask = 0;

十七、碰撞检测(3——设置飞镖的物理刚体属性

属性

// 1) 使用飞镖的尺寸创建一个圆形刚体

projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width / 2.0];

// 2) 标示物体的移动是否由仿真引擎负责

projectile.physicsBody.dynamic = YES;

// 3) 设置类别掩码

projectile.physicsBody.categoryBitMask = projectileCategory;

// 4) 设置碰撞检测类别掩码

projectile.physicsBody.contactTestBitMask = monsterCategory;

// 5) 设置回弹掩码

projectile.physicsBody.collisionBitMask = 0;

// 6) 设置精确的碰撞检测,避免出现“遂穿”

projectile.physicsBody.usesPreciseCollisionDetection = YES;

十八、碰撞检测——消灭妖怪

/ 1. 使用类别掩码判断发生碰撞的对象类别

SKPhysicsBody *projectileBody = nil;

SKPhysicsBody *monsterBody = nil;

 

if (contact.bodyA.categoryBitMask == projectileCategory) {

    projectileBody = contact.bodyA;

    monsterBody = contact.bodyB;

} else {

    projectileBody = contact.bodyB;

    monsterBody = contact.bodyA;

}

// 2. 从场景中移除飞镖

[projectileBody.node removeFromParent];

// 3. 从场景中移出妖怪

SKSpriteNode *monster = (SKSpriteNode *)monsterBody.node;

SKAction *rotate = [SKAction rotateToAngle:-M_PI_2 duration:0.1];

SKAction *rotateDone = [SKAction removeFromParent];

[monster runAction:[SKAction sequence:@[rotate, rotateDone]]];

十九、战斗开始啦~~

二十、添加声音

•[self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];

 

 

posted on 2013-12-21 12:14  林源  阅读(1140)  评论(0编辑  收藏  举报

导航