【问题标题】:SKPhysicsBody and [SKNode setScale:]SKPhysicsBody 和 [SKNode setScale:]
【发布时间】:2013-10-10 20:31:10
【问题描述】:

在我当前使用 SpriteKit 的项目中,我有一堆需要在不同时间独立放大和缩小的精灵。问题是当我缩放节点时,物理体不会随它缩放,所以它搞砸了物理。这是我为了这个问题而整理的一个小例子:

CGSize objectSize = CGSizeMake(100, 100);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];

SKSpriteNode *n1 = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:objectSize];
n1.position = CGPointMake(self.size.width/2, 2*self.size.height/3);
n1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectSize];
n1.physicsBody.affectedByGravity = YES;
[self addChild:n1];

SKSpriteNode *n2 = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:objectSize];
n2.position = CGPointMake(self.size.width/2, self.size.height/3);
n2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectSize];
n2.physicsBody.affectedByGravity = YES;
[self addChild:n2];

[n1 setScale:0.5];

注意蓝色精灵(按比例缩小)如何位于红色精灵之上,但您可以看出它的物理体仍然具有我告诉它的尺寸,但它没有缩放。

很明显,缩小节点并不会缩小physicsBody。所以我的问题是,如果我必须手动执行,我该怎么做?

我尝试在缩放时将身体换成合适尺寸的身体,但如果旧身体有关节等,事情就会变得非常复杂......如果我能以某种方式缩放现有身体会简单得多.

【问题讨论】:

  • Box2D 中根本没有体形缩放(由 SK 使用)

标签: ios7 sprite-kit


【解决方案1】:

使用SKAction 或更新循环,您可以创建一个具有适当比例的新SKPhysicsBody 并将其应用于对象。但是,这样做会失去速度。要解决此问题,您可以执行以下操作:

SKPhysicsBody *newBody = [SKPhysicsBody bodyWithRectangleOfSize:boxObject.size];
newBody.velocity = boxObject.physicsBody.velocity;

boxObject.physicsBody = newBody;

【讨论】:

  • 这还不够,还涉及其他参数,例如 angularVelocity 和其他无法直接使用的参数,因此您无法将相同的属性传播到新的物理体
【解决方案2】:

物理体形无法缩放。绝对不是在 Sprite Kit 内部使用的 Box2D 中。

除了内部优化之外,缩放物理体还会产生深远的影响。例如,放大身体的形状可能会使身体陷入碰撞。它会影响关节如何相互作用。它肯定会改变身体的密度或质量,从而改变它的行为。

您可以使用一个 SKNode,向其中添加没有物理主体的精灵,然后添加具有给定大小的主体的附加 SKNode。然后,您可以在开始缩放精灵时启用或禁用身体。如果时间正确,玩家将不会注意到碰撞形状只是从全尺寸变为半尺寸,而精灵会为缩放过渡设置动画。

你必须根据它的大小计算身体的密度,也许还有其他属性。

【讨论】:

  • 好主意,但不幸的是不适用于我的用例:我有一个球(带有身体的 SKShapeNode),当它击中另一个物体时,它会朝另一个方向击落并变小。如果我简单地停用身体并创建另一个身体,球将失去它的速度和其他属性。您写道: > 添加具有给定大小的主体的附加 SKNode AFAIK 不可能将多个主体添加到单个 SKNode,不是吗?
  • 我认为他的意思是您可以将多个 SKNodes 作为子节点添加到您的精灵节点,并且每个子节点都有自己的物理体。您可以启用/禁用主体的一种方法是更改​​它们的碰撞位掩码。
【解决方案3】:

对于其他阅读此答案的人,我相信现在物理体与 SKNode 一起扩展。我正在使用 Xcode 8.2.1 和 Swift 3.0.2。我新建一个Project,选择Game,填写详细信息。更改 2 个文件:

GameViewController.swift(加一行)

view.showsFPS = true
view.showsNodeCount = true

// add this to turn on Physics Edges    
view.showsPhysics = true

Game Scene.swift(替换sceneDidLoad())函数:

override func sceneDidLoad() {

    var found = false
    self.enumerateChildNodes(withName: "testSprite") {
        node, stop in
            found = true
    }
    if !found {
        let testSprite = SKSpriteNode(color: UIColor.white, size: CGSize(width: 200.0, height: 200.0))
        testSprite.physicsBody = SKPhysicsBody(polygonFrom: CGPath(rect: CGRect(x: -100.0, y: -100.0, width: 200.0, height: 200.0), transform: nil))
        testSprite.physicsBody?.affectedByGravity = false
        testSprite.name = "testSprite"
        let scaleAction = SKAction.repeatForever(SKAction.sequence([
            SKAction.scale(to: 2.0, duration: 2.0),
            SKAction.scale(to: 0.5, duration: 2.0)
            ]))
        testSprite.run(scaleAction)
        self.addChild(testSprite)
    }

}

物理边界随着精灵节点缩放。

【讨论】:

【解决方案4】:

我遇到了完全相同的问题,我认为这是精灵套件中的错误。

尝试使用动作来缩放,这适用于整个场景。

[self runAction:[SKAction scaleTo:0.5 duration:0]];

我原来的question

这是你想要发生的事情

- (void) anthoertest
{
    CGSize objectSize = CGSizeMake(100, 100);
    self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    SKSpriteNode *n1 = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:objectSize];
    n1.position = CGPointMake(self.size.width/2, 2*self.size.height/3);
    n1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:n1.size];
    n1.physicsBody.affectedByGravity = YES;
    [self addChild:n1];

    SKSpriteNode *n2 = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:objectSize];
    n2.position = CGPointMake(self.size.width/2, self.size.height/3);
    n2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:n2.size];
    n2.physicsBody.affectedByGravity = YES;
    [self addChild:n2];

    [self shrinkMe:n1];
}

- (void) shrinkMe:(SKSpriteNode *) s
{
    [s setScale:0.5];
    s.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:s.size];
}

【讨论】:

  • 其实我之前也读过你的帖子。如果我以这种方式缩放整个场景,它会起作用,但如果你在精灵上运行相同的动作,它会产生相同的错误结果。我正在尝试独立扩展这些节点,这让我发疯了。
  • 好吧,如果你把身体换成更小的身体,它有点工作。但它对身体之间现有的关节有影响。如果节点处于运动状态,则重新创建关节效果不佳。恐怕在对框架进行调整之前,这将是那些不可能的问题之一。
  • 我同意你的意见,需要一个 SK Fix
  • 这不是错误。缩放对视图进行操作,但物理体的形状无法缩放。 Box2D 不允许缩放形状,除非您删除并添加一个效率相当低的新(缩放)形状。缩放物理物体会产生深远的影响,例如,将物体的形状放大可能会使物体陷入碰撞。
【解决方案5】:

物理体依赖于SKNode的CGPath;你需要以某种方式改变它。您可以尝试使用以下方式缩放 CGPath:

//scale up

CGFloat scaleFactor = 1.1;
CGAffineTransform scaleTransform = CGAffineTransformIdentity;
scaleTransform = CGAffineTransformScale(scaleTransform, scaleFactor, scaleFactor);
CGPathRef scaledPathRef = CGPathCreateCopyByTransformingPath(exampleNode.path, &scaleTransform);
exampleNode.path = scaledPathRef;

但请记住,这不会更新已在 SKScene 中的节点的外观。您可能需要将调整 CGPath 的大小与缩放节点的 SKAction 结合起来。

【讨论】:

  • 但是无法访问 PhysicsBody 当前路径。
  • 主体所依赖的取决于您创建它的方式,不一定(直接)/a CGPath - 它取决于创建时的路径(或其他几何形状)。跨度>
【解决方案6】:

我遇到了同样的问题,我所做的只是在我的更新当前时间函数中定义我的物理体,它会随着它缩放。

对你来说应该是这样的:

override func sceneDidLoad() {

SKSpriteNode *n1 = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:objectSize];
n1.position = CGPointMake(self.size.width/2, 2*self.size.height/3);

}
override func update(_ currentTime: TimeInterval) {

n1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectSize];
n1.physicsBody.affectedByGravity = YES;

}

唯一的问题是你必须每次在 updateCurrentTime 中重新定义你的物理属性。您可以使其中一些属性(例如恢复原状)等于一个变量,这样您就可以通过在其他地方更改变量来更改其属性。在其他任何地方重新定义它只在调用下一帧之前有效。

【讨论】:

    猜你喜欢
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多