Nowy projekt iOS Game. Ustaw rozmiar sceny 320 x 480 i rodzaj
Transkrypt
Nowy projekt iOS Game. Ustaw rozmiar sceny 320 x 480 i rodzaj
Nowy projekt iOS Game. Ustaw rozmiar sceny 320 x 480 i rodzaj symulatora: 4s Utwórz w projekcie nową grupę zasoby, zaimportuj do niej obrazki i dźwięki. Player Umieść sprite’a player, steruj playerem za pomocą dotknięcia ekranu, tak aby obrócił się i podążał do miejsca dotknięcia. W GameScene.sks: umieść ColorSprite / Texture: player, nadaj name: player W GameScene.swift posprzataj domyślny kod var player = SKSpriteNode() override func didMoveToView(view: SKView) { player = self.childNodeWithName("player") as! SKSpriteNode } Zdefiniuj w klasie GameScene punkt, przypisz mu lokalizację aktualnego dotknięcia. var punkt: CGPoint? // nie: CGPointZero, bo player będzie dążył na początku do (0,0) override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { for touch in touches { punkt = touch.locationInNode(self) } } override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { for touch in touches { punkt = touch.locationInNode(self) } } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { for touch in touches { punkt = touch.locationInNode(self) } } Zdefiniuj funkcję updatePlayer() i wywołaj ją we funkcji update() let pi2 = CGFloat(M_PI)/2 let v: CGFloat = 150; func updatePlayer() { if let t: CGPoint = punkt { // jeśli punkt dotknięcia != null let p = player.position let dx = t.x - p.x let dy = t.y - p.y let kat = atan2(dy, d.x) player.runAction(SKAction.rotateToAngle(kat + pi2, duration: 0)) let vx = v*cos(kat) let vy = v*sin(kat) player.physicsBody!.velocity = CGVectorMake(vx, vy) } } override func update(currentTime: CFTimeInterval) { updatePlayer() } lub raczej - wywoływana automatycznie po wykonaniu obliczeń symulacji, 1 raz na ramkę override func didSimulatePhysics() { updatePlayer() } Nadaj spritowi playera właściwości ciała fizycznego: we własciwościach sprite’a ustaw Body type: rectangle, Dynamic, Allow rotation odznacz affected by gravity Niech player zatrzyma się po dojściu do punktu dotknięcia func updatePlayer() { if let t: CGPoint = punkt { // cel let p = player.position // start let dx = t.x - p.x let dy = t.y - p.y if abs(dx)>player.frame.width/2 || (dy)>player.frame.height/2 { let kat = atan2(dy, dx) player.runAction(SKAction.rotateToAngle(kat + pi2, duration: 0)) let vx = v*cos(kat) let vy = v*sin(kat) player.physicsBody!.velocity = CGVectorMake(vx, vy) } else { player.physicsBody?.resting = true } } } Zombie W GameScene.sks umieść ColorSprite, texture: zombie, name zombie, ustaw właściwości fizyczne: Body type: rectangle, Dynamic, Allow rotation, odznacz affected by gravity sklonuj CMD+D sprite’a kilka razy i rozmieść na scenie. W GameScene.swift przygotuj tablicę Z dla zombies var Z = [SKSpriteNode]() we funkcji didMoveToView() załaduj zombies do tablicy Z for child in self.children { if child.name == "zombie" { if let z = child as? SKSpriteNode { Z.append(z) } } } Zombie będą gonić playera, napiszemy funkcję updateZombies(), która będzie aktualizować połozenie każdego zombie let vz: CGFloat = 50 // moduł prędkości zombie, składnik klasy func updateZombies() { let p = player.position // cel for z in Z { let q = z.position // start let dx = p.x - q.x let dy = p.y - q.y let kat = atan2(dy,dx) let obrot = SKAction.rotateToAngle(kat + pi2, duration: 0) z.runAction(obrot) z.physicsBody?.velocity = CGVectorMake(vz*cos(kat), vz*sin(kat)) } } Obsługa kontaktów ciał fizycznych W klasie GameScene implementuj protokół SKPhysicsContactDelegate, we funkcji didMoveToView ustaw physicsWorld.contactDelegate = self W GameScene.sks zdefiniuj bity kategorii oraz maski kontaktów i kolizji dla playera i zombies player: category Mask = 1 contact Mask, collision Mask = 2 player: category Mask = 2 contact Mask, collision Mask = 1 Gdy jakiś zombie dotknir playera: func didBeginContact(contact: SKPhysicsContact) { var a = contact.bodyA var b = contact.bodyB if a.categoryBitMask>b.categoryBitMask { swap(&a, &b) } // a ma mniejszą kategorię niż b if a.categoryBitMask==1 && b.categoryBitMask==2 { gameOver(0) } } func gameOver(result: Int) { exit(0) } Dodaj drzwi, aby gracz mógł uciec ze sceny. W GameScene.sks umieść Color Sprite texture: door, name door ustaw właściwości fizyczne: Body type: rectangle, Dynamic, Allow rotation, odznacz affected by gravity oraz: category Mask = 3 contact Mask, collision Mask = 1 Wyjście ze sceny W GameScene.swift zrób obiekt door, ustaw właściwości fizyczne: body type: Rectangle, odznacz (disable) dynamic, rotation, gravity. w klasie GameScene: var door: SKSpriteNode? we funkcji didMoveToView przypisz mu sprite’a ze sceny sks door = self.childNodeWithName("door") as? SKSpriteNode Uzupełnij funkcję obsługi kontaktu i funkcję gameOver: jeśli player dopadł drzwi, to zacznij grę od początku. func didBeginContact(contact: SKPhysicsContact) { var a = contact.bodyA var b = contact.bodyB if a.categoryBitMask>b.categoryBitMask { swap(&a, &b) } // a ma mniejszą kategorię niż b if a.categoryBitMask==1 && b.categoryBitMask==2 { gameOver(0) } if a.categoryBitMask==1 && b.categoryBitMask==3 { gameOver(1) } } func gameOver(result: Int) { if result == 0 { exit(0) } else { let s = GameScene(fileNamed: "GameScene") let t = SKTransition.flipHorizontalWithDuration(1) self.view?.presentScene(s!, transition: t) } } Scena wynikowa File / New / File / iOS Resource, SpriteKit Scene, name: MyScene, ustaw rozmiary: 320 x 480 umieść 2 labele: jeden na informację o wyniku, drugi: „dotknij mnie” File / New / File / Source file, Swift file, name: MyScene. import SpriteKit class MyScene: SKScene { var result: Int = 0 override func didMoveToView(view: SKView) { let lab = self.childNodeWithName("SKLabelNode_0") as? SKLabelNode if result==0 { self.backgroundColor = SKColor.blackColor() lab!.text = "jesteś martwy" } else { self.backgroundColor = SKColor.redColor() lab!.text = "żyjesz" } } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { let s = GameScene(fileNamed: "GameScene") let t = SKTransition.flipHorizontalWithDuration(1) self.view?.presentScene(s!, transition: t) } } Zmiana w Gamescene.swift func gameOver(result: Int) { let s = MyScene(fileNamed: "MyScene") s!.result = result let t = SKTransition.flipHorizontalWithDuration(1) self.view?.presentScene(s!, transition: t) } Dzwięki Muzyka w tle gry - przypisana do playera Player jako centrum nasłuchiwania innych dźwięków self.listener = player // w didMoveToView() Zombies jako źródła własnych dźwięków for child in self.children { // rozszerzenie w didMoveToView() if child.name == "zombie" { if let z = child as? SKSpriteNode { let glos = SKAudioNode(fileNamed: "moan.mp3") z.addChild(glos) Z.append(z) } } } Umieść obrazek podłogi sceny: Color Sprite / texture: background ważne: umieść podłogę zanim zaczniesz operować światłem, podłoga będzie odbijać światło. Światło Dodaj SKLightNode do playera, dokładnie na źródle jego światła, parent: player, aby światło podążalo za nim Falloff: 1,5 (wsp. zanikania światła) Sam obiekt SKLightNode jest niewidoczny, widoczne są tylko jego efekty w powiązaniu z innymi obiektami: rozpraszanie swiatła i cienie. W tym celu dla każdego obiektu na scenie określ: Lighting Mask: sprite odbija światło z otoczenia, Shadow Cast Mask: sprite rzuca cień, jeśli stoi na linii światła Shadowed Mask: określa swiatło sprita gdy sprite jest w cieniu, ale jest na pozycji z niższej od światła. Ustaw playerowi i wszystkim zombie wszystkie trzy maski na wartość 1. Ustaw dla sprite’a obrazka tła Lighting Mask = 1, a obie maski cienia na 0 (podłoga odbila światło, ale nie rzuca cienia) Kamera Widok na część sceny i przesuwanie zakresu widoku w ślad za graczem. Widoczny jest tylko fragment aktualnego poziomu, przez co gra staje się bardziej nieprzewidywalna, a więc ciekawsza. W GameScene.sks umieśc obiekt Camera nad playerem, name: camera, parent: SKScene_0 scale 0.5 dla x i y, (decyduje ile sceny jest widoczne) We właściwościach sceny ustaw tę kamerę. Aktualizacja pozycji kamery w funkcji update() klasy GameScene: override func update(currentTime: CFTimeInterval) { updatePlayer() updateZombies() if let c = self.camera { c.position = player.position } } Ściany Aby player i zombie nie wychodziły poza scenę, dodaj sprity z teksturą: wall, dopasuj ich położenie i wymiary, we właściwościach fizycznych ustaw: body type: Rectangle, odznacz (disable) dynamic, rotation, gravity. Na podstawie: https://www.raywenderlich.com/118225/introduction-sprite-kit-scene-editor