ศัตรูได้รับความเสียหายหลายครั้ง - Swift, Xcode 8.2.1

ฉันกำลังอยู่ในขั้นตอนการสร้างเกมสไตล์ Space Invaders และอยากจะสร้างให้ศัตรูต้องถูกโจมตีสามครั้งก่อนจะระเบิด

บทช่วยสอนที่ฉันใช้แสดงเฉพาะวิธีทำให้ศัตรูระเบิดหลังจากโจมตีเพียงครั้งเดียว มันใช้ฟังก์ชันที่เรียกว่า didBegin(_ contact: SKPhysicsContact)

https://www.youtube.com/watch?v=F0kcw6eryJs&t=617s

จากความเข้าใจของฉัน ฟังก์ชันนี้ประเมินแต่ละกรณีของการติดต่อ กำหนดบทบาทที่แตกต่างกันสองส่วนให้กับสองส่วน จากนั้นจึงตัดสินใจว่าจะทำอย่างไรกับแต่ละส่วน ฉันถือว่าศัตรูได้รับการโจมตีสามครั้ง ตัวแปรที่มีพลังชีวิตที่เหลืออยู่จะถูกนำมาใช้ จากนั้น เมื่อมีการสัมผัสกันแต่ละครั้ง ตัวแปรจะลดลงทีละตัว จนกระทั่งถ้าเป็นศูนย์ ศัตรูจะถูกกำจัดออกไป

อย่างไรก็ตาม มีปัญหาลึกในเรื่องนี้ เนื่องจากdidBegin(_ contact: SKPhysicsContact) ประเมินอินสแตนซ์ของการติดต่อเพียงรายการเดียว จึงไม่มีความรู้เกี่ยวกับอินสแตนซ์อื่นๆ ของการติดต่อก่อนหน้านี้ โดยพื้นฐานแล้ว เมื่อศัตรูถูกโจมตี ไม่มีทางรู้ได้เลยว่าศัตรูถูกโจมตีมาก่อน ไม่เคยถูกโจมตีเลย หรือถูกโจมตีหลายครั้งเกินไป หากมีศัตรูเพียงตัวเดียว ฉันสามารถใช้ตัวแปรตัวเดียวเพื่อติดตามสุขภาพของมัน แต่จะไม่เป็นเช่นนั้น เนื่องจากมีศัตรูหลายรายบนหน้าจอพร้อมกัน และทุกครั้งที่มีการติดต่อ จึงไม่มีทางรู้ได้ว่าการโจมตีครั้งก่อนเป็นศัตรูรายนี้หรือศัตรูรายอื่น

หากมีศัตรูหนึ่งตัวบนหน้าจอ มันง่ายเพราะทุกครั้งที่มีการติดต่อ ศัตรูนั้นจะต้องเป็นศัตรูตัวนั้น แต่ถ้ามีหลายเอนทิตีบนหน้าจอ ก็ไม่มีทางรู้ได้เลยว่าผู้ติดต่อรายใดที่นำไปใช้กับศัตรู

ฉันเชื่อว่าสิ่งนี้จะต้องมีการระบุตัวตนของศัตรูแต่ละราย แม้ว่าฉันจะไม่แน่ใจว่าจะทำอย่างไร สำหรับผู้ที่อ่าน ฉันขอขอบคุณมากที่แวะมา และฉันรู้สึกขอบคุณมากหากคุณสามารถช่วยได้


person cTem    schedule 06.06.2018    source แหล่งที่มา


คำตอบ (2)


ไม่จำเป็นต้องแยกพจนานุกรมเพื่อติดตามสถานะของสไปรท์

SKNode ทุกตัวมี userData และคุณสามารถติดตามชีวิตของศัตรูได้ด้วยมัน

ตัวอย่าง:

let invader = SKSpriteNode(imageNamed:"invader")
invader.userData = ["health":3]

...


func didBeginContact(...)
{
...
  //when a contact happens
    contact.body_.node.userData["health"] -= 1
...
}

โปรดจำไว้ว่า กระสุน 1 นัดสามารถโจมตีศัตรู 1 คนได้สองครั้ง คุณคงไม่อยากทำให้เกิดการสูญเสียชีวิต 2 ครั้งที่นี่ ดังนั้นคุณจะต้องมีตัวแปรชั่วคราว (ซึ่งคุณสามารถบันทึกไว้ในข้อมูลผู้ใช้ได้ด้วย) ที่จะแจ้งให้คุณทราบว่าสัญลักษณ์แสดงหัวข้อย่อยได้ติดต่อกับผู้บุกรุกแล้วหรือไม่

person Knight0fDragon    schedule 06.06.2018
comment
ขอบคุณมากสำหรับสิ่งนี้! ฉันสงสัยว่าใน func didBeginContact การจัดรูปแบบที่แน่นอนสำหรับการหักความสมบูรณ์ของตัวแปรคืออะไร เมื่อคุณอ้างถึง body_ คุณหมายถึง bodyA หรือ bodyB หรือฉันควรทดสอบทั้งสองอย่าง ดังที่กล่าวไว้ว่า SKPhysicsContact ไม่มีเนื้อหาสมาชิก นอกจากนี้เมื่อพยายามหักหนึ่งก็ให้ข้อผิดพลาด Binary operator '-=' cannot be applied to operands of type 'Any?' and 'Int' สิ่งนี้ทำให้เกิดความสับสน เนื่องจากดูเหมือนว่าประเภท Int สามารถใช้งานได้ ขอขอบคุณอีกครั้งสำหรับความช่วยเหลือของคุณ - person cTem; 07.06.2018
comment
Body_ คือร่างกายใดก็ตามที่ผู้บุกรุกของคุณเป็น หมวดหมู่ก็จะบอกคุณว่า - person Knight0fDragon; 07.06.2018

คุณพูดถูก คุณจำเป็นต้องติดตามศัตรูและสุขภาพของพวกเขาด้วยตัวเอง อาจมีหลายวิธีที่จะทำได้ แต่นี่เป็นวิธีหนึ่งในการบรรลุเป้าหมายของคุณ:

ใช้พจนานุกรมของศัตรูกับสุขภาพของพวกเขา ศัตรูทุกคนจะได้รับรหัสประจำตัวเพื่อระบุตัวพวกเขา สุขภาพสามารถแสดงเป็น Int พจนานุกรมนี้ยังสามารถใช้เพื่อบอกจำนวนศัตรูที่ยังคงอยู่รอบๆ ได้อย่างง่ายดาย

var enemyHealth = [String:Int]()

โหนดมีคุณสมบัติชื่อที่คุณสามารถตั้งค่าสตริงใดก็ได้ นี่คือวิธีที่คุณจะสามารถระบุโหนดของคุณได้ เมื่อสร้างศัตรู คุณจะต้องสร้างรหัส (เช่น การสร้างตัวเลขสุ่ม) ตั้งชื่อโหนดเป็นรหัส และเพิ่มศัตรูลงในพจนานุกรม enemyHealth ด้วยค่าสุขภาพเริ่มต้น

let enemyNode = SKSpriteNode(color: UIColor.white, size: CGSize.zero)
let enemyId = "\(arc4random())"
enemyNode.name = enemyId
enemyHealth[enemyId] = 10
...

ใน didBegin(_ contact: SKPhysicsContact) คุณสามารถเข้าถึงโหนดที่เกี่ยวข้องในการชนกันโดยใช้พารามิเตอร์การติดต่อของฟังก์ชัน (contact.bodyA.node หรือ contact.bodyB.node) ด้วยการเปรียบเทียบชื่อของโหนดกับคีย์ใน enemyHealth คุณจะทราบได้ว่าตัวการชนกันตัวใดที่เป็นศัตรูและสุขภาพของมันเป็นอย่างไร

let enemy:SKSpriteNode

if enemyHealth.keys.contains(contact.bodyA.node?.name ?? "") {
    enemy = contact.bodyA.node as! SKSpriteNode

} else if enemyHealth.keys.contains(contact.bodyB.node?.name ?? "") {
    enemy = contact.bodyB.node as! SKSpriteNode
} else {
    return  //none of the collision partners are an enemy
}

let health = enemyHealth[enemy.name!]!
...

ตอนนี้คุณสามารถทำทุกอย่างที่คุณต้องการกับศัตรู เมื่อศัตรูถูกฆ่า/กำจัด ให้ลบออกจากพจนานุกรม enemyHealth ด้วย

person Christoph    schedule 06.06.2018