Unity - วิธีเคลื่อนย้ายเรือไปยังจุดที่สมจริงในเกมบนลงล่าง 2D


14

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

ฉันจะดีใจถ้ามีคนช่วยฉันด้วยปัญหานี้ขอบคุณ การเคลื่อนไหวของเรือ


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

เพิ่มเติมไปยังจุดที่มีเหตุผลมองการเคลื่อนไหวของการแล่นเรือใบเรือจริงๆต้องสละลมเข้าบัญชี; การเพิกเฉยมันจะเหมือนกับการเพิกเฉยต่อแรงโน้มถ่วงเมื่อทำการกระโดด คุณไม่จำเป็นต้องมีแบบจำลองของลมที่มีรายละเอียดเป็นพิเศษ แต่คุณต้องจำไว้ว่าเรือของคุณถูกลมพัดผ่านใบเรือของคุณ (และน้ำกับกระดูกงูและหางเสือ) โดยเฉพาะอย่างยิ่งเรือไม่สามารถแล่นเรือที่อยู่เหนือลมได้โดยตรง พวกเขาจะต้องเอาชนะทางที่นั่นแทน
Ilmari Karonen

ตามปกติ "จุดข้าม" สามารถแบ่งออกเป็นเฟสการหมุนและเฟสการเคลื่อนที่ไปข้างหน้า ใช้ aproach เดียวกัน แต่กำหนดให้การหมุนเป็นการเคลื่อนที่ไปข้างหน้า ตัวอย่างแต่ละ x rad ของการหมุนเลื่อนเรือไปข้างหน้าของ y meters
dnk drone.vs.drones

คำตอบ:


7

ดูหน้านี้

การเพิ่มเทิร์นสมจริง

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

สำหรับวิธีแก้ปัญหาที่ดีกว่าสิ่งแรกที่เราต้องรู้คือรัศมีวงเลี้ยวสำหรับหน่วยของเรา รัศมีวงเลี้ยวเป็นแนวคิดที่เรียบง่าย: ถ้าคุณอยู่ในลานจอดรถขนาดใหญ่ในรถของคุณและหมุนวงล้อไปทางซ้ายเท่าที่มันจะไปและขับรถเป็นวงกลมรัศมีของวงกลมนั้นคือการเลี้ยวของคุณ รัศมี. รัศมีวงเลี้ยวของ Volkswagen Beetle จะเล็กกว่า SUV ขนาดใหญ่อย่างมากและรัศมีวงเลี้ยวของคนจะน้อยกว่าของหมีตัวใหญ่

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

ในรูปที่ 5 เส้นทางที่สั้นที่สุดคือเส้นสีเขียวที่ด้านล่างอย่างชัดเจน เส้นทางนี้ค่อนข้างตรงไปตรงมาในการคำนวณเนื่องจากความสัมพันธ์ทางเรขาคณิตบางอย่างแสดงในรูปที่ 6

รูปที่ 6: การคำนวณความยาวของเส้นทาง

อันดับแรกเราคำนวณตำแหน่งของจุด P ซึ่งเป็นศูนย์กลางของวงเลี้ยวของเราและรัศมีอยู่ห่างจากจุดเริ่มต้นเสมอ หากเราเลี้ยวขวาจากทิศทางเริ่มต้นของเรานั่นหมายความว่า P อยู่ในมุมของ (initial_direction - 90) จากจุดกำเนิดดังนั้น:

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

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

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

ณ จุดนี้เราต้องการตรวจสอบว่าปลายทางไม่อยู่ในวงกลมเพราะถ้าเป็นเช่นนั้นเราไม่สามารถไปถึงได้:

if (h < r)
    return false

ทีนี้เราสามารถคำนวณความยาวของเซกเมนต์ d เนื่องจากเราทราบความยาวของอีกสองด้านของสามเหลี่ยมมุมฉากนั่นคือ h และ r เราสามารถกำหนดมุมจากความสัมพันธ์สามเหลี่ยมมุมฉาก:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

ในที่สุดหากต้องการหาจุด Q ที่จะออกจากวงกลมและเริ่มต้นบนเส้นตรงเราจำเป็นต้องรู้มุมทั้งหมด + และกำหนดได้ง่ายเช่นมุมจาก P ถึงปลายทาง:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

การคำนวณข้างต้นแสดงถึงเส้นทางเลี้ยวขวา เส้นทางซ้ายมือสามารถคำนวณได้ในลักษณะเดียวกันยกเว้นว่าเราเพิ่ม 90 ลงใน initial_direction สำหรับการคำนวณ angleToP และหลังจากนั้นเราจะใช้ - แทน + หลังจากการคำนวณทั้งสองเราจะเห็นเส้นทางที่สั้นกว่าและใช้เส้นทางนั้น

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

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

รายการ 2.คำนวณตำแหน่งและทิศทางในเวลาที่ต้องการ

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length

4
คำตอบนี้ไม่ได้มองเข้าไปในฟิสิกส์ของเรือ ฉันยังพบว่ามีปัญหาว่าเป็นลิงก์ไปยังและข้อความที่ตัดตอนมายาวจากเว็บไซต์อื่น (ฉันไม่แน่ใจเกี่ยวกับกฎหมาย)
ไม่มีใคร

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

3
@ Draco18s: สิ่งที่คุณควรทำคือสรุปประเด็นสำคัญของเนื้อหาที่เชื่อมโยงด้วยคำพูดของคุณเอง (หรือดีกว่าตอบคำถามตามประสบการณ์ของคุณและใช้ลิงก์เป็นสื่อประกอบการสอนหรือเพื่อการอ่านเพิ่มเติม) โดยทั่วไปคำพูดสั้น ๆ ก็โอเคโดยเฉพาะอย่างยิ่งในสถานการณ์ที่ไม่สามารถหลีกเลี่ยงได้จริง ๆ (เช่นอ้างถึงคำพูดของใครบางคน คำที่จะแสดงให้เห็นว่าพวกเขาจริงๆพูดอะไรบางอย่าง) แต่อ้างเป็นรูปธรรมส่วนของบทความที่เป็นจริงที่จะเกินการใช้งานยุติธรรม
Ilmari Karonen

หากจุดอยู่ในวงกลมคุณสามารถออกไปเล็กน้อยแล้วกลับมา
user253751

(. Ps ดูเพิ่มเติมเหล่านี้สองคำถามใน meta.SE. )
Ilmari Karonen

7

เป็นวิธีง่ายๆอย่างที่ฉันได้กล่าวไปแล้วในความคิดเห็นคุณสามารถลอง aproach นี้:

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

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

ป้อนคำอธิบายรูปภาพที่นี่

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


นี่เป็นคำตอบที่ดี แต่มันอาจจะใช่หรือไม่สมจริงสำหรับ OP ซึ่งแตกต่างจากการพูด, รถยนต์, เรือไม่ได้จริงๆมี "รัศมีวงเลี้ยว": ตัวเองมากที่สุด (เครื่องยนต์ / มนุษย์) เรือขับเคลื่อนเป็นหลักสามารถเปิดเล็กน้อยในขณะที่เรือขึ้นอยู่กับลมและจริงสามารถมีเชิงลบหักเหที่มีประสิทธิภาพ รัศมีเมื่อทำการตรึงในแง่ที่ว่าการเลี้ยวซ้ายเป็นลมอาจทำให้เรือแล่นไปทางขวา เรืออะไรทำมีคือความเฉื่อย (และลาก): พวกเขาไม่สามารถเปิดหรือย้ายทันทีและเมื่อการย้ายหรือเปลี่ยนใช้เวลาและบังคับให้หยุด ยังมี +1
Ilmari Karonen

ขอบคุณมากสำหรับคำตอบของคุณ!!! :) คุณเป็นฮีโร่ของฉัน!
DavidT

@DavidT จากนั้นให้พิจารณาการทำเครื่องหมายคำตอบของเขา / เธอเป็นที่ยอมรับถ้ามันสามารถแก้ปัญหาของคุณได้อย่างน่าพอใจ :)
mand

-2

ระบบ Unity Nav mesh เป็นไปได้ว่าจะทำในสิ่งที่คุณต้องการด้วยการเล่นกับค่าเอเจนต์ nav

Nav Meshes ใช้งานง่าย และใช้ได้เฉพาะในการตั้งค่าจากบนลงล่าง (หรืออย่างน้อยใช้ได้เฉพาะกับการเคลื่อนไหว x / z)

Unity Manual Page ในการตั้งค่า nav nav

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


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

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