如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?
Posted
技术标签:
【中文标题】如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?【英文标题】:How can I stop walking of a man if there is a wall in Sprite Kit? 【发布时间】:2013-11-27 12:38:15 【问题描述】:我正在 ios 7 中使用 Sprite Kit 练习。
现在我遇到了一个问题,当一个人通过 SKAction moveTo
从一个点走到另一个点时。
如果画面中有墙,我想在墙前停下脚步。
我使用了 skscen.h 文件中的代码,如下所示:
typedef NS_ENUM(uint32_t, CollisionType)
CollisionTypePlayer = 0x1 << 0,
CollisionTypeWall = 0x1 << 1,
CollisionTypeRiver = 0x1 << 3,
CollisionTypeBush = 0x1 << 4
;
#import <SpriteKit/SpriteKit.h>
@interface THMyScene : SKScene <SKPhysicsContactDelegate>
@property (nonatomic) SKSpriteNode *manContainer;
//Wall sprite
@property (nonatomic) SKSpriteNode *wallNode1;
@end
在下面给出的scene.m文件中:
#import "THMyScene.h"
@interface THMyScene()
@property (nonatomic) SKTextureAtlas *manAtlas;
@property (nonatomic) NSMutableArray *manImagesArray;
@end
@implementation THMyScene
-(id)initWithSize:(CGSize)size
if (self = [super initWithSize:size])
/* Setup your scene here */
// Configure physics for the world.
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f); // no gravity
self.physicsWorld.contactDelegate = self;
[self createWall];
[self createMan];
return self;
-(void) createMan
_manAtlas = [SKTextureAtlas atlasNamed:@"secondLevelMan"];
_manImagesArray = [[NSMutableArray alloc]init];
for(int i = 1; i <= _manAtlas.textureNames.count ; i++)
NSString *imageName = [NSString stringWithFormat:@"man%d.png",i];
SKTexture *tmpTexture = [SKTexture textureWithImageNamed:imageName];
[_manImagesArray addObject:tmpTexture];
_manContainer = [SKSpriteNode spriteNodeWithTexture:[_manImagesArray objectAtIndex:0]];
_manContainer.position = CGPointMake(50, 250);
[self addChild:_manContainer];
_manContainer.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_manContainer.size];
_manContainer.physicsBody.allowsRotation = YES;
_manContainer.physicsBody.dynamic = YES;
_manContainer.physicsBody.usesPreciseCollisionDetection = YES;
_manContainer.physicsBody.categoryBitMask = CollisionTypePlayer;
_manContainer.physicsBody.contactTestBitMask = CollisionTypeWall;
_manContainer.physicsBody.collisionBitMask = CollisionTypeRiver;
-(void) createWall
//Create wall 1
_wallNode1 = [SKSpriteNode spriteNodeWithImageNamed:@"rock-1"];
_wallNode1.name = @"stonewall";
_wallNode1.position = CGPointMake(400 , 700);
[self addChild:_wallNode1];
_wallNode1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_wallNode1.size];
_wallNode1.physicsBody.dynamic = NO;
_wallNode1.physicsBody.categoryBitMask = CollisionTypeWall;
_wallNode1.physicsBody.contactTestBitMask = 0;
_wallNode1.physicsBody.collisionBitMask = CollisionTypePlayer;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint locationTouch = [touch locationInNode:self];
CGPoint manLocation = _manContainer.position;
CGFloat rotatingAngle = [self pointPairToBearingDegrees:manLocation secondPoint:locationTouch];
CGFloat distance = [self distanceBetweenTwoPoints:manLocation andSecondpoint:locationTouch];
SKAction *animationAction = [SKAction repeatActionForever:[SKAction animateWithTextures:_manImagesArray timePerFrame: 0.0833]];
float duration = distance / 300;
SKAction *movePoint = [SKAction moveTo:locationTouch duration:duration];
SKAction *rotate = [SKAction rotateToAngle:rotatingAngle duration:0.0f];
SKAction *sequenceAction = [SKAction sequence:@[rotate, movePoint]];
[_manContainer runAction:[SKAction group:@[sequenceAction, animationAction]] withKey:@"runAnimation"];
- (CGFloat) pointPairToBearingDegrees:(CGPoint)startingPoint secondPoint:(CGPoint) endingPoint
CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
return bearingRadians;
-(CGFloat)distanceBetweenTwoPoints:(CGPoint)firstPoint andSecondpoint:(CGPoint)secondPoint
CGFloat dx = secondPoint.x - firstPoint.x;
CGFloat dy = secondPoint.y - firstPoint.y;
return sqrt(dx*dx + dy*dy );
- (void) didBeginContact:(SKPhysicsContact *)contact
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
firstBody = contact.bodyA;
secondBody = contact.bodyB;
else
firstBody = contact.bodyB;
secondBody = contact.bodyA;
@end
【问题讨论】:
使用物理时不要使用移动动作,而是改变身体速度或施加力 那么在上面给出的示例中我应该在哪里更改我的代码? 【参考方案1】:试试这样的:
-(void)update:(CFTimeInterval)currentTime
int distance = 10; // distance to wall when to stop
if ((man.position.x > wall.position.x + wall.size.width/2 + distance) &&
(man.position.x < wall.position.x - wall.size.width/2 - distance)
if ((man.position.y > wall.position.y + wall.size.height/2 + distance) &&
(man.position.y < wall.position.y - wall.size.height/2 - distance)
//do what you want like remove some or all actions of man
【讨论】:
【参考方案2】://改变你的代码这样就可以了
- (void) didBeginContact:(SKPhysicsContact *)contact
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
firstBody = contact.bodyA;
secondBody = contact.bodyB;
[firstBody.node removeAllActions];
firstBody.node.speed=0;
else
firstBody = contact.bodyB;
secondBody = contact.bodyA;
[secondBody.node removeAllActions];
secondBody.node.speed=0;
// 记住 spritekit 中的每个节点都有 speed 属性来控制精灵动画的速度
【讨论】:
以上是关于如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?的主要内容,如果未能解决你的问题,请参考以下文章