理解 SpriteKit:移动精灵
Posted
技术标签:
【中文标题】理解 SpriteKit:移动精灵【英文标题】:Understanding SpriteKit : Moving Sprites 【发布时间】:2013-10-10 01:07:55 【问题描述】:这是我的第一篇文章,我正在尝试使用 Apple 的 SpriteKit
框架。
我相信我对如何使用框架移动精灵有误解。我有一个简单的例子,我想在一个简单的UP
、DOWN
、LEFT
、RIGHT
方向上移动一个hero
,基于点击位置,相对于“英雄”位置。一旦英雄击中block
,“英雄”就会停止。
出于测试目的,我只是试图点击上方的“英雄”撞到屏幕顶部的块墙。然后在碰撞发生后,点击下方的“英雄”。我期待着“英雄”朝着最下面一排的积木墙移动;然而,似乎“英雄”继续向上移动并穿过顶墙。我确信我正在犯一个根本性的缺陷,我将不胜感激。
谢谢
这是我写的示例场景:
static inline CGPoint CGPointSubtract(const CGPoint a, const CGPoint b)
return CGPointMake(a.x - b.x, a.y - b.y);
typedef enum DIRECTION_e
UP,
DOWN,
LEFT,
RIGHT
DIRECTION_t;
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory)
PhysicsCategoryBlock = 1 << 0,
PhysicsCategoryHero = 1 << 1
;
@interface LevelScene ()
@property (nonatomic) SKSpriteNode * hero;
@property (nonatomic) BOOL inMotion;
@end
@implementation LevelScene
-(id) initWithSize:(CGSize)size
if (self = [super initWithSize:size])
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
[self createLevel];
[self createHero];
self.inMotion = NO;
return self;
- (void) createHero
[self addHeroAtRow:5 column:2];
- (void) createLevel
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addBlockAtRow:1 column:1];
[self addBlockAtRow:1 column:2];
[self addBlockAtRow:1 column:3];
[self addBlockAtRow:10 column:1];
[self addBlockAtRow:10 column:2];
[self addBlockAtRow:10 column:3];
- (void) addBlockAtRow:(NSInteger)row column:(NSInteger)column
SKSpriteNode *block = [[SKSpriteNode alloc] initWithColor:[SKColor brownColor] size:CGSizeMake(64,64)];
block.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
block.name = @"block";
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size];
block.physicsBody.dynamic = NO;
block.physicsBody.categoryBitMask = PhysicsCategoryBlock;
block.physicsBody.collisionBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
block.physicsBody.contactTestBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
[self addChild:block];
- (void) addHeroAtRow:(NSInteger)row column:(NSInteger)column
self.hero = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(64,64)];
self.hero.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
self.hero.name = @"hero";
self.hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.hero.size.width/2, self.hero.size.height/2)];
self.hero.physicsBody.usesPreciseCollisionDetection = YES;
self.hero.physicsBody.dynamic = YES;
self.hero.physicsBody.categoryBitMask = PhysicsCategoryHero;
self.hero.physicsBody.collisionBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
self.hero.physicsBody.contactTestBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
[self addChild:self.hero];
NSLog(@"ADDING HERO: %f, %f", self.hero.position.x, self.hero.position.y);
- (void)didBeginContact:(SKPhysicsContact *)contact
if (contact.bodyA.categoryBitMask == PhysicsCategoryBlock && contact.bodyB.categoryBitMask == PhysicsCategoryHero)
[self.hero removeAllActions];
self.hero.position = contact.bodyB.node.position;
NSLog(@"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
else if (contact.bodyB.categoryBitMask == PhysicsCategoryBlock && contact.bodyA.categoryBitMask == PhysicsCategoryHero)
[self.hero removeAllActions];
self.hero.position = contact.bodyA.node.position;
NSLog(@"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
- (void) moveHeroTowardDirection:(DIRECTION_t)direction
CGPoint location;
switch (direction)
case UP:
location = CGPointMake(self.hero.position.x, self.hero.position.y + 600);
break;
case DOWN:
location = CGPointMake(self.hero.position.x, self.hero.position.y + -600);
break;
case LEFT:
location = CGPointMake(self.hero.position.x + -600, self.hero.position.y);
break;
case RIGHT:
location = CGPointMake(self.hero.position.x + 600, self.hero.position.y);
break;
default: return;
NSLog(@"MOVE POSITION: %f, %f", location.x, location.y);
SKAction *action = [SKAction moveTo:location duration:10];
[self.hero runAction:action];
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
if (self.inMotion)
return;
self.inMotion = YES;
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
CGPoint diff = CGPointSubtract(self.hero.position, touchLocation);
NSLog(@"TOUCH POSITION: %f, %f", touchLocation.x, touchLocation.y);
NSLog(@"HERO POSITION: %f, %f", self.hero.position.x, self.hero.position.y);
NSLog(@"DIFF POSITION: %f, %f", diff.x, diff.y);
//
// Magnitude to find out which direction is dominate
//
if (abs(diff.x) > abs(diff.y))
if (touchLocation.x > self.hero.position.x)
NSLog(@"LEFT");
[self moveHeroTowardDirection:LEFT];
else
NSLog(@"RIGHT");
[self moveHeroTowardDirection:RIGHT];
else
if (touchLocation.y < self.hero.position.y)
NSLog(@"UP");
[self moveHeroTowardDirection:UP];
else
NSLog(@"DOWN");
[self moveHeroTowardDirection:DOWN];
@end
【问题讨论】:
这将有助于***.com/questions/19172140/skaction-move-forward/… @Smick 太棒了。谢谢 @Smick 我想感谢您的回答。最好的方法是什么?对不起,我是新来的。 【参考方案1】:这里试试这个,你也需要删除/禁用你的触摸结束
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
for (UITouch *touch in touches)
for (UITouch *touch in touches)
CGPoint location = [touch locationInNode:self];
CGPoint diff = CGPointMake(location.x - self.hero.position.x, location.y - self.hero.position.y);
CGFloat angleRadians = atan2f(diff.y, diff.x);
[self.hero runAction:[SKAction sequence:@[
[SKAction rotateToAngle:angleRadians duration:1.0],
[SKAction moveByX:diff.x y:diff.y duration:3.0]
]]];
【讨论】:
以上是关于理解 SpriteKit:移动精灵的主要内容,如果未能解决你的问题,请参考以下文章
使用 SKY SpriteKit 和 Swift 4 移动和旋转精灵
使用 SpriteKit 如何以随机但一致的速度将精灵节点移动到一个点