พล็อตโลก 3 มิติหลอก

Sep 06 2020

ฉันต้องการพล็อตโลกเล็ก ๆ ที่ตัวละครหลักสามารถเดินได้เหมือนกับ Sonic & Knukles Bonus Stage สำหรับผู้ที่จะไม่ google มันนี่เป็นภาพ

ฉันคุ้นเคยกับ Raycasting ซึ่งใช้ใน Wolfenstein และเกมอื่น ๆ เพื่อ "จำลอง" มุมมอง 3 มิติในแผนที่ 2 มิติ

แต่ฉันคิดไม่ออกว่าจะตั้งโปรแกรมโลกอย่างไรและฉันคิดว่ามันไม่ใช่การเรนเดอร์ 3 มิติจริงเนื่องจาก Sonic เป็นเกม 16 บิต

มีความคิดเกี่ยวกับวิธีการทำโดยไม่ใช้เอ็นจิ้น 3 มิติที่นุ่มนวลหรือไม่?

คำตอบ

1 Engineer Sep 06 2020 at 15:22

ภาพรวม

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

เครื่องบิน 3 มิติในแบบ 2 มิติ

สมมติว่าคุณมีเครื่องบินแบน 2x2 ที่แสดงผลบนหน้าจอของคุณเป็นสี่เหลี่ยม (ดูจากบนลงล่าง) และคุณสามารถเลื่อนไปมาได้ตามที่อธิบายไว้ข้างต้น

ตอนนี้เราจำเป็นต้องเปลี่ยนเครื่องบินเหล่านี้ (โดยรวม) โดยมองจากบนลงล่างเป็นมุมมองแบบเฉียงลงสู่พื้น

ทำได้ใน 2 ขั้นตอน:

  1. บีบระนาบกราวด์รวมเพื่อให้ครึ่งบน "บีบ" เข้ากับความกว้างของวิวพอร์ตและครึ่งล่างเกินความกว้างของวิวพอร์ต สิ่งนี้ทำได้โดยใช้yRatioตามที่คำนวณในส่วนโค้ดด้านล่างกล่าวคือยิ่งเราอยู่ใกล้ด้านบนมากเท่าไหร่เราก็จะยิ่งปรับขนาดมากขึ้นxเพื่อที่จะบีบด้านบนของสี่เหลี่ยมจัตุรัสให้ดูเหมือนเป็นรูปแห้วหรือสามเหลี่ยม
  2. ลดขนาดลงและจัดตำแหน่งใหม่เป็น y เพื่อให้ด้านล่างล้างด้วยด้านล่างของวิวพอร์ตและด้านบนคือ (พูด) ที่กึ่งกลางหน้าจอ - นี่คือขอบฟ้าของคุณ

ขั้นตอนทั้งสองนี้ขึ้นอยู่กับตำแหน่งที่ผู้เล่นกำลังยืนอยู่

ความโค้ง

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

semicircleDisplace(xCurrent)
{
    
    //formula to calculate maximal (horizon) yDisplacement from xCurrent
    //...
    
    return yDisplacement;
}

pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent);

ปัญหาของสิ่งนี้คือเราทำให้พิกเซลทั้งหมดนูนออกมาใกล้กับด้านล่างของหน้าจอมากที่สุดเท่าที่จะเป็นไปได้ใกล้ ๆ กับด้านบนซึ่งจะนำไปสู่การกลับหัว U มองไปยังภูมิประเทศเมื่อสิ่งที่เราต้องการจริงๆใกล้กับด้านล่างของ หน้าจอเป็นเส้นตรงเกือบ ตรงกลางบางส่วนกระจัด / กระพุ้ง; และที่ขอบฟ้าการกระจัดสูงสุด เราบรรลุสิ่งนี้ได้โดยใช้ปัจจัยสอดแทรก (อาจเป็นเชิงเส้น):

semicircleDisplace(xCurrent, yCurrent)
{
    
    //formula to calculate maximal (horizon) yDisplacement from xCurrent
    //...

    //linear interpolation based on where we are between bottom of screen and horizon
    yRange  = yMax - yMin
    yRatio  = yCurrent - yMin
    yFactor = yRatio / yRange

    return yDisplacement * yFactor;

}
pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent, yCurrent);

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