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);
}
祝你好运。
我正在使用 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);
}
祝你好运。