2016-02-01 20 views
5

Così ho una messa a punto gioco di base che si possono trovare al link qui sotto bitbucket:bloccaggio telecamera intorno lo sfondo di una scena in SpriteKit

Game link

Attualmente sto attraversando un periodo difficile capire come traduci il nodo della videocamera in relazione al layout della scena.

L'obiettivo è far seguire la videocamera al giocatore fino a raggiungere un limite d'angolo definito dalla dimensione della scena. In questa configurazione particolare scenario di test, la scena è 1000x1000 dimensioni con una scala di fotocamera 1.

Il codice di seguito viene utilizzato per modificare la posizione della fotocamera quando una nuova posizione viene impostato per seguire il carattere:

var cameraPosition: CGPoint { 

     get { 
      return CGPoint(x: camera!.position.x, y: camera!.position.y) 
     } 

     set { 

      let cameraScale = CGFloat(1) 
      let sceneScale = CGFloat(1)//CGFloat(1 - 0.44 + 0.05 /*possible rounding error adjustment*/) 
//   let viewAspectRatio = CGRectGetWidth(view!.frame)/CGRectGetHeight(view!.frame) 
      let newPositionValue = double2(x: Double(newValue.x * sceneScale), y: Double(newValue.y * sceneScale)) 

      let scaledSceneSize = CGSize(width: size.width * sceneScale , height: size.height * sceneScale) 
////   scaledSceneSize.height = scaledSceneSize.height/viewAspectRatio 

      let cameraSize = view!.bounds.size 
      let scaledCameraSize = CGSize(width: cameraSize.width * cameraScale, height: cameraSize.height * cameraScale) 


      let minX = 0//-scaledSceneSize.width * anchorPoint.x + scaledCameraSize.width/2 
      let minY = -219//-scaledSceneSize.height * anchorPoint.y + scaledCameraSize.height/2 

      let minValues = double2(x: Double(minX), y: Double(minY)) 

      let maxX = 0//(scaledSceneSize.width * anchorPoint.x - scaledCameraSize.width/2) //size.width - cameraSize.width/2 
      let maxY = 219//(scaledSceneSize.height * anchorPoint.y - scaledCameraSize.height/2) //- cameraSize.height/2 

      let maxValues = double2(x: Double(maxX), y: Double(maxY)) 

      let clampedPosition = clamp(newPositionValue, min: minValues, max: maxValues) 


      camera!.position = CGPoint(x: (clampedPosition.x/Double(sceneScale)), y: (clampedPosition.y/Double(sceneScale))) 
     } 

    } 

Ci sono dei valori fondamentali che attualmente si adattano alle dimensioni della scena richiesta e non sono sicuro su come ottenere questi risultati tramite la scala. La scala di default è:

/* Set the scale mode to scale to fit the window */ 
      scene.scaleMode = .AspectFill 

Senza la conoscenza di sapere c'è una traduzione in scala, per impostazione predefinita, mi aspetterei i confini di essere largestSceneDimensionXValue - cameraSize.width/2 largestSceneDimensionYValue - cameraSize.height/2

Come esempio di alto livello. Qualcuno potrebbe aiutarmi a ottenere questa traduzione?

Nel complesso la scena dovrebbe essere simile al seguente in tutti gli angoli: goal

VS avere l'overflow sfondo nero nella telecamera come tale:

anti goal

risposta

1

Non ho usato il codice . Ho realizzato un progetto di esempio e ho funzionato.

enter image description here

heres il mio codice

import SpriteKit 

class GameScene: SKScene { 

    let world = SKSpriteNode(imageNamed: "world.jpg") 
    let player = SKSpriteNode(color: SKColor.greenColor(), size: CGSizeMake(10, 10)) 

    var cam: SKCameraNode! 

    override init(size: CGSize) { 
     super.init(size: size) 
     print(world.size) 
     addChild(world) 
     addChild(player) 

     world.zPosition = 1 
     player.zPosition = 2 

     cam = SKCameraNode() 
     self.camera = cam 
     addChild(cam) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { 
     for touch: AnyObject in touches { 
      let location = touch.locationInNode(self) 

      player.position = location 
     } 
    } 

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { 
     for touch: AnyObject in touches { 
      let location = touch.locationInNode(self) 

      player.position = location 
     } 
    } 

    func clampCamera(){ 

     func clamp(inout input: CGFloat, num1: CGFloat, num2: CGFloat) { 
      if input < num1 { 
       input = num1 
      } 
      else if input > num2 { 
       input = num2 
      } 
     } 

     let lBoundary = -world.size.width/2 + size.width/2 
     let rBoundary = world.size.width/2 - size.width/2 
     let bBoundary = -world.size.height/2 + size.height/2 
     let tBoundary = world.size.height/2 - size.height/2 

     clamp(&camera!.position.x, num1: lBoundary, num2: rBoundary) 
     clamp(&camera!.position.y, num1: bBoundary, num2: tBoundary) 

    } 

    override func update(currentTime: NSTimeInterval) { 
     camera!.position = player.position 
     clampCamera() 
    } 
} 

questa è la stessa immagine che ho usato come il mio "mondo" http://i.imgur.com/XhZbh8q.jpg

+0

Questo è molto simile al mio primo approccio che non funziona quando ridimensionamento della fotocamera e altre condizioni. Il motivo principale per cui ho allegato il codice sopra è di fare riferimento allo scenario specifico. Se riesci a far funzionare il codice sopra riportato nel repository, allora dovrebbe essere perfetto ma sono al 100% positivo che non lo farà. La scala della fotocamera dovrebbe essere .44, ma ho normalizzato tutto per capire da dove vengono i valori. – TheCodingArt

+0

Notare la larghezza della scena non corrisponde alla larghezza della telecamera. – TheCodingArt

+0

ho giocato con il tuo codice e sta iniziando a diventare il mio progetto lol .. ce n'è davvero tanto da fare .. se fossi in te potrei iniziare un nuovo progetto di esempio aggiungendo in ogni elemento di complessità (cameraScale .. ecc.) uno alla volta fino a trovare un modo più semplice per risolvere il problema. – hamobi

2

Applicazioni come questa sono esattamente ciò che è per SKConstraint.

È possibile visualizzare una dimostrazione di questa funzione esatta - vincolando una telecamera in modo che segua il lettore, ma non mostri troppo spazio vuoto attorno al bordo del livello - nella sessione WWDC15 Deeper into GameplayKit with DemoBots. * (Il collegamento ci dovrebbe saltare a circa 07:27 nel discorso in cui la discussione di questa funzione ha inizio)

l'essenza di ciò che è nel video, con alcuni frammenti di codice di esempio DemoBots:.

  1. Utilizzare un distanza vincolo per mantenere la fotocamera centrata sul lettore (automaticamente , senza dover impostare camera.position direttamente su ogni update()).

    // Constrain the camera to stay a constant distance of 0 points from the player node. 
    let zeroRange = SKRange(constantValue: 0.0) 
    let playerBotLocationConstraint = SKConstraint.distance(zeroRange, toNode: playerNode) 
    
  2. Utilizzare una posizione vincolo per tenere la fotocamera entro un certo intervallo del bordo del livello. Calcola tale intervallo prendendo la cornice del livello e inserendo il rettangolo in base alla distanza che la telecamera deve mantenere dal bordo del livello.

    // get the scene size as scaled by `scaleMode = .AspectFill` 
    let scaledSize = CGSize(width: size.width * camera.xScale, height: size.height * camera.yScale) 
    
    // get the frame of the entire level contents 
    let boardNode = childNodeWithName(WorldLayer.Board.nodePath)! 
    let boardContentRect = boardNode.calculateAccumulatedFrame() 
    
    // inset that frame from the edges of the level 
    // inset by `scaledSize/2 - 100` to show 100 pt of black around the level 
    // (no need for `- 100` if you want zero padding) 
    // use min() to make sure we don't inset too far if the level is small 
    let xInset = min((scaledSize.width/2) - 100.0, boardContentRect.width/2) 
    let yInset = min((scaledSize.height/2) - 100.0, boardContentRect.height/2) 
    let insetContentRect = boardContentRect.insetBy(dx: xInset, dy: yInset) 
    
    // use the corners of the inset as the X and Y range of a position constraint 
    let xRange = SKRange(lowerLimit: insetContentRect.minX, upperLimit: insetContentRect.maxX) 
    let yRange = SKRange(lowerLimit: insetContentRect.minY, upperLimit: insetContentRect.maxY) 
    let levelEdgeConstraint = SKConstraint.positionX(xRange, y: yRange) 
    levelEdgeConstraint.referenceNode = boardNode 
    
  3. si applicano sia i vincoli al vostro SKCameraNode.

    camera.constraints = [playerBotLocationConstraint, levelEdgeConstraint] 
    

Per uno sguardo più profondo, download Apple's DemoBots sample code project, che ha un sacco di commenti e sostenere codice che ho tagliato dai frammenti di cui sopra per mantenere questo post da ottenere eccessivamente lunghi. Tutto per il vincolo della videocamera è func setCameraConstraints() in LevelScene.swift.

* Nonostante il nome della sessione, è molto più di un semplice GameplayKit ... mostra come sfruttare molte delle tecnologie introdotte in iOS 8/OS X 10.11/Xcode 7 per creare qualcosa che assomigli a un gioco a grandezza naturale : App Thinning, nuove funzionalità di SpriteKit, ReplayKit e molto altro.

+0

Ti manca il punto della domanda, sì questa è un'applicazione primaria per un vincolo ma l'offset generale deve ancora essere calcolato e conosciuto, che è ciò a cui la domanda precedente sta cercando di ottenere una risposta. – TheCodingArt

+0

* Se il tuo livello è abbastanza grande e la fotocamera non si ridimensiona o ruota, il tuo riquadro può essere semplicemente metà della larghezza/altezza dello schermo. * Se il tuo livello è sempre più piccolo dello schermo del dispositivo, una dimensione a schermo intero costante dal livello di frame è tutto ciò che serve. – rickster

+0

Queste condizioni non si applicano all'applicazione di esempio sopra e ho bisogno di qualcosa che possa scalare con la fotocamera. – TheCodingArt

Problemi correlati