iOS 9 更新后 SKFieldNode 定位错误
SKFieldNode positioned wrong after iOS 9 update
我有一些代码在 iOS 8 中工作得很好,但是自从 iOS 9 以来,一些 SKFieldNodes
的行为非常奇怪。下图显示了一个场景,其中有两个 SKFieldNodes
(标有红色精灵)和一个 SKEmitterNode
发射金色粒子。
在 iOS 8 中,磁场会吸引粒子并 "suck" 它们朝向磁铁的尖端。由于 iOS 9,粒子向右上角加速,如红色箭头所示。此外,我还必须增加字段的 strength
才能使效果可见。
对应代码如下:
SKSpriteNode* magnet = [SKSpriteNode spriteNodeWithImageNamed:@"StarMagnet_main"];
//Add field node
SKFieldNode* field = [SKFieldNode radialGravityField];
field.strength = 10.0;
field.falloff = 0.1;
//Add a red circle to visualize the node
SKShapeNode* debugNode = [SKShapeNode shapeNodeWithCircleOfRadius:20.0];
debugNode.fillColor = [UIColor redColor];
[field addChild:debugNode];
field.position = CGPointMake(magnet.size.width * 0.3, magnet.size.height * 0.45);
field.categoryBitMask = LECategoryDust;
[magnet addChild:field];
//Add second field
field = [field copy];
field.position = CGPointMake(-field.position.x, field.position.y);
[magnet addChild:field];
//Add particle emitter
SKEmitterNode* emitter = [SKEmitterNode emitterNamed:@"MagneticParticleEmitter"];
emitter.fieldBitMask = LECategoryDust;
emitter.position = CGPointMake(0, magnet.size.height/2.0);
[magnet addChild:emitter];
好像字段节点位于右上角附近的某个地方,但是红色圆圈子节点显示不同。
仔细调查后,我断定这是一个 SpriteKit 错误引入 iOS 9. 下面你可以找到一个由 SKEmitterNode
, SKFieldNode
组成的测试场景和两个 SKShapeNodes
标记初始视口和字段的位置。所有节点都是用于翻译“世界”的 rootNode
的后代。
虽然场的位置没有改变,但它的效果中心会改变。
仅当 SKEmitterNode's
targetNode
属性 设置为 scene
时力计算才是正确的,这并不总是需要的。
黄色圆圈标记了字段的位置。然而,粒子被吸引到右上角。以下是此时的一些位置:
Root scene pos: 160x, 284y | parent pos: 160x, 284y
Field scene pos: 80x, 142y | parent pos: -80x, -142y
Target scene pos: 80x, 142y | parent pos: -80x, -142y
如您所见,该字段和黄色圆圈具有相同的位置(和父级)。
移动场景时(即仅rootNode
),粒子被拉向另一个点,该点移动到更靠近左下角的位置,同时平移到相反的位置。
翻译后的一些位置:
Root scene pos: 84x, 149y | parent pos: 84x, 149y
Field scene pos: 4x, 7y | parent pos: -80x, -142y
Target scene pos: 4x, 7y | parent pos: -80x, -142y
场地位置没变,重心变了
视频
为了更好地说明该行为,我上传了截屏视频:
https://youtu.be/EJs4vPYMndU
代码
欢迎大家自行尝试,下面是本次实验使用的测试场景代码:
#import "LEDebugScene.h"
#import "LEPhysicsCategories.h"
@implementation LEDebugScene
SKNode* rootNode;
SKFieldNode* fieldNode;
SKShapeNode* targetPosShape;
- (void) didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
// This will be the desired field's position (in parent space)
CGPoint fieldPosition = CGPointMake(-self.size.width * 0.25, -self.size.height * 0.25);
// 1. Set up a root node to move around to translate the "world"
rootNode = [SKNode node];
rootNode.position = CGPointMake(self.size.width/2.0, self.size.height/2.0);
[self addChild:rootNode];
// 2. Mark the target position of the field with a circle
targetPosShape = [SKShapeNode shapeNodeWithCircleOfRadius:20.0];
targetPosShape.fillColor = [UIColor yellowColor];
targetPosShape.strokeColor = [UIColor brownColor];
[rootNode addChild:targetPosShape];
targetPosShape.position = fieldPosition;
// 3. Mark the initially visible portion of the scene
SKShapeNode* initialViewportShape = [SKShapeNode shapeNodeWithRect: CGRectMake(-self.size.width/2.0,
-self.size.height/2.0,
self.size.width,
self.size.height)];
initialViewportShape.fillColor = [UIColor clearColor];
initialViewportShape.strokeColor = [UIColor redColor];
initialViewportShape.lineWidth = 3.0;
[rootNode addChild:initialViewportShape];
// 4. Add an emitter at the center of the initial viewport
NSString* emitterPath = [[NSBundle mainBundle] pathForResource:@"DebugEmitter" ofType:@"sks"];
SKEmitterNode* emitterNode = [NSKeyedUnarchiver unarchiveObjectWithFile:emitterPath];
emitterNode.fieldBitMask = LECategoryDust;
emitterNode.particlePositionRange = CGVectorMake(self.size.width, self.size.height);
emitterNode.position = CGPointZero;
[rootNode addChild:emitterNode];
// 5. Create a field at the desired position
fieldNode = [SKFieldNode radialGravityField];
fieldNode.userData = [NSMutableDictionary dictionary];
fieldNode.categoryBitMask = LECategoryDust;
fieldNode.falloff = 1.8;
fieldNode.minimumRadius = 20.0;
fieldNode.strength = 2.5;
fieldNode.position = fieldPosition;
[rootNode addChild:fieldNode];
}
- (void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//Get the touch movement vector
UITouch* touch = [touches anyObject];
CGPoint prevLoc = [touch previousLocationInNode:self];
CGPoint location = [touch locationInNode:self];
CGVector delta = CGVectorMake(location.x - prevLoc.x, location.y - prevLoc.y);
//Translate the world by repositioning the root node
rootNode.position = CGPointMake(rootNode.position.x + delta.dx, rootNode.position.y + delta.dy);
CGPoint rootScenePos = [self convertPoint:rootNode.position fromNode:rootNode.parent];
CGPoint fieldScenePos = [self convertPoint:fieldNode.position fromNode:fieldNode.parent];
CGPoint targetShapeScenePos = [self convertPoint:targetPosShape.position fromNode:targetPosShape.parent];
NSLog(@"");
NSLog(@"Root scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
rootScenePos.x, rootScenePos.y, rootNode.position.x, rootNode.position.y);
NSLog(@"Field scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
fieldScenePos.x, fieldScenePos.y, fieldNode.position.x, fieldNode.position.y);
NSLog(@"Target scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
targetShapeScenePos.x, targetShapeScenePos.y, targetPosShape.position.x, targetPosShape.position.y);
}
@end
尽管尝试了几个小时,我还是没能通过重新定位字段节点来弥补计算错误。如果有人做了,如果他们能分享它就太好了。
编辑:我还提交了错误报告 (23063175)。
我有一些代码在 iOS 8 中工作得很好,但是自从 iOS 9 以来,一些 SKFieldNodes
的行为非常奇怪。下图显示了一个场景,其中有两个 SKFieldNodes
(标有红色精灵)和一个 SKEmitterNode
发射金色粒子。
在 iOS 8 中,磁场会吸引粒子并 "suck" 它们朝向磁铁的尖端。由于 iOS 9,粒子向右上角加速,如红色箭头所示。此外,我还必须增加字段的 strength
才能使效果可见。
对应代码如下:
SKSpriteNode* magnet = [SKSpriteNode spriteNodeWithImageNamed:@"StarMagnet_main"];
//Add field node
SKFieldNode* field = [SKFieldNode radialGravityField];
field.strength = 10.0;
field.falloff = 0.1;
//Add a red circle to visualize the node
SKShapeNode* debugNode = [SKShapeNode shapeNodeWithCircleOfRadius:20.0];
debugNode.fillColor = [UIColor redColor];
[field addChild:debugNode];
field.position = CGPointMake(magnet.size.width * 0.3, magnet.size.height * 0.45);
field.categoryBitMask = LECategoryDust;
[magnet addChild:field];
//Add second field
field = [field copy];
field.position = CGPointMake(-field.position.x, field.position.y);
[magnet addChild:field];
//Add particle emitter
SKEmitterNode* emitter = [SKEmitterNode emitterNamed:@"MagneticParticleEmitter"];
emitter.fieldBitMask = LECategoryDust;
emitter.position = CGPointMake(0, magnet.size.height/2.0);
[magnet addChild:emitter];
好像字段节点位于右上角附近的某个地方,但是红色圆圈子节点显示不同。
仔细调查后,我断定这是一个 SpriteKit 错误引入 iOS 9. 下面你可以找到一个由 SKEmitterNode
, SKFieldNode
组成的测试场景和两个 SKShapeNodes
标记初始视口和字段的位置。所有节点都是用于翻译“世界”的 rootNode
的后代。
虽然场的位置没有改变,但它的效果中心会改变。
仅当 SKEmitterNode's
targetNode
属性 设置为 scene
时力计算才是正确的,这并不总是需要的。
黄色圆圈标记了字段的位置。然而,粒子被吸引到右上角。以下是此时的一些位置:
Root scene pos: 160x, 284y | parent pos: 160x, 284y
Field scene pos: 80x, 142y | parent pos: -80x, -142y
Target scene pos: 80x, 142y | parent pos: -80x, -142y
如您所见,该字段和黄色圆圈具有相同的位置(和父级)。
移动场景时(即仅rootNode
),粒子被拉向另一个点,该点移动到更靠近左下角的位置,同时平移到相反的位置。
翻译后的一些位置:
Root scene pos: 84x, 149y | parent pos: 84x, 149y
Field scene pos: 4x, 7y | parent pos: -80x, -142y
Target scene pos: 4x, 7y | parent pos: -80x, -142y
场地位置没变,重心变了
视频
为了更好地说明该行为,我上传了截屏视频: https://youtu.be/EJs4vPYMndU
代码
欢迎大家自行尝试,下面是本次实验使用的测试场景代码:
#import "LEDebugScene.h"
#import "LEPhysicsCategories.h"
@implementation LEDebugScene
SKNode* rootNode;
SKFieldNode* fieldNode;
SKShapeNode* targetPosShape;
- (void) didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
// This will be the desired field's position (in parent space)
CGPoint fieldPosition = CGPointMake(-self.size.width * 0.25, -self.size.height * 0.25);
// 1. Set up a root node to move around to translate the "world"
rootNode = [SKNode node];
rootNode.position = CGPointMake(self.size.width/2.0, self.size.height/2.0);
[self addChild:rootNode];
// 2. Mark the target position of the field with a circle
targetPosShape = [SKShapeNode shapeNodeWithCircleOfRadius:20.0];
targetPosShape.fillColor = [UIColor yellowColor];
targetPosShape.strokeColor = [UIColor brownColor];
[rootNode addChild:targetPosShape];
targetPosShape.position = fieldPosition;
// 3. Mark the initially visible portion of the scene
SKShapeNode* initialViewportShape = [SKShapeNode shapeNodeWithRect: CGRectMake(-self.size.width/2.0,
-self.size.height/2.0,
self.size.width,
self.size.height)];
initialViewportShape.fillColor = [UIColor clearColor];
initialViewportShape.strokeColor = [UIColor redColor];
initialViewportShape.lineWidth = 3.0;
[rootNode addChild:initialViewportShape];
// 4. Add an emitter at the center of the initial viewport
NSString* emitterPath = [[NSBundle mainBundle] pathForResource:@"DebugEmitter" ofType:@"sks"];
SKEmitterNode* emitterNode = [NSKeyedUnarchiver unarchiveObjectWithFile:emitterPath];
emitterNode.fieldBitMask = LECategoryDust;
emitterNode.particlePositionRange = CGVectorMake(self.size.width, self.size.height);
emitterNode.position = CGPointZero;
[rootNode addChild:emitterNode];
// 5. Create a field at the desired position
fieldNode = [SKFieldNode radialGravityField];
fieldNode.userData = [NSMutableDictionary dictionary];
fieldNode.categoryBitMask = LECategoryDust;
fieldNode.falloff = 1.8;
fieldNode.minimumRadius = 20.0;
fieldNode.strength = 2.5;
fieldNode.position = fieldPosition;
[rootNode addChild:fieldNode];
}
- (void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//Get the touch movement vector
UITouch* touch = [touches anyObject];
CGPoint prevLoc = [touch previousLocationInNode:self];
CGPoint location = [touch locationInNode:self];
CGVector delta = CGVectorMake(location.x - prevLoc.x, location.y - prevLoc.y);
//Translate the world by repositioning the root node
rootNode.position = CGPointMake(rootNode.position.x + delta.dx, rootNode.position.y + delta.dy);
CGPoint rootScenePos = [self convertPoint:rootNode.position fromNode:rootNode.parent];
CGPoint fieldScenePos = [self convertPoint:fieldNode.position fromNode:fieldNode.parent];
CGPoint targetShapeScenePos = [self convertPoint:targetPosShape.position fromNode:targetPosShape.parent];
NSLog(@"");
NSLog(@"Root scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
rootScenePos.x, rootScenePos.y, rootNode.position.x, rootNode.position.y);
NSLog(@"Field scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
fieldScenePos.x, fieldScenePos.y, fieldNode.position.x, fieldNode.position.y);
NSLog(@"Target scene pos: %.0fx, %.0fy | parent pos: %.0fx, %.0fy",
targetShapeScenePos.x, targetShapeScenePos.y, targetPosShape.position.x, targetPosShape.position.y);
}
@end
尽管尝试了几个小时,我还是没能通过重新定位字段节点来弥补计算错误。如果有人做了,如果他们能分享它就太好了。
编辑:我还提交了错误报告 (23063175)。