我正在开发一个SpriteKit应用程序,精灵在屏幕上弹跳(iOS 8,iPad,仅横向,Objective-C)。
作为一个测试案例,我有一个精灵从屏幕底部的中间开始,然后以45度向右上行。如果我在屏幕周围没有边缘体,这可以正常工作,但是当我添加边循环时会表现得非常奇怪(注释掉边循环并且它再次起作用)。
self.physicsBody= [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
注意:我在最后添加了一个更新,解释了行为,但没有解释原因。
NSLog显示使用预期帧({{0,0},{768,1024}})创建的边循环,并使用正确的位置和速度添加精灵。
当第一次通过渲染循环调用didSimulatePhysics
时,精灵的位置已经移动到屏幕上方四分之一处(横向)并且速度的dx分量已经变为零。精灵然后垂直移动,在屏幕中心〜512点的距离上下弹跳。
换句话说,精灵似乎沿着{384,384}和{384,896}之间的垂直线上下移动,好像边缘循环位于{{384,384},{0, 512}}而不是{{0,0},{768,1024}}。
如果我将精灵的起始位置更改为在此行上,它将从正确的位置开始,但仍会丢失它的x速度分量并保持约束到此行。如果我在该行的y范围内启动精灵但是在该行的x坐标之外,它会立即移动到该行的最近点,并继续相同的行为。
正如其他问题中所建议的那样,我尝试在视图控制器的SKScene
和viewWillAppear
中展示viewWillLayoutSubviews
,但行为是相同的。
我试过对边循环帧进行硬编码 - 没有变化。模拟器和设备上的行为也相同。
我有另一个玩具应用程序,看似相同的代码用于呈现SKScene
,设置边循环并生成可以正常工作的精灵。
以下代码来自SKScene子类:
- (id)initWithSize:(CGSize)size;
{
if (!(self= [super initWithSize:size])) return nil;
self.physicsWorld.contactDelegate= self;
self.physicsWorld.gravity= CGVectorMake(0.0, 0.0);
self.spriteAtlas= [SKTextureAtlas atlasNamed:@"sprites"];
srandom((unsigned int)time(NULL));
return self;
}
- (void)didMoveToView:(SKView *)view;
{
if (!self.contentCreated)
{
[self createTestSceneContent];
self.contentCreated= YES;
}
}
- (void)createTestSceneContent;
{
self.backgroundColor= [SKColor whiteColor];
self.scaleMode= SKSceneScaleModeAspectFit;
self.name= @"scene";
CGRect fr= self.frame;
NSLog(@"bodyWithEdgeLoopFromRect: %@", NSStringFromCGRect(fr));
// commenting out the following line resolves the issue
self.physicsBody= [SKPhysicsBody bodyWithEdgeLoopFromRect:fr];
self.physicsBody.friction= 0.0;
self.physicsBody.restitution= 1.0;
self.physicsBody.linearDamping= 0.0;
self.physicsBody.angularDamping= 0.0;
SKSpriteNode *ball= [[SKSpriteNode alloc] initWithTexture:[self.spriteAtlas textureNamed:@"ball"]];
ball.name= @"ball";
ball.physicsBody= [SKPhysicsBody bodyWithCircleOfRadius:self.size.width / 2.0];
ball.physicsBody.dynamic= YES;
ball.physicsBody.mass= 1.0;
ball.physicsBody.restitution= 1.0;
ball.physicsBody.friction= 0.0;
ball.physicsBody.linearDamping= 0.0;
ball.physicsBody.angularDamping= 0.0;
ball.physicsBody.affectedByGravity= NO;
ball.physicsBody.contactTestBitMask= 1;
ball.position= CGPointMake(self.size.width / 2.0, ball.size.height / 2.0);
ball.physicsBody.velocity= CGVectorMake(-75.0, 75.0);;
[self addChild:ball];
NSLog(@"createTestSceneContent - p= %@, v= %@", NSStringFromCGPoint(ball.position), NSStringFromCGVector(ball.physicsBody.velocity));
}
- (void)didSimulatePhysics;
{
SKNode *ball= [self childNodeWithName:@"ball"];
NSLog(@"didSimulatePhysics - p= %@, v= %@", NSStringFromCGPoint(ball.position), NSStringFromCGVector(ball.physicsBody.velocity));
}
并生成以下日志输出:
bodyWithEdgeLoopFromRect:{{0,0},{768,1024}}
createTestSceneContent - p = {384,15},v = {-75,75}
didSimulatePhysics - p = {383.90228,389.04977},v = {0,75}
didSimulatePhysics - p = {383.91571,390.29974},v = {0,75}
didSimulatePhysics - p = {383.92258,392.17471},v = {0,75}
...
didSimulatePhysics - p = {383.92499,637.17346},v = {0,75}
didSimulatePhysics - p = {383.92499,638.42346},v = {0,75}
didSimulatePhysics - p = {383.92499,638.42346},v = {0,-75}
didSimulatePhysics - p = {383.92499,637.17346},v = {0,-75}
更新:
经过大量尝试添加不同的边缘体后,我可以解释发生了什么,但不是为什么。
我添加的任何边缘身体似乎从身体所在的位置生效384点。 384是横向iPad屏幕宽度的一半。
例如,如果我在屏幕的左侧添加边缘:
self.physicsBody= [SKPhysicsBody bodyWithEdgeFromPoint:CGPointMake(0.0, 0.0) toPoint:CGPointMake(0.0, self.size.height)];
精灵会在x == 384时反弹。
因此,对于框架的边缘循环,球被限制在距离屏幕边缘384点的区域内,该区域是屏幕中心256点长的线。在屏幕的每个边缘外设置一个带有矩形384点的边缘循环会产生正确的行为(即精灵在屏幕边缘反弹):
self.physicsBody= [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectInset(self.frame, -384.0, -384.0)];
虽然这个kludge解决了当前的问题,但我仍然想了解为什么会发生这种情况,因为我认为这是一个潜在问题的症状,也会出现在应用程序的其他地方。
任何想法都会非常感激。感谢