วิธีการผูกกระสุนด้วยภาพเคลื่อนไหวการยิง


15

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

แก้ไข: ฉันคิดว่าฉันมีปัญหาในการใช้ถ้อยคำคำถามอย่างถูกต้อง

คำถามของฉัน


ขอบคุณ! ความคิดดีๆจากคุณทุกคนฉันชอบความคิดในการใช้โทรกลับ ฉันคิดว่าฉันจะลองและนำไปใช้จริง ๆ ฉันไม่ต้องการพึ่งพาการติดตามเวลา
tp0w3rn

คำตอบ:


8

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

แนวทางที่ยืดหยุ่นคือการใช้คำจำกัดความของภาพเคลื่อนไหวเพื่อสรุปข้อมูลประเภทนี้ ดังนั้นแทนที่จะเพียงแค่พูดว่า "ภาพเคลื่อนไหว X เป็นเฟรมเหล่านี้ทั้งหมดเพียงแค่เล่นผ่านมัน" คุณจะได้รับบางสิ่งที่ซับซ้อนกว่านี้

เช่นกับรูปแบบข้อมูลที่เยาะเย้ย

แอนิเมชั่น =
{
  {name = "walk", files = "walk * .png", frameCount = "12", loop = "true"},
  {name = "fire" ไฟล์ = "fire * .png" frameCount = "6",
       เหตุการณ์ = {
           {name = "bulletLeavesGun", frame = "4", param1 = "43", param2 = "30"}
       }
  }
}

ดังนั้นรหัสของคุณพูดว่า:

currentAnimation = animations.Get("fire");
currentAnimation.Play();

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

List<Event> events = currentAnimation.EventsSinceLastCheck();
foreach (AnimationEvent event in events)
{
    if (event.name == "bulletLeavesGun")
    {
        Vector2 bulletPosition = new Vector2(event.param1, event.param2);
        Vector2 actualBulletPosition = new Vector2(
                 character.x + bulletPosition.x, 
                 character.y + bulletPosition.y);
        CreateBulletAt(actualBulletPosition);
    }
}

จุดที่ควรทราบ:

  • รหัสภาพเคลื่อนไหวควรมีอยู่แยกต่างหากจากรหัสเกม คุณไม่ต้องการให้รหัสการเล่นของคุณผูกติดแน่นเกินไปกับการเล่นภาพเคลื่อนไหว
  • รหัสภาพเคลื่อนไหวรู้ว่าจะวนซ้ำตามนิยามของภาพเคลื่อนไหวหรือไม่
  • รหัสภาพเคลื่อนไหวรู้ว่าเมื่อทำภาพเคลื่อนไหวแล้วและสามารถโทรกลับไปที่รหัสอื่นเพื่อบอกว่า 'เดี๋ยวก่อนภาพเคลื่อนไหวที่เรียกว่า "ไฟ" เพิ่งเสร็จสิ้นคุณต้องการทำอะไรในตอนนี้
  • รหัสภาพเคลื่อนไหวไม่ทราบอะไรเกี่ยวกับเหตุการณ์อื่นนอกจากว่าพวกเขามีชื่อและข้อมูลบางอย่างที่เกี่ยวข้องกับพวกเขา (param1 และ param2)
  • รหัสภาพเคลื่อนไหวรู้ว่าตอนนี้เฟรมเปิดอยู่และเมื่อเปลี่ยนเป็นเฟรมใหม่มันสามารถตรวจสอบและพูดว่า 'โอ้ตอนนี้ฉันอยู่ที่เฟรม 4 แล้วนั่นหมายความว่าเหตุการณ์นี้เรียกว่า "ไฟ" เพิ่งเกิดขึ้นเพิ่มไปที่ รายการเหตุการณ์ล่าสุดของฉันดังนั้นฉันสามารถบอกใครก็ได้ที่ถามเกี่ยวกับมัน '

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


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

การแยกภาพเคลื่อนไหวออกเป็นชิ้น ๆ ดูเหมือนไม่จำเป็นเลย ฉันจะเห็นด้วยกับการไม่สำรวจสถานะภาพเคลื่อนไหว แต่ยังคงทิ้งคำแนะนำแรกไว้ ฉันไม่รู้ว่าเขาหมายถึงระบบเหตุการณ์แยกต่างหากเพื่อแยกรหัสภาพเคลื่อนไหวออกจากส่วนที่เหลือของเกม (รูปแบบการสังเกตการณ์) หรือไม่ แต่นั่นเป็นวิธีที่ฉันทำ ทั้ง "logics" ตามที่คุณควรรู้เกี่ยวกับรหัสภาพเคลื่อนไหวหรือในทางกลับกัน
jhocking

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

@ โคโยตี้ (ต่อ ... ) การเล่นเกมสามารถขับเคลื่อนโดยเซิร์ฟเวอร์แยกออกจากภาพ ดังนั้นกระสุนจึงถูกยิงในเวลาที่ X บนเซิร์ฟเวอร์และลูกค้าสะท้อนให้เห็นการกระทำนั้นโดยเริ่มเล่นภาพเคลื่อนไหวไฟทันทีด้วยกระสุนที่ยิงด้วยแสงซึ่งปกคลุมด้วยกรอบไม่กี่หลังการจำลองการเล่นเกมกระสุน การประนีประนอมทุกรูปแบบจำเป็นต้องทำขึ้นมาระหว่างความเที่ยงตรงของภาพและการจำลองการเล่นเกมดังนั้นเพื่อกล่าวว่า "ภาพเคลื่อนไหวควรจะตาบอดและเป็นใบ้" นั้นไร้เดียงสา บางครั้งเหตุการณ์จำเป็นต้องเชื่อมโยงกับเฟรมภาพเคลื่อนไหวเพราะไม่มีวิธีอื่นที่จะทำให้ดูหรือถูกต้อง
MrCranky

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

3

ในบางวิธีคุณจะต้องรอจนกว่าภาพเคลื่อนไหวจะเสร็จสิ้นและสร้างสัญลักษณ์แสดงหัวข้อ ณ จุดนั้น

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

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


1
addAnimationCallbackวิธีการของ Flixel สามารถใช้ได้กับเอนทิตีของการยิง ในฟังก์ชั่นการโทรกลับคุณสามารถดูว่าเฟรมปัจจุบันของภาพเคลื่อนไหวการยิงเป็นเฟรมที่ควรสร้างเอนทิตีกระสุนหรือไม่ ถ้าเป็นเช่นนั้นคุณสามารถเพิ่มสัญลักษณ์แสดงหัวข้อย่อยบนหน้าจอ
Snow Blind

2

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

คำตอบการออกแบบเกมสำรอง: หากไม่มีเหตุผลที่ดีจริงๆให้ทำฉันจะหลีกเลี่ยงความล่าช้าจากการกดปุ่ม 'fire' และมีสัญลักษณ์แสดงหัวข้อย่อย เว้นแต่ว่าภาพเคลื่อนไหวจะสั้นจริงๆ (หนึ่งหรือสองเฟรม, สูงสุด, โดยทั่วไปแล้วเป็นตะกร้อแฟลช), มันจะทำให้การตอบสนองของปุ่มไฟช้าลงและมันจะสร้างความรำคาญให้กับผู้เล่นทั่วไป แม้ว่าคุณจะตัดสินใจที่จะใช้แอนิเมชั่นก่อนที่กระสุนจะออกมา (เทิร์นอาร์พีจีและเกมทางยุทธวิธีจะเป็นเหตุผลที่ยอมรับได้ในการทำเช่นนี้) ฉันคิดว่าจะรวมถึงตัวเลือก "ปิดภาพเคลื่อนไหว" เพื่อให้ เกมที่จะเคลื่อนที่เร็วขึ้นหากผู้เล่นต้องการ


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

2

อย่างที่ MrCranky พูด; แยกนิเมชั่นและ logics ออกจากกัน

แต่ที่สำคัญที่สุดlogics จะต้องยังคงอยู่ในส่วนหลัก

  • เมื่อกดปุ่มไฟคุณควรเปิด " การกระทำ " เสมอในสถานะตัวละครของคุณ (logics)
  • การดำเนินการนี้ควรกระตุ้นให้แอนิเมชั่นรูปวาดที่มีพารามิเตอร์ทั้งหมด (เวลาอยู่เป็นต้น)
  • เมื่อวาดดำเนินการเสร็จเรียบร้อยแล้วคุณสามารถเรียกไฟกระทำ (สามารถยิงหนึ่งครั้งหรือมากกว่านั้นขึ้นอยู่กับอาวุธ)
  • การดำเนินการนี้สามารถสร้างกระสุนและก่อให้เกิดไฟไหม้นิเมชั่น

โปรดทราบว่าการควบคุม UI จาก logics เป็นวิธีเดียวที่จะทำให้แน่ใจว่าคุณจะสามารถนำมาใช้ซ้ำและแบ่งปัน logics ของคุณได้ในภายหลัง (renderer ใหม่เกมใหม่เวอร์ชันเซิร์ฟเวอร์โดยไม่มี renderer ... )


1

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

ตอนนี้รหัสภาพเคลื่อนไหวต้องมีการอ้างอิงจริงกับตัวแจกจ่ายเหตุการณ์ (ทำได้อย่างง่ายดายด้วยการฉีดพึ่งพา) และคุณต้องมี XML หรือ JSON บางตัวที่กำหนดภาพเคลื่อนไหวของคุณ สิ่งที่ต้องการ:

{
  animation: {
    name: shoot,
    length: 12,
    spritesheet: shoot.png
    event: {
      frame: 4,
      name: bulletLeavesGun,
    },
  },
}

อ่านข้อมูลเมื่อโหลดภาพเคลื่อนไหวและให้รหัสภาพเคลื่อนไหวส่งเหตุการณ์เมื่ออยู่ในเฟรมนั้นระหว่างการเล่น

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