简体   繁体   English

触摸更改精灵图像

[英]Change sprite image on touch

I am making a game which purpose it is to catch multiple objects that are falling from the top of the screen. 我正在制作一个游戏,目的是捕获从屏幕顶部掉落的多个对象。 In the bottom there is a basket to catch the objects. 在底部有一个篮子来抓东西。 i managed to randomly spawn objects from the top dropping to the bottom using raywenderlich's tutorial : http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners 我设法使用raywenderlich的教程从顶部到底部随机生成对象: http ://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners

But what i want is that when i tap on that random object, the image of that object changes into another image , so just for imagination if the random objects are cats, after i tap them they have to become dogs, how do i have to program this? 但是我想要的是,当我点击该随机对象时,该对象的图像会更改为另一幅图像,所以如果想像一下,如果随机对象是猫,则在我点击它们之后必须将它们变成狗,我该怎么做?编程这个?

edit this is what i got so far : 编辑 这是我到目前为止所得到的:

#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

Each part of the skeleton model is a spritekit node. 骨架模型的每个部分都是一个spritekit节点。 Find the node that you wish to change and update its texture property like this: 找到您想要更改的节点并更新其纹理属性,如下所示:

spriteKitNode.texture = // Updated SKTexture spriteKitNode.texture = //更新了SKTexture

Once a touch is detected on a sprite (I assume you already got that working out) you can either create the sprite again with spriteNodeWithImageNamed . 一旦在sprite上检测到触摸(我假设您已经解决了),您可以使用spriteNodeWithImageNamed再次创建sprite。 Make sure you save the previous node's position and set it again on the new sprite so it will match the position of the old sprite. 确保保存前一个节点的位置,然后在新的精灵上再次设置它,使其与旧的精灵的位置匹配。

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

You can also set the texture with setTexture method which will not require you to change anything else (eg position) : 您也可以使用setTexture方法设置纹理,而无需更改其他任何内容(例如,位置):

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

EDIT : Answering your question in the comments you implement this in the touchesEnded method of the parent node of the sprites : 编辑:在注释中回答您的问题,您可以在sprites父节点的touchesEnded方法中实现此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"]];
       }
    }
}

Another approach (Haven't tried it yet) is to subclass SKSpriteNode and implement the same method but without the touch detection in rect since if this method is called the sprite has been touched . 另一种方法(尚未尝试过)是子类化SKSpriteNode并实现相同的方法,但是在rect中没有触摸检测,因为如果此方法称为sprite,则已经被触摸。

In your TouchesEnded event: 在您的TouchesEnded事件中:
Add a small skspritenode positioned at the touch location with a small physics body that last for a short duration. 在触摸位置添加一个小的skspritenode,并保留一个持续较短时间的小型物理实体。 ("touch spritenode) (“ touch spritenode”)

Set up contact between all possible transformed objects and the "touch spritenode" 在所有可能的转换对象和“ touch spritenode”之间建立联系

Create a subclass of SKSpritenode for the falling objects that has a variable to stores their type. 为下落的对象创建SKSpritenode的子类,该子类具有用于存储其类型的变量。

In the method called from contact between the touch spritenode and the falling objects: 在触摸精灵节点和下落物体之间的接触中调用的方法中:

  1. Remove the touchspritenode first 首先删除touchspritenode
  2. Create if statements to check which falling object was touched. 创建if语句以检查接触了哪个下降物体。
  3. Update the image of the contacted falling object spritenode according to its type. 根据其类型更新接触的下落物体spritenode的图像。

If you are following Raywenderlich you have access to the actual syntax 如果您遵循Raywenderlich,则可以访问实际语法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM