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

推荐阅读更多精彩内容

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