背景精灵图像一直在屏幕上居中

时间:2015-01-22 01:35:22

标签: objective-c background sprite-kit uigesturerecognizer

我试图在我当前的GameScene中实现可滚动的背景。这应该通过手势识别来完成,我已经将其用于Taps并移动其他场景对象。

与Google搜索返回的其他所有结果不同,我不想要无限滚动的背景。它只需要用手指移动,并保持在移动的位置。

问题: 我可以在我的场景中移动背景SKSpriteNode,但是当我再次尝试移动它时它会捕捉到中心并且你的滚动实际上变得无用。它不断重置。

这是我到目前为止移动我的精灵所得到的:

-(void)selectTouchedNode:(CGPoint)location
{
    SKSpriteNode *node = (SKSpriteNode *)[self nodeAtPoint:location];
    if ([self.selectedNode isEqual:node]){
        if (![self.selectedNode isEqual:self.background]){
           self.selectedNode = NULL;
        }
    }

    if ([node isKindOfClass:[SKLabelNode class]]){
        self.selectedNode = node.parent;
    } else {
        self.selectedNode = node;
    }
    NSLog(@"Node Selected: %@ | Position: %f, %f",node.name,node.position.x,node.position.y);

}

- (void)respondToPan:(UIPanGestureRecognizer *)recognizer {

    if (recognizer.state == UIGestureRecognizerStateBegan) {
        // Get Touch Location in the View
        CGPoint touchLocation = [recognizer locationInView:recognizer.view];
        // Convert that Touch Location
        touchLocation = [self convertPointFromView:touchLocation];
        // Select Node at said Location.
        [self selectTouchedNode:touchLocation];


    } else if (recognizer.state == UIGestureRecognizerStateChanged) {
        // Get the translation being performed on the sprite.
        CGPoint translation = [recognizer translationInView:recognizer.view];
        // Copy to another CGPoint
        translation = CGPointMake(translation.x, -translation.y);
        // Translate the currently selected object
        [self translateMotion:recognizer Translation:translation];
        // Reset translation to zero.
        [recognizer setTranslation:CGPointZero inView:recognizer.view];

    } else if (recognizer.state == UIGestureRecognizerStateEnded) {
        // Fetch Current Location in View
        CGPoint touchLocation = [recognizer locationInView:recognizer.view];
        // Convert to location in game.
        CGPoint correctLocation = [self convertPointFromView:touchLocation];

        // If the selected node is the background node
        if ([self.selectedNode isEqual:self.background]) {
            NSLog(@"Scrolling the background: Node is: %@",self.selectedNode.name);
            // Set up a scroll duration
            float scrollDuration = 0.2;
            // Get the new position based on what is allowed by the function
            CGPoint newPos = [self backgroundPanPos:correctLocation];

            NSLog(@"New Position: %f, %f",newPos.x,newPos.y);

            // Remove all Actions from the background
            [_selectedNode removeAllActions];
            // Move the background to the new position with defined duration.
            SKAction *moveTo = [SKAction moveTo:newPos duration:scrollDuration];
            // SetTimingMode for a smoother transition
            [moveTo setTimingMode:SKActionTimingEaseOut];
            // Run the action
            [_selectedNode runAction:moveTo];
        } else {
            // Otherwise, just put the damn node where the touch occured.
            self.selectedNode.position = correctLocation;
        }

        }
}

// NEW PLAN: Kill myself
- (void)translateMotion:(UIGestureRecognizer *)recognizer Translation:(CGPoint)translation {

    // Fetch Location being touched
    CGPoint touchLocation = [recognizer locationInView:recognizer.view];
    // Convert to place in View
    CGPoint location = [self convertPointFromView:touchLocation];
    // Set node to that location
    self.selectedNode.position = location;
}

- (CGPoint)backgroundPanPos:(CGPoint)newPos {
    // Create a new point based on the touched location
    CGPoint correctedPos = newPos;

    return correctedPos;
}

到目前为止我知道什么?

我已尝试在滚动之前,结束时以及再次启动时打印位置。

结果是背景 移动位置,一旦你再次尝试移动它,它就会从那些新的坐标开始,屏幕在中心上只有重新定位精灵。

支持插图:

MSPaint Diagram

1 个答案:

答案 0 :(得分:0)

我不确定我是否100%了解您所描述的情况,但我相信它可能与您的背景精灵节点的锚点有关。

在您的方法中:

- (void)translateMotion:(UIGestureRecognizer *)recognizer Translation:(CGPoint)translation

你有这条线:

self.selectedNode.position = location;

由于默认情况下背景精灵的定位点设置为其中心,因此无论何时移动新触摸,它都会将背景精灵的中心捕捉到手指的位置。

换句话说,background.sprite.position设置背景精灵 定位点 的坐标(默认情况下是精灵的中心) ,在这种情况下,无论何时设置新位置,它都会将中心移动到该位置。

在这种情况下,解决方案是将背景精灵的定位点移动到每次触摸的正下方,这样就可以改变背景相对于触摸开始的背景点的位置。 / p>

这有点难以解释,所以这里有一些示例代码向您展示:

1)使用Sprite Kit Game模板在Xcode中创建一个新项目

2)用以下内容替换GameScene.m的内容:

#import "GameScene.h"

@interface GameScene ()

@property (nonatomic, strong) SKSpriteNode *sprite;

@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */
    self.sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

    self.sprite.position = CGPointMake(CGRectGetMidX(self.frame),
                                   CGRectGetMidY(self.frame));

    [self addChild:self.sprite];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */
    UITouch *touch = [touches anyObject];

    CGPoint nodelocation = [touch locationInNode:self.sprite];
    //[self adjustAnchorPointForSprite:self.sprite toLocation:nodelocation];

    CGPoint location = [touch locationInNode:self];
    self.sprite.position = location;
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    self.sprite.position = location;
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

}

-(void)adjustAnchorPointForSprite:(SKSpriteNode *)sprite toLocation:(CGPoint)location {

    // Remember the sprite's current position
    CGPoint originalPosition = sprite.position;

    // Convert the coordinates of the passed-in location to be relative to the bottom left of the sprite (instead of its current anchor point)
    CGPoint adjustedNodeLocation = CGPointMake(sprite.anchorPoint.x * sprite.size.width + location.x, sprite.anchorPoint.y * sprite.size.height + location.y);

    // Move the anchor point of the sprite to match the passed-in location
    sprite.anchorPoint = CGPointMake(adjustedNodeLocation.x / self.sprite.size.width, adjustedNodeLocation.y / self.sprite.size.height);

    //  Undo any change of position caused by moving the anchor point
    self.sprite.position = CGPointMake(sprite.position.x - (sprite.position.x - originalPosition.x), sprite.position.y - (sprite.position.y - originalPosition.y));
}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
}

@end  

3)在模拟器或设备上运行项目,然后单击/触摸太空船的顶端并开始拖动。

4)请注意,宇宙飞船将其中心点捕捉到您的触控位置。如果您将其拖动并释放到新位置,然后再次触摸屏幕,则会将其中心按回到您的手指。

5)现在取消注释:

[self adjustAnchorPointForSprite:self.sprite toLocation:nodelocation];

再次运行该项目。

6)看看你现在如何将船拖到你想要的地方,当你稍后触摸它时,它会保持原位,并从你触摸它的点开始跟随你的手指。这是因为每次新的触摸开始时,锚点现在都被调整到触摸下的点。

希望这能为您提供一个可以在游戏中使用的解决方案。