Изменение изображения спрайта при касании

Я делаю игру, целью которой является поймать несколько объектов, падающих с верхней части экрана. Внизу есть корзина для ловли предметов. мне удалось случайным образом создавать объекты сверху вниз, используя учебник raywenderlich: http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners

Но что я хочу, так это то, что когда я нажимаю на этот случайный объект, изображение этого объекта меняется на другое изображение, так что просто для воображения, если случайными объектами являются кошки, после того, как я нажму на них, они должны стать собаками, как я должен запрограммировать это?

редактировать вот что у меня получилось:

#import "MyScene.h"

static NSString* basketCategoryName = @"basket";
static NSString* monsterCategoryName= @"monster";
static const uint32_t projectileCategory     =  0x1 << 0;
static const uint32_t monsterCategory        =  0x1 << 1;





@interface MyScene() <SKPhysicsContactDelegate>
    @property (nonatomic) SKLabelNode * scoreLabelNode;
    @property int score;
    @property (nonatomic) SKSpriteNode * basket;
    @property (nonatomic) SKSpriteNode * monster;

    @property (nonatomic) BOOL isFingerOnBasket;
    @property (nonatomic) BOOL isFingerOnMonster;

    @property (nonatomic) BOOL isTouching;
    @property (nonatomic) NSTimeInterval lastSpawnTimeInterval;
    @property (nonatomic) NSTimeInterval lastUpdateTimeInterval;

    //@property (nonatomic, strong) SKSpriteNode *selectedNode;

@end

@implementation MyScene

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {

        // Initialize label and create a label which holds the score
        _score = 0;
        _scoreLabelNode = [SKLabelNode labelNodeWithFontNamed:@"MarkerFelt-Wide"];
        _scoreLabelNode.position = CGPointMake( CGRectGetMidX( self.frame ), 3 * self.frame.size.height / 4 );
        _scoreLabelNode.zPosition = 100;
        _scoreLabelNode.text = [NSString stringWithFormat:@"%d", _score];
        [self addChild:_scoreLabelNode];

        // Set the background
        SKTexture* groundTexture = [SKTexture textureWithImageNamed:@"AcornFlipTestBackground1136x640.png"];
        groundTexture.filteringMode = SKTextureFilteringNearest;

        for( int i = 0; i < 2 + self.frame.size.width / ( groundTexture.size.width * 2 ); ++i ) {
            SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithTexture:groundTexture];
            [sprite setScale:1.0];
            sprite.size = CGSizeMake(self.frame.size.width,self.frame.size.height);
            sprite.position = CGPointMake(CGRectGetMidX(self.frame),
                                          CGRectGetMidY(self.frame));
            [self addChild:sprite];
        }

        // Make grafity for sprite
        self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
        self.physicsWorld.contactDelegate = self;
        // Make catching object sprite
        self.basket = [SKSpriteNode spriteNodeWithImageNamed:@"bedTest.png"];
        self.basket.position = CGPointMake(CGRectGetMidX(self.frame), _basket.frame.size.height * 0.5f);
        self.basket.name = basketCategoryName;
        [self addChild:self.basket];

        // For default this is set to no until user touches the basket and the game begins.
        self.isTouching = NO;


        }
    return self;
}

-(void)addAcorn{
    if(_isTouching == YES) {

        self.monster= [SKSpriteNode spriteNodeWithImageNamed:@"AcornFinal.png"];

     // Determine where to spawn the monster along the X axis
        int minX = self.monster.size.width;
        int maxX = self.frame.size.width - self.monster.size.width;
        int rangeX = maxX - minX;
        int actualX = (arc4random() % rangeX)+minX;


        // Random position along the X axis as calculated above
        // This describe from which way the acorns move
        // - means moving from top to the right and + means moving from the top to the left
        self.monster.position = CGPointMake(actualX ,self.frame.size.height+ self.monster.size.height);
        self.monster.name = monsterCategoryName;
        [self addChild:self.monster];

        CGSize contactSize = CGSizeMake(self.monster.size.width - 5.0, self.monster.size.height - 10.0);
        self.monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:contactSize]; // 1
        self.monster.physicsBody.dynamic = YES; // 2
        self.monster.physicsBody.categoryBitMask = monsterCategory; // 3
        self.monster.physicsBody.contactTestBitMask = projectileCategory; // 4
        self.monster.physicsBody.collisionBitMask = 0; // 5

        // Determine speed of the monster
        int minDuration = 8.0;
        int maxDuration = 10.0;
        int rangeDuration = maxDuration - minDuration;
        int actualDuration = (arc4random() % rangeDuration) + minDuration;


        // Create the actions
        SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX,-self.monster.size.height) duration:actualDuration];
        SKAction * actionMoveDone = [SKAction removeFromParent];
        [self.monster runAction:[SKAction sequence:@[actionMove, actionMoveDone]]];


    }
}

- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {

    self.lastSpawnTimeInterval += timeSinceLast;
    if (self.lastSpawnTimeInterval > 0.5) {
        self.lastSpawnTimeInterval = 0;
        [self addAcorn];

    }
}

- (void)update:(NSTimeInterval)currentTime {
    // Handle time delta.
    // If we drop below 60fps, we still want everything to move the same distance.
    CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
    self.lastUpdateTimeInterval = currentTime;
    if (timeSinceLast > 1) { // more than a second since last update
        timeSinceLast = 1.0 / 60.0;
        self.lastUpdateTimeInterval = currentTime;
    }

    [self updateWithTimeSinceLastUpdate:timeSinceLast];

}

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    self.isTouching = YES;

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode* body = [self nodeAtPoint:location];

    if ([body.name isEqualToString:basketCategoryName])
    {
        NSLog(@"Began touch on basket");
        self.isFingerOnBasket = YES;
    }

    else if ([body.name isEqualToString:monsterCategoryName])
    {
        NSLog(@"Began touch on MONSTER");
        self.isFingerOnMonster = YES;


    }
}


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

    if (self.isFingerOnMonster) {

        // 2 Get touch location
        UITouch* touch = [touches anyObject];
        CGPoint location = [touch locationInNode:self];
        CGPoint previousLocation = [touch previousLocationInNode:self];

        // 3 Get node for paddle
        SKSpriteNode* monster = (SKSpriteNode*)[self childNodeWithName: monsterCategoryName];

        int oldPosition = monster.position.x + (location.x - previousLocation.x);
        self.monster = [SKSpriteNode spriteNodeWithImageNamed:@"AcornFinal.png"];
        monster.position = CGPointMake(oldPosition, monster.position.y);
        NSLog(@"reached the touch though");


    }





    // 1 Check whether user tapped paddle
    if (self.isFingerOnBasket) {

        // 2 Get touch location
        UITouch* touch = [touches anyObject];
        CGPoint location = [touch locationInNode:self];
        CGPoint previousLocation = [touch previousLocationInNode:self];

        // 3 Get node for paddle
        SKSpriteNode* basket = (SKSpriteNode*)[self childNodeWithName: basketCategoryName];

        // 4 Calculate new position along x for paddle
        int basketX = basket.position.x + (location.x - previousLocation.x);

        // 5 Limit x so that the paddle will not leave the screen to left or right
        basketX = MAX(basketX, basket.size.width/2);
        basketX = MIN(basketX, self.size.width - basket.size.width/2);
        // 6 Update position of paddle
        basket.position = CGPointMake(basketX, basket.position.y);
        CGSize contactSize = CGSizeMake(basket.size.width - 8.0, basket.size.height - 8.0);
        basket.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:contactSize];
        basket.physicsBody.dynamic = YES;
        basket.physicsBody.categoryBitMask = projectileCategory;
        basket.physicsBody.contactTestBitMask = monsterCategory;
        basket.physicsBody.collisionBitMask = 0;
        basket.physicsBody.usesPreciseCollisionDetection = YES;
    }


}

- (void)projectile:(SKSpriteNode *)basket didCollideWithMonster:(SKSpriteNode *)monster {
    NSLog(@"Hit");
    [monster removeFromParent];


}

- (void)didBeginContact:(SKPhysicsContact *)contact
{
    // 1
    SKPhysicsBody *firstBody, *secondBody;

    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
    {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    }
    else
    {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }

    // 2
    if ((firstBody.categoryBitMask & projectileCategory) != 0 &&
        (secondBody.categoryBitMask & monsterCategory) != 0)

    {
        [self projectile:(SKSpriteNode *) firstBody.node didCollideWithMonster:(SKSpriteNode *) secondBody.node];
        NSLog(@"test");
        _score++;
        _scoreLabelNode.text = [NSString stringWithFormat:@"%d", _score];
    }


}


// Removing this void will result in being able to drag the basket accross the screen without touching the basket itself.
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
    self.isFingerOnBasket = NO;
    self.isFingerOnMonster = NO;


}




@end

person Romano Vacca    schedule 18.06.2014    source источник


Ответы (3)


Как только прикосновение к спрайту обнаружено (я полагаю, вы уже разобрались с этим), вы можете снова создать спрайт с помощью spriteNodeWithImageNamed. Убедитесь, что вы сохранили положение предыдущего узла и снова установили его для нового спрайта, чтобы оно соответствовало положению старого спрайта.

CGPoint oldPosition = touchedSprite.position;
touchedSprite = [SKSpritNode spriteWithImageNamed:@"imgge.png"];
touchedSprite.position = oldPosition;
// If you have any other sprite properties you will have to save them as well

Вы также можете установить текстуру с помощью метода setTexture, который не потребует от вас каких-либо изменений (например, положение):

[touchedSprite setTexture:[SKTexture textureWithImageNamed:@"image.png"]];

EDIT: Отвечая на ваш вопрос в комментариях, вы реализуете это в методе touchesEnded родительского узла спрайтов:

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {    
    UITouch *touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInNode:self];

    for (SKSpriteNode *sprite in fallingSprites) { // Assuming fallingSprite is an array containing the cat sprites you want to detect touches for
       if (CGRectContainsPoint(sprite.frame, touchLocation)) {
           [sprite setTexture:[SKTexture textureWithImageNamed:@"dog.png"]];
       }
    }
}

Другой подход (еще не пробовал) состоит в том, чтобы создать подкласс SKSpriteNode и реализовать тот же метод, но без обнаружения касания в прямоугольнике, поскольку, если этот метод вызывается, спрайт был затронут.

person giorashc    schedule 18.06.2014
comment
Как вы можете видеть в моем отредактированном первом вопросе, у меня не было способа обнаружить падающие спрайты, поэтому я реализовал это. Теперь я реализовал это в моих прикосновениях, а также попытался реализовать первый ответ в моем прикосновении, чтобы изменить изображения, точно так же, как я изменил свою ракетку. я сделал это так: i58.tinypic.com/a5dthl.png Но это не работает - person Romano Vacca; 19.06.2014
comment
У меня проблема с открытием этого из моего офиса. Можете пояснить, что не работает? - person giorashc; 19.06.2014
comment
см. редактирование моего вопроса. Я реализовал обнаружение касания для падающих спрайтов, используя BOOL isfingeronMonster, а затем, когда я коснулся его в касаниях, я установил для него значение «да». Затем в TouchesMoved под if (isfingerongMonster) я пробовал. Я понимаю, что NSLog достиг касания, но ничего не происходит - person Romano Vacca; 19.06.2014
comment
@RomanoVacca Вы забыли добавить вновь созданный спрайт в свою сцену (а также удалить старый с помощью ([monster removeFromParent] и удалить его ПЕРЕД созданием нового спрайта, иначе вы потеряете ссылку на старый спрайт монстра) - person giorashc; 20.06.2014

Каждая часть модели скелета является узлом набора спрайтов. Найдите узел, который вы хотите изменить, и обновите его свойство текстуры следующим образом:

spriteKitNode.texture = // Обновлена ​​SKTexture

person Zoltan Varadi    schedule 18.06.2014

В событии TouchesEnded:
добавьте небольшой skspritenode, расположенный в месте касания, с небольшим физическим телом, которое существует в течение короткого времени. ("коснитесь спрайтенода")

Настройте контакт между всеми возможными трансформируемыми объектами и «сенсорным спрайтенодом».

Создайте подкласс SKSpritenode для падающих объектов, у которого есть переменная для хранения их типа.

В методе, вызываемом при контакте сенсорного спрайтенода с падающими объектами:

  1. Сначала удалите touchspritenode
  2. Создайте операторы if, чтобы проверить, какой падающий объект был затронут.
  3. Обновите изображение спрайтенода падающего объекта, с которым контактировали, в соответствии с его типом.

Если вы следуете Raywenderlich, у вас есть доступ к фактическому синтаксису

person meisenman    schedule 18.06.2014