前言
在游戏当中,碰撞是避免不了的,碰撞的实现主要有三种方法,一种是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来获取到碰撞的节点,然后再进行下一步操作.
接着我们就需要在-(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