Obj-C 和 SpriteKit - 更改随机创建的精灵值

Obj-C and SpriteKit - Changing a sprite value that is created randomly

我正在使用 SpriteKit 和 Objective-C 制作游戏。

我有四种不同的纹理滴(蓝色、绿色、橙色和红色)随机落在屏幕上。

在我的 ANBDropNode class 我有这个方法:

+(instancetype)dropOfType:(ANBDropType)type {

    ANBDropsNode *drop;

    if (type == ANBDropTypeBlue) {
        drop = [self spriteNodeWithImageNamed:@"bluedrop"];
    } else if (type == ANBDropTypeGreen) {
        drop = [self spriteNodeWithImageNamed:@"greendrop"];
    } else if (type == ANBDropTypeOrange) {
        drop = [self spriteNodeWithImageNamed:@"orangedrop"];
    } else if (type == ANBDropTypeRed){
        drop = [self spriteNodeWithImageNamed:@"reddrop"];
    }

    [drop setupPhysicsBody];
    return drop;
}

在我的 GamePlayScene 中这两个:

    -(void)addDrops {

        NSUInteger randomDrop = [ANBUtil randomWithMin:0 max:4];

        self.drop = [ANBDropsNode dropOfType:randomDrop];

        float y = self.frame.size.height + self.drop.size.height;
        float x = [ANBUtil randomWithMin:10 + self.drop.size.width
                                     max:self.frame.size.width - self.drop.size.width - 10];
        self.drop.position = CGPointMake(x, y);

        [self addChild:self.drop];
    }

    -(void)update:(NSTimeInterval)currentTime {

        if (self.lastUpdateTimeInterval) {
            self.timeSinceDropAdded += currentTime - self.lastUpdateTimeInterval;
        }

        if (self.timeSinceDropAdded > 1) {
            [self addDrops];
            self.timeSinceDropAdded = 0;
        }

        self.lastUpdateTimeInterval = currentTime;

}

问题是(我知道这听起来可能有点笨):在水滴落到地面之前它已经改变了它的值。例如,如果 ANBDropNode *drop 是蓝水滴,则在它落地之前,该方法会随机创建另一个水滴并将其值更改为绿水滴。但我不想要这种行为。我希望下降继续保持其值直到它到达地面,这样我就可以在我的 didBeginContact 方法中检测它的颜色。

您可以简单地将 属性 与 ANBDropsNode class 相关联,这可以在实例化 drop 时设置。

在ANBDropsNode.h文件中,

@interface ANBDropsNode

@property (strong, nonatomic) NSString *dropColor; //This property will hold the value associated with the color.

然后在dropOfTypeclass方法中:

+(instancetype)dropOfType:(ANBDropType)type {

    NSString *strDropColor;

    if (type == ANBDropTypeBlue) {
        strDropColor = @"bluedrop";
    } else if (type == ANBDropTypeGreen) {
        strDropColor = @"greendrop";
    } else if (type == ANBDropTypeOrange) {
        strDropColor = @"orangedrop";
    } else if (type == ANBDropTypeRed){
        strDropColor = @"reddrop";
    }

    ANBDropsNode *drop = [self spriteNodeWithImageNamed:strDropColor];
    drop.dropColor = strDropColor;

    [drop setupPhysicsBody];
    return drop;
}

现在,在您的碰撞检测委托方法中,您可以通过简单地引用 dropColor 属性.

来找出节点的颜色

对于任何英语错误,我深表歉意,因为我的母语不是英语。

根据你的问题,我了解到你保留对坠落 (self.drop) 的引用的原因是为了检查它落地时的颜色。
所以你可以删除它,每次都创建一个新的 SKSpriteNode 对象,而不是仅仅更改当前 属性.
的引用 如果您有任何其他原因要保留对该掉落的引用,请继续保留引用。
请注意,执行上述任何操作都不会影响下面的代码。

我认为你的方向是正确的(当询问 [​​=13=] 时)但是错误的 approach/mindset,因为在使用 didBeginContact 时不需要保留参考,因为您可以通过此方法获取联系的节点。

无论如何,这是代码+解释

// MyScene.m  

// First, conform to SKPhysicsContactDelegate, so you can get didBeginContact 'calls'
@interface MyScene () <SKPhysicsContactDelegate>  
@end  

@implementation MyScene  

// Now add the following constant, that you'll use as the physics body category bit masks  
static const uint32_t groundCategory = 0x01 << 0;  
static const uint32_t dropsCategory  = 0x01 << 1;  

// Somewhere in your initialisation, set yourself to be the physicsWorld  
// contact delegate, so you'll receive the didBeginContact 'calls',  
// And also call setupGround method, that we will create in here as well
-(id)initSceneWithSize:(CGSize)size {  
    ...
    ...
    self.physicsWorld.contactDelegate = self;  
    [self setupGround];  
    ...  
}  

// Here we will create the ground node, so we can detect when a drop  
// Hits the ground.  
// The reason that, in the below code, I am setting just the ground,  
// and not the whole borders of the screen, is because the drops  
// are added above the screen 'borders', and if we would make  
// a 'frame' node, and not a 'ground' node, we will also receive  
// contact delegate calls, when the nodes first enter the scene  
// and hits the top 'border' of the frame
-(void)setupGround {  
    SKNode *groundNode     = [SKNode node];  
    groundNode.strokeColor = [SKColor clearColor];  
    groundNode.fillColor   = [SKColor clearColor];  
    // Not sure if the above two are mandatory, but better be safe than sorry...  

    // Here we set the physics body to start at the bottom left edge of the screen  
    // and be the width of the screen, and the size of 1 points  
    // Then, we also set its category bit mask
    CGRect groundRect = CGRectMake(0, 0, self.size.width, 1);
    groundNode.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:groundRect];  
    groundNode.physicsBody.categoryBitMask = groundCategory;  

    [self addChild:groundNode];  
}  

// Next we will modify your current method of creating drops, to also have  
// their name property to holds the corresponding colour name  
+(instancetype)dropOfType:(ANBDropType)type {

    ANBDropsNode *drop;

    if (type == ANBDropTypeBlue) {
        drop = [self spriteNodeWithImageNamed:@"bluedrop"];
        drop.name = @"Blue";
    } else if (type == ANBDropTypeGreen) {
        drop = [self spriteNodeWithImageNamed:@"greendrop"];
        drop.name = @"Green";
    } else if (type == ANBDropTypeOrange) {
        drop = [self spriteNodeWithImageNamed:@"orangedrop"];
        drop.name = @"Orange";
    } else if (type == ANBDropTypeRed){
        drop = [self spriteNodeWithImageNamed:@"reddrop"];
        drop.name = @"Red";
    }

    [drop setupPhysicsBody];
    return drop;
}  

// In your setupPhysicsBody method of the drop, add the following to define  
// the drop's bit mask, contact test, and collision.  
// Make sure you are adding them AFTER setting the physics body, and not before.  
// Since you revealed no code regarding this method, I will assume 'self' is  
// referring to the drop, since you call this method on the drop.
-(void) setupPhysicsBody {  
    ...  
    ...  
    ...  
    self.physicsBody.categoryBitMask    = dropsCategory;  
    self.physicsBody.contactTestBitMask = groundCategory;  
    self.physicsBody.collisionBitMask   = 0;  
    // The above code sets the drop category bit mask, sets its contactTestBitMask  
    // to be of the groundCategory, so whenever an object with drop category, will  
    // 'touch' and object with groundCategory, our didBeginContact delegate will  
    // get called.  
    // Also, we've set the collision bit mask to be 0, since we only want to  
    // be notified when a contact begins, but we don't actually want them both to  
    // 'collide', and therefore, have the drops 'lying' on the ground.  
    ...  
    ...  
    ...  
}  

// Now we can set the didBeginContact: delegate method.  
// Note that, as the name of the method suggests, this method gets called when a  
// Contact is began, meaning, the drop is still visible on screen.  
// If you would like to do whatever you want to do, when the drop leaves the screen,  
// just call the didEndContact: delegate method  
-(void)didBeginContact:(SKPhysicsContact *)contact {  
    // SKPhysicsContact have two properties, bodyA and bodyB, which represents  
    // the two nodes that contacted each other.  
    // Since there is no certain way to know which body will always be our drop,  
    // We will check the bodies category bit masks, to determine which is which  
    ANBDropsNode *drop = (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) ? (ANBDropsNode *)contact.bodyB.node : (ANBDropsNode *)contact.bodyA.node;  
    // In the above we are checking the category bit masks,  
    // Note that we set groundCategory to be 1, and dropsCategory to be 2,  
    // So we are checking which is higher.  
    // If bodyA bit mask is lower than bodyB bit mask, that means the bodyA is  
    // the ground, and bodyB is the drop, so we set the drop to be bodyB's node  
    // Else, we set it to be bodyA's node.  

    // Now you can easily get the drop colour from the name property we've set in  
    // the beginning. you can do some sort of if-else statement, that check  
    // 'if isEqualToString'. Here I just NSLog the colour  
    NSLog(@"%@", drop.name);

}  

祝你好运。