2013-10-10 3 views
8

Nel mio progetto corrente che utilizza SpriteKit, ho una serie di sprite che devono essere scalate in su e in giù indipendentemente in vari momenti. Il problema è che quando scala il nodo, il corpo della fisica non si scala con esso in modo da rovinare la fisica. Ecco un piccolo esempio ho messo insieme per lo scopo di questa domanda:SKPhysicsBody e [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

Notate come lo sprite blu (ridotta) si trova sulla cima di quello rosso, ma si può dire il suo corpo fisico ancora ha la dimensione che ho detto, e non ha scala.

Quindi, ovviamente, il ridimensionamento del nodo non ridimensiona il corpo fisico. Quindi la mia domanda è se devo farlo manualmente, come faccio a farlo?

Ho provato a scambiare il corpo con una delle dimensioni giuste durante il ridimensionamento, ma poi le cose si fanno davvero complicate se il vecchio corpo ha delle articolazioni, ecc ... Sarebbe molto più semplice se potessi ridimensionare il corpo esistente in qualche modo.

+1

semplicemente non c'è ridimensionamento delle forme del corpo in Box2D (usato da SK) – LearnCocos2D

risposta

3

Ho avuto lo stesso identico problema, penso sia un bug nel kit sprite.

Provare a utilizzare un'azione per ridimensionare, questo funziona su tutta la scena.

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

mio originale question

E 'questo ciò che si vuole che accada

- (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

Ho letto anche il tuo thread prima. Funziona se scala l'intera scena in quel modo, ma se si esegue la stessa azione sullo sprite, si ottiene lo stesso risultato buggato. Sto cercando di scalare quei nodi in modo indipendente, mi sta facendo impazzire. – mprivat

+0

Beh, se si sostituisce il corpo con uno più piccolo, funziona in qualche modo. Ma poi ha implicazioni sulle giunture esistenti tra i corpi. Ricreare le articolazioni non funziona bene se i nodi sono in movimento. Temo che questo sarà uno di quei problemi impossibili fino a quando non saranno apportate modifiche al framework. – mprivat

+0

Sono d'accordo con il tuo commento, ho bisogno di una correzione SK – DogCoffee

5

forme del corpo la fisica non possono essere scalate. Sicuramente non in Box2D che Sprite Kit usa internamente.

Oltre alle ottimizzazioni interne, il ridimensionamento di un corpo fisico avrebbe implicazioni di vasta portata. Ad esempio ridimensionare la forma di un corpo potrebbe far rimanere il corpo in collisione. Avrebbe influito sul modo in cui le articolazioni interagiscono. Cambierà sicuramente la densità o la massa del corpo e quindi il suo comportamento.

È possibile utilizzare un codice SKN a cui si aggiunge lo sprite senza un corpo fisico e quindi aggiungere SKNode aggiuntivo con corpi di dimensioni specifiche. Potresti quindi abilitare o disabilitare i corpi quando inizi a ridimensionare lo sprite. Se fai questo tempo, il giocatore non noterà che la forma della collisione è passata da una dimensione intera a una metà, mentre lo sprite anima quella transizione di scala.

Si dovrebbe calcolare la densità del corpo e forse altre proprietà in base alle sue dimensioni però.

+0

Bella idea, ma sfortunatamente non applicabile per il mio caso d'uso: ho una palla (SKShapeNode con un corpo) che, quando colpisce un altro oggetto, si stacca in un'altra direzione e diventa più piccola. Se semplicemente disattivo il corpo e ne creo un altro, la palla perderà la sua velocità e altre proprietà. Scrivi: > aggiungi SKNode aggiuntivo con corpi di dimensioni specifiche AFAIK non è possibile aggiungere più corpi a un singolo SKNode, non è vero? – cocoapriest

+0

Penso che significhi che potresti aggiungere più SKNode come figli al tuo nodo sprite, e ciascuno dei nodi figli avrebbe il suo corpo fisico. Un modo per abilitare/disabilitare i corpi è quello di cambiare le loro maschere di bit di collisione. – peacetype

1

Il corpo fisico dipende dal CGPath dello SKNode; dovrai cambiarlo in qualche modo. Si potrebbe provare a scalare il CGPath con qualcosa come il seguente:

//scale up 

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

Ma tenere a mente questo non aggiornerà la comparsa di nodi già in uno SKScene. Potrebbe essere necessario combinare il ridimensionamento di CGPath con una SKAction che ridimensiona il nodo.

+0

Ma non è possibile accedere al percorso corrente di PhysicsBody. – Martin

+0

dipende dalla modalità di creazione, non necessariamente (direttamente) di/a CGPath e dipende da quel percorso (o altra geometria) nel momento in cui viene creato. – bshirley

7

Utilizzando uno SKAction o il ciclo di aggiornamento, è possibile creare un nuovo SKPhysicsBody con la scala appropriata e applicarlo all'oggetto. Tuttavia, così facendo, perderai la velocità.Per risolvere questo problema, è possibile effettuare le seguenti operazioni:

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

boxObject.physicsBody = newBody; 
+0

Non è sufficiente, ci sono altri parametri coinvolti come angularVelocity e altri non disponibili direttamente, quindi non è possibile propagare le stesse proprietà a una nuova fisica. Bodo –

2

Per chiunque altro stia leggendo questa risposta, credo che ora Fisici Corpi scala con il codice SKNode. Sto usando Xcode 8.2.1 e Swift 3.0.2. Inizio un nuovo Progetto, seleziono Gioco, compilo i dettagli. Cambiare 2 file:

GameViewController.swift (aggiungere una riga)

gioco Scene.swift (sostituire lo sceneDidLoad()) funzione con questo:

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) 
    } 

} 

Il confine fisica è scalare con il nodo sprite.

+2

Ho notato anche questo: http://stackoverflow.com/a/33572073/3402095 – Whirlwind

+0

@Whirlwind vorrei aver visto il tuo post prima di questo –

0

Ho avuto lo stesso problema, tutto quello che ho fatto è stato definire il mio corpo fisico nella mia funzione di aggiornamento dell'ora corrente e sarebbe scalabile con esso.

Per te sarebbe qualcosa di simile:

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; 

} 

L'unico problema è che si deve ridefinire le proprietà di fisica ogni volta che in updateCurrentTime. Puoi rendere alcune di queste proprietà come se fosse la restituzione uguale a una variabile in modo da poter cambiare le sue proprietà modificando la variabile altrove. La ridefinizione in qualsiasi altro punto funziona solo fino alla chiamata del prossimo frame.