2013-10-10 2 views
8

В моем текущем проекте, использующем SpriteKit, у меня есть куча спрайтов, которые нужно масштабировать вверх и вниз независимо в разное время. Проблема в том, что когда я масштабирую узел, физическое тело не масштабируется, поэтому оно закручивает физику. Вот небольшой пример, который я поставил вместе для целей данного вопроса:SKPhysicsBody и [SKNode setScale:]

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]; 

enter image description here

Обратите внимание, как синий спрайт (уменьшено) сидит на вершине красной, но вы можете сказать, его физический организм еще имеет размер, который я ему сказал, и он не масштабировался.

Очевидно, что масштабирование узла не уменьшает физический порядок. Поэтому мой вопрос в том, нужно ли мне вручную это делать, как мне это сделать?

Я попытался поменять местами корпус с одним из правильных размеров при масштабировании, но тогда все становится действительно запутанным, если у старого тела есть суставы и т. Д. Это было бы намного проще, если бы я мог просто масштабировать существующее тело как-то.

+1

Просто нет масштабирования форм тела в Box2D (используется SK) – LearnCocos2D

ответ

3

У меня была такая же проблема, я думаю, что это ошибка в комплекте спрайтов.

Попробуйте использовать действие для масштабирования, это работает на всей сцене.

[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]; 
} 

enter image description here

+0

Я действительно прочитал вашу нить раньше. Он работает, если я масштабирую всю сцену таким образом, но если вы выполняете то же действие над спрайтом, оно дает такой же баггиальный результат. Я пытаюсь масштабировать эти узлы самостоятельно, это сводит меня с ума. – mprivat

+0

Ну, если вы поменяете тело на меньший, он будет работать. Но тогда это имеет последствия для существующих суставов между органами. Повторное создание суставов не работает, если узлы находятся в движении. Я боюсь, что это будет одна из тех невозможных проблем, пока не будут внесены корректировки в рамки. – mprivat

+0

Я согласен с Вашим запросом, нужен SK Fix – DogCoffee

5

формы тела Физика не может быть расширена. Определенно не в Box2D, который использует Sprite Kit внутри.

Помимо внутренних оптимизаций, масштабирование физического тела будет иметь далеко идущие последствия. Например, масштабирование формы тела может привести к тому, что тело застрянет в столкновениях. Это повлияет на взаимодействие суставов. Это определенно изменило бы плотность тела или массу и, следовательно, его поведение.

Вы можете использовать SKNode, к которому вы добавляете спрайт без физического тела, а затем добавить дополнительный SKNode с телами заданных размеров. Затем вы можете включить или отключить тела при запуске масштабирования спрайта. Если вы правильно это сделаете, игрок не заметит, что форма столкновения просто переместилась от полного размера до половины размера, в то время как спрайт оживляет этот масштабный переход.

Вам нужно было бы вычислить плотность тела и, возможно, другие свойства в соответствии с его размером.

+0

Хорошая идея, но, к сожалению, не применима для моего варианта использования: у меня есть мяч (SKShapeNode с телом), который при ударе другого объекта сбивается в другом направлении и становится меньше. Если я просто деактивирую тело и создаю еще один, мяч потеряет скорость и другие свойства. Вы пишете: > добавить дополнительный SKNode с телами заданных размеров AFAIK нельзя добавить несколько тел в один SKNode, не так ли? – cocoapriest

+0

Я думаю, что он означает, что вы можете добавить несколько SKNodes в качестве дочерних элементов для вашего узла спрайтов, и каждый из дочерних узлов будет иметь свой собственный физический объект. Одним из способов, позволяющих включать/отключать тела, является изменение их битмаксов столкновения. – peacetype

1

Физический корпус зависит от CGPath SKNode; вам нужно каким-то образом изменить это. Вы можете попробовать масштабирование 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, который масштабирует узел.

+0

Но вы не можете получить доступ к текущему пути PhysicsBody. – Martin

+0

То, от чего зависит организм, зависит от того, как вы его создали, не обязательно (напрямую)/CGPath - и это зависит от этого пути (или другой геометрии) в момент его создания. – bshirley

7

Используя либо SKAction, либо цикл обновления, вы можете создать новый SKPhysicsBody с соответствующим масштабом и применить его к объекту. Однако при этом вы потеряете скорость.Чтобы исправить это, вы можете сделать следующее:

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

boxObject.physicsBody = newBody; 
+0

Этого недостаточно, есть другие параметры, такие как angularVelocity и другие, недоступные напрямую, поэтому вы не можете распространять одни и те же свойства на новый физический элемент –

2

Для тех, кто читает этот ответ, я считаю, что теперь физические тела масштабируются с помощью SKNode. Я использую Xcode 8.2.1 и Swift 3.0.2. Я начинаю новый проект, выбираю игру, заполняю детали. Изменение 2 файла:

GameViewController.swift (добавить одну строку)

игры 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) 
    } 

} 

Граница физика масштабировании с узлом спрайта.

+2

. Я также заметил это: http://stackoverflow.com/a/33572073/3402095 – Whirlwind

+0

@Whirlwind пожелал, чтобы я видел ваше сообщение до этого –

0

У меня была эта же проблема, все, что я делал, определяло мое физическое тело в моей текущей функции текущего времени обновления, и оно будет масштабироваться.

Для вас это было бы что-то вроде этого:

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. Вы можете сделать некоторые из этих свойств, как реституция, равную переменной, чтобы вы могли изменить ее свойства, изменив переменную в другом месте. Переопределение его в другом месте работает только до тех пор, пока не будет вызван следующий кадр.

Смежные вопросы