พัฒนาเกมลง iOS ด้วย Swift และ SpriteKit ตอนที่ 5 การใช้ SKAction.move
สำหรับบทความตอนนี้จะพูดถึงการใช้ SKAction.move เพื่อที่จะให้ภาพเคลื่อนที่ไปยังจุดต่าง ๆ ที่เรากำหนด
ใน SpriteKit จะมีคลาส SKAction ซึ่งเก็บรวบรวมฟังก์ชันที่ทำหน้าที่ในการเปลี่ยนแปลงโครงสร้างหรือคุณสมบัติของโหนดที่อยู่ในซีน ซึ่งฟังก์ชัน move เป็นหนึ่งในฟังก์ชันที่อยู่ใน SKAction โดยทำหน้าที่ในการทำให้โหนดหรือวัตถุนั้น ๆ เคลื่อนที่ไปยังตำแหน่งใหม่
เรามาเริ่มต้นเรียนรู้การใช้ SKAction.move โดยเริ่มต้นสร้างโปรเจคชื่อ ActionMove ดังรูปที่ 1
รูปที่ 1 สร้างโปรเจค ActionMove
จากนั้นเลือกไฟล์ GameScene.swift เพื่อทำการลบคำสั่งเดิมที่มีมาให้จากการสร้างโปรเจคเริ่มต้น โดยลบคำสั่งออกให้เหลือเฉพาะฟังก์ชัน didMove() ดังรูปที่ 2
รูปที่ 2 ลบคำสั่งใน GameScene.swift
จากนั้นเลือกไฟล์ GameScene.sks เพื่อลบ hellolabel ออก และปรับค่า Anchor Point เป็น (0,0) และปรับขนาดตามต้องการ ตัวอย่างดังรูปที่ 3
รูปที่ 3 ตั้งค่า SpriteKit Scene
จากนั้นโหลดรูป spaceship.png ซึ่งเป็นรูปที่แถมมากับ Xcode ในเวอร์ชันเก่า ๆ ก่อนหน้านี้
จากนั้นนำรูป spaceship.png ไปใส่ในใน Assets.xcassets ดังรูปที่ 4
รูปที่ 4 นำรูป spaceship เข้า Assets
จากนั้นกลับมาที่ไฟล์ GameScene.swift เพื่อเขียนคำสั่งแสดงรูป spaceship.png บนหน้าจอ (เหมือนบทความตอนที่ 4) โดยเพิ่มคำสั่งบรรทัดที่ 14 และบรรทัดที่ 17-20 ดังนี้
//
// GameScene.swift
// ActionMove
//
// Created by Aj.Montri on 21/12/2560 BE.
// Copyright © 2560 SOFTZOL. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var spaceship: SKSpriteNode!
override func didMove(to view: SKView) {
spaceship = SKSpriteNode(imageNamed: "spaceship")
spaceship.position = CGPoint(x: size.width/2, y: size.height/2)
spaceship.setScale(0.3)
addChild(spaceship)
}
}
จากข้างต้นบรรทัดที่ 19 : spaceship.setScale(0.3) เป็นคำสั่งสำหรับย่อส่วนภาพให้มีขนาด 0.3 เท่า เนื่องจากถ้าไม่ย่อส่วน ภาพจะมีขนาดเกือบเต็มจอซึ่งใหญ่เกินไป
ต่อไปเราจะทำให้ภาพเคลื่อนที่โดยใช้ SKAction.move
โดยในตัวอย่างเริ่มต้นนี้ขอใช้เป็นการเคลื่อนที่ของภาพ spaceship ไปยังตำแหน่งที่ทัช หรือตำแหน่งที่นิ้วสัมผัสหน้าจอนั่นเอง
ดังนั้นก่อนอื่นเราต้องสร้าง event เพื่อรับเหตุการณ์เมื่อนิ้วเริ่มทัชที่หน้าจอ โดยใช้ overide func touchesBegan(…) และเก็บค่าตำแหน่ง (x,y) ที่นิ้วทัช เพื่อที่จะให้เป็นตำแหน่งปลายทางที่รูปเคลื่อนที่ไป
สำหรับ SKAction.move จะมี 2 รูปแบบหลัก ๆ คือ move…to กับ move…by
แบบแรก move…to มีรูปแบบ ดังนี้
SKAction.move(to: CGPoint, duration: TimeInterval)
ซึ่งพารามิเตอร์ to จะรอรับตำแหน่งปลายทางที่ต้องการไปถึง
ส่วนพารามิเตอร์ duration จะรอรับค่าเวลาที่ใช้สำหรับเคลื่อนที่จากจุดเริ่มต้นไปยังจุดปลายทาง
ซึ่งตัวอย่างการใช้ดังคำสั่งบรรทัดที่ 23-30 ดังนี้
//
// GameScene.swift
// ActionMove
//
// Created by Aj.Montri on 21/12/2560 BE.
// Copyright © 2560 SOFTZOL. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var spaceship: SKSpriteNode!
override func didMove(to view: SKView) {
spaceship = SKSpriteNode(imageNamed: "spaceship")
spaceship.position = CGPoint(x: size.width/2, y: size.height/2)
spaceship.setScale(0.3)
addChild(spaceship)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else{
return
}
let location = touch.location(in: self)
let moveAction = SKAction.move(to: location, duration: 1.0)
spaceship.run(moveAction)
}
}
เมื่อรันโปรเจคแล้วให้ลองทัช (หรือคลิ๊ก ถ้ารันบน Simulator) จะพบว่าภาพ space ship จะเคลื่อนที่ไปยังตำแหน่งนั้น ดังรูปที่ 5
รูปที่ 5 ผลจากการรัน
ทีนี้เรามาลองแบบที่ 2 ก็ดูบ้าง นั่นก็คือ move…by ซึ่งการใช้จะมีรูปแบบ ดังนี้
SKAction.move(by: CGVector, duration: TimeInterval)
ตัวอย่างเช่น
let moveByAction = SKAction.move(by: CGVector(dx: 100.0, dy: 200.0), duration: 1.0)
คำสั่งข้างต้น หมายถึง การให้วัตถุขยับแกน x ไป 100 points และขยับแกน y ไป 200 point โดยใช้เวลา 1 วินาที นั่นเอง
จากทั้ง 2 ตัวอย่างข้างต้น จะเห็นว่า การเคลื่อนที่ของภาพ ไม่ว่าจะไกล หรือใกล้ จะใช้เวลาเท่ากัน ทำให้ความเร็วในการเคลื่อนที่ของภาพ ช้าบ้าง เร็วบ้าง ความเร็วไม่คงที่
ดังนั้นหากเราต้องการให้ภาพเคลื่อนที่ด้วยความเร็วคงที่ ไม่ว่าตำแหน่งปลายทางจะใกล้หรือไกล เราจึงต้องคำนวณเวลาก่อน เพื่อให้ภาพเคลื่อนที่ไปยังปลายทางด้วยความเร็วคงที่
หลักการคือ ต้องหาระยะทางจากจุดเริ่มต้นไปยังปลายทาง เราจะใช้ทฤษฎีพีทากอรัส
ระยะทาง = square root ( (x2-x1)^2 + (y2-y1)^2)
จากนั้นหาเวลาได้จาก สมการ
เวลาเดินทาง = ระยะทาง / ความเร็ว
เราสามารถเขียนเป็นคำสั่งได้ ดังนี้
//
// GameScene.swift
// ActionMove
//
// Created by Aj.Montri on 21/12/2560 BE.
// Copyright © 2560 SOFTZOL. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var spaceship: SKSpriteNode!
override func didMove(to view: SKView) {
spaceship = SKSpriteNode(imageNamed: "spaceship")
spaceship.position = CGPoint(x: size.width/2, y: size.height/2)
spaceship.setScale(0.3)
addChild(spaceship)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else{
return
}
let location = touch.location(in: self)
let velocity = size.width/2.0
let moveDiff = CGPoint(x: location.x - spaceship.position.x, y: location.y-spaceship.position.y)
let distance = sqrt(moveDiff.x * moveDiff.x + moveDiff.y*moveDiff.y)
let moveDuration = distance / velocity
let moveAction = SKAction.move(to: location, duration: Double(moveDuration))
spaceship.run(moveAction)
}
}
จากนั้นก็ลองรันดู จะพบว่าภาพเคลื่อนที่ด้วยความเร็วคงที่
วิดีโอประกอบบทความ
Aj.Montri