SpriteKit框架之浅谈节点碰撞的实现


前言


在游戏当中,碰撞是避免不了的,碰撞的实现主要有三种方法,一种是if语句,第二种是使用intersectsNode(),第三种是物理引擎,前两种方法麻烦繁琐,今天我就第三种基于物理引擎的碰撞来说一下.


生活中的碰撞


基于物理引擎的碰撞实现


基于物理引擎的碰撞实现主要是用SKPhysicsContactDelegate中的- (void)didBeginContact:(SKPhysicsContact *)contact;这个代理方法实现的.下面我们就看一下具体的实现过程.

  • 准备工作

我们首先要对场景的physicsWorld属性设置代理对象为场景自身.并且设置physicsWorld的重力加速度为(0,0).代码如下.

#import "GameScene.h"

@interface GameScene ()<SKPhysicsContactDelegate>

@end

@implementation GameScene

-(instancetype)initWithSize:(CGSize)size{
    
    if (self = [super initWithSize:size]) {
        
        self.backgroundColor = [SKColor whiteColor];
        
        //设置重力加速度
        self.physicsWorld.gravity = CGVectorMake(0, 0);
        
        self.physicsWorld.contactDelegate = self;
        
    }
    
    return self;
    
}

接着,我们设置背景以及被碰撞的飞机.代码如下.

-(void)didMoveToView:(SKView *)view{
    
    [super didMoveToView:view];
    
    [self backgroundNode];
    
    [self planeNode];
    
    
}

#pragma mark ----创建背景----

-(void)backgroundNode{
    
    SKSpriteNode *backgroundNode = [SKSpriteNode spriteNodeWithImageNamed:@"bg_02.jpg"];
    
    backgroundNode.position = CGPointZero;
    
    backgroundNode.zPosition = 0;
    
    backgroundNode.anchorPoint = CGPointZero;
    
    backgroundNode.size = self.size;
    
    [self addChild:backgroundNode];
    
    
    
}

#pragma mark ---- 创建飞船 ----

-(void)planeNode{
    
    SKSpriteNode *planeNode = [SKSpriteNode spriteNodeWithImageNamed:@"飞机.png"];
    
    planeNode.position = CGPointMake(self.size.width/2, self.size.height/2);
    
    planeNode.anchorPoint = CGPointMake(0.5, 0.5);
    
    planeNode.zPosition = 1;
    
    planeNode.name = @"plane";
    
    [self addChild:planeNode];

}

效果图如下所示.

接着我们在touchBegan中实现一个事件:每当我们点击一次屏幕的时候,被撞飞机的正上方就会出现一个飞机,这个飞机会往下飞行.整体代码如下.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    SKSpriteNode *enemyNode = [SKSpriteNode spriteNodeWithImageNamed:@"敌人1.png"];
    
    enemyNode.position = CGPointMake(self.size.width/2, self.size.height);
    
    enemyNode.anchorPoint = CGPointMake(0.5, 1);
    
    enemyNode.zPosition = 1;
    
    enemyNode.name = @"enemy";
    
    [self addChild:enemyNode];

    //添加动作
    [enemyNode runAction:[SKAction moveToY:0 duration:2]];
    
}

效果图如下.我们看到两者虽然经过,但是并不能发生碰撞,这是因为我们没有给他们设置物理体以及碰撞属性.

效果图
  • 碰撞实现

首先我们先给两个物体设置物理体及其属性,属性主要是categoryBitMask和contactTestBitMask,这两个属性分别是设置物理体的标识符和物理体可与哪一类的物理体发生碰撞.两者代码如下.

被撞飞机的物理体的设置

    planeNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:planeNode.size];
    
    //物理体是否受力
    planeNode.physicsBody.dynamic = YES;
    
    //设置物理体的标识符
    planeNode.physicsBody.categoryBitMask = 1;
    
    //设置可与哪一类的物理体发生碰撞
    planeNode.physicsBody.contactTestBitMask = 2;
    
    
    

敌机的物理体的设置

    enemyNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemyNode.size];
    
    //物理体是否受力
    enemyNode.physicsBody.dynamic = YES;
    
    //设置物理体的标识符
    enemyNode.physicsBody.categoryBitMask = 2;
    
    //设置可与哪一类的物理体发生碰撞
    enemyNode.physicsBody.contactTestBitMask = 1;
    

在说-(void)didBeginContact:(SKPhysicsContact *)contact之前,我们要说一下SKPhysicsContact对象,不多说,还是API文档,我们从文档中可以看出,SKPhysicsContact对象是包含着碰撞的两个物理体的,分别是bodyA和bodyB.我们可以通过bodyA和bodyB来获取到碰撞的节点,然后再进行下一步操作.

API文档中的SKPhysicsContact说明

接着我们就需要在-(void)didBeginContact:(SKPhysicsContact *)contact方法中实现碰撞事件,我们让两者碰撞之后,敌机让其消失,代码如下所示.

-(void)didBeginContact:(SKPhysicsContact *)contact{

    SKSpriteNode *planeNode;
    SKSpriteNode *enemyNode;

    if (contact.bodyA.categoryBitMask == 1 && contact.bodyB.categoryBitMask == 2) {
        
        planeNode = (SKSpriteNode *)[contact.bodyA node];
        
        enemyNode = (SKSpriteNode *)[contact.bodyB node];

        //去除敌机
        [enemyNode removeAllActions];
        [enemyNode removeFromParent];
        
    }else{
    
        planeNode = (SKSpriteNode *)[contact.bodyB node];
        
        enemyNode = (SKSpriteNode *)[contact.bodyA node];
        
        //去除敌机
        [enemyNode removeAllActions];
        [enemyNode removeFromParent];

    }

}



效果图如下所示.

效果图



基于物理引擎的简单碰撞就到这了.谢谢阅读本文章.最后废话不多说,直接上Demo
-->节点的碰撞Demo💾
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,845评论 18 139
  • 由于很多小伙伴要demo我就不一一发了,直接丢在github上自己下载吧:https://github.com/s...
    FKSky阅读 23,585评论 27 99
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,916评论 25 708
  • #字词 1.racket But I guess I must have made a pretty big ra...
    仲孙书琴阅读 531评论 0 0
  • 1.早上看到陈立发给我的微信:黄利霞,变了一一充满自信,阳光,纯洁,最重要的是你总在为别人着想,让人觉得温暖⋯祝福...
    彩霞满天q2阅读 202评论 0 0