การแยกสถานะของโลกและแอนิเมชั่นในเกมพื้นฐาน


9

คุณจัดการกับการแยกอนิเมชั่นจากสภาวะโลกในเกมที่มีการเปิดได้อย่างไร? ฉันกำลังทำงานกับเกม 2D กริดในปัจจุบัน โค้ดด้านล่างนี้ง่ายต่อการอธิบายได้ดีขึ้น

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

สิ่งที่ฉันทำคือแนะนำภาพเคลื่อนไหวสองประเภทซึ่งฉันเรียกว่าการปิดกั้นภาพเคลื่อนไหวและภาพเคลื่อนไหวที่ไม่ปิดกั้น เมื่อผู้เล่นต้องการย้ายรหัสที่ถูกเรียกใช้งานคือ

class Actor {
    void move(PositionInfo oldPosition, PositionInfo newPosition) {
        if(isValidMove(oldPosition, newPosition) {
             getGame().pushBlockingAnimation(new MoveAnimation(this, oldPosition, newPosition, ....));
             player.setPosition(newPosition);
        }
    }
}

จากนั้นห่วงการอัพเดทหลักจะ:

class Game {
    void update(float dt) {
        updateNonBlockingAnimations(dt); //Effects like particle explosions, damage numbers, etc. Things that don't block the flow of turns.
        if(!mBlockingAnimations.empty()) {
            mBlockingAnimations.get(0).update(dt);
        } else {
             //.. handle the next turn. This is where new animations will be enqueued..//
        }
        cleanUpAnimations(); // remove finished animations
    }
}

... ที่ภาพเคลื่อนไหวจะอัพเดตตำแหน่งหน้าจอของนักแสดง

อีกแนวคิดหนึ่งที่ฉันใช้คือมีภาพเคลื่อนไหวการบล็อกพร้อมกันซึ่งภาพเคลื่อนไหวการบล็อกหลายรายการจะได้รับการอัปเดตพร้อมกัน แต่การเปิดครั้งต่อไปจะไม่เกิดขึ้นจนกว่าจะเสร็จทั้งหมด

สิ่งนี้ดูเหมือนเป็นวิธีที่มีเหตุผลในการทำสิ่งต่างๆหรือไม่? ไม่มีใครมีข้อเสนอแนะใด ๆ หรือแม้กระทั่งการอ้างอิงถึงวิธีการที่เกมอื่นที่คล้ายคลึงกันทำสิ่งนั้น

คำตอบ:


2

หากระบบของคุณเหมาะกับคุณฉันไม่เห็นเหตุผลที่จะไม่ทำเช่นนั้น

เหตุผลข้อหนึ่ง: มันอาจยุ่งเหยิงเมื่อคุณไม่สามารถตัดสินผลของ "ผู้เล่น setPosition (newPosition)" ได้อย่างง่ายดาย อีกต่อไป

ตัวอย่าง (เพิ่งทำสิ่งต่าง ๆ ): จินตนาการว่าคุณย้ายผู้เล่นด้วย setPosition ของคุณที่ด้านบนของกับดัก การเรียกไปที่ "player.setPosition" นั้นจะทำให้บางคนเรียกไปที่ .. พูดว่ารหัสฟังกับดักซึ่งจะผลักดันภาพเคลื่อนไหวการปิดกั้นด้วยตัวเองที่แสดง "ทำร้ายสาด" ด้านบนของตัวเอง

คุณเห็นปัญหา: สแปลชจะแสดงขึ้นพร้อมกันโดยย้ายผู้เล่นเข้าหากับดัก (สมมติว่าคุณไม่ต้องการสิ่งนี้ แต่ต้องการให้แอนิเมชั่นแทร็พเล่นหลังจากการย้ายเสร็จสิ้น))

ดังนั้นตราบใดที่คุณสามารถรักษาผลที่ตามมาจากการกระทำของคุณไว้ในใจที่คุณทำหลังจากการเรียก "pushBlockingAnimation" ทุกอย่างก็ใช้ได้

คุณอาจต้องเริ่มล้อมตรรกะของเกมเป็น "บล็อกบางอย่าง" - คลาสเพื่อให้พวกเขาสามารถเข้าคิวเพื่อดำเนินการหลังจากที่ภาพเคลื่อนไหวเสร็จสิ้น หรือคุณส่งการเรียก "callThisAfterAnimationFinishes" กลับไปที่ pushBlockingAnimation แล้วย้าย setPosition ไปยังฟังก์ชันการเรียกกลับ

อีกวิธีคือภาษาสคริปต์ ตัวอย่างเช่น Lua มี "coroutine.yield" ซึ่งส่งคืนฟังก์ชันด้วยสถานะพิเศษดังนั้นจึงสามารถเรียกใช้ในภายหลังเพื่อดำเนินการต่อที่คำสั่งถัดไป วิธีนี้คุณสามารถรอให้จุดสิ้นสุดของอนิเมชั่นดำเนินการตรรกะของเกมได้อย่างง่ายดายโดยไม่เกะกะการไหลของโปรแกรม "ปกติ" ในโค้ดของคุณ (หมายถึงรหัสของคุณจะยังคงมีลักษณะเช่น "playAnimation (); setPosition ();" แทนที่จะส่งการเรียกกลับไปรอบ ๆ

Unity3D (และอย่างน้อยหนึ่งระบบเกมอื่นที่ฉันรู้จัก) แสดงคำสั่ง C # "return return" เพื่อจำลองสิ่งนี้โดยตรงในรหัส C #

// instead of simple call to move(), you have to "iterate" it in a foreach-like loop
IEnumerable<Updatable> move(...) {
    // playAnimation returns an object that contain an update() and finished() method.
    // the caller will not iterate over move() again until the object is "finished"
    yield return getGame().playAnimation(...)
    // the next statement will be executed *after* the animation finished
    player.setPosition(newPosition);
}

แน่นอนในรูปแบบนี้การเรียกร้องให้ย้าย () ได้รับงานสกปรกทั้งหมดในขณะนี้ คุณอาจจะใช้เทคนิคนี้เฉพาะฟังก์ชั่นเฉพาะที่คุณรู้ว่าใครโทรมาจากที่ใด ดังนั้นให้ใช้แนวคิดนี้เป็นเพียงแนวคิดพื้นฐานในการจัดเรียงเครื่องมืออื่น ๆ ซึ่งอาจเป็นวิธีที่ซับซ้อนเกินไปสำหรับปัญหาเฉพาะของคุณในปัจจุบัน

ฉันแนะนำให้คุณใช้แนวคิด pushBlockingAnimation ของคุณจนกว่าคุณจะมีปัญหาในโลกแห่งความจริง จากนั้นแก้ไขมัน ;)


ขอบคุณมากที่สละเวลาเขียนคำตอบนี้ฉันซาบซึ้งจริงๆ
mdkess
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.