ฉันพยายามเคลื่อนย้ายเรือใบไปยังจุดที่ฉันคลิกด้วยเมาส์ การเคลื่อนไหวนี้ควรเป็นจริง (พายที่ด้านหลังที่เรือเคลื่อนที่ไปรอบ ๆ ) ดังนั้นหากการคลิกเมาส์ถูกทิ้งไว้และด้านหน้าของเรือเรือควรเลื่อนไปที่นั่นด้วยเส้นทางโค้งเพื่อให้การหมุนถูกต้อง
ฉันพยายามเคลื่อนย้ายเรือใบไปยังจุดที่ฉันคลิกด้วยเมาส์ การเคลื่อนไหวนี้ควรเป็นจริง (พายที่ด้านหลังที่เรือเคลื่อนที่ไปรอบ ๆ ) ดังนั้นหากการคลิกเมาส์ถูกทิ้งไว้และด้านหน้าของเรือเรือควรเลื่อนไปที่นั่นด้วยเส้นทางโค้งเพื่อให้การหมุนถูกต้อง
คำตอบ:
ดูหน้านี้
การเพิ่มเทิร์นสมจริง
ขั้นตอนต่อไปคือการเพิ่มโค้งโค้งที่เหมือนจริงสำหรับหน่วยของเราเพื่อที่ว่าพวกเขาจะไม่เปลี่ยนทิศทางทันทีทันใดทุกครั้งที่พวกเขาต้องเลี้ยว วิธีแก้ปัญหาง่าย ๆ คือการใช้ spline เพื่อทำให้มุมที่ฉับพลันเปลี่ยนเป็นเรียบ แม้ว่าวิธีนี้จะช่วยแก้ปัญหาเกี่ยวกับสุนทรียศาสตร์บางอย่าง แต่ก็ยังส่งผลให้เกิดการเคลื่อนไหวที่ไม่สมจริงมากสำหรับยูนิตส่วนใหญ่ ตัวอย่างเช่นมันอาจเปลี่ยนการเข้าโค้งอย่างกระทันหันของรถถังเป็นเส้นโค้งแน่น แต่การเลี้ยวโค้งจะยังคงแน่นกว่ารถถังจริง ๆ
สำหรับวิธีแก้ปัญหาที่ดีกว่าสิ่งแรกที่เราต้องรู้คือรัศมีวงเลี้ยวสำหรับหน่วยของเรา รัศมีวงเลี้ยวเป็นแนวคิดที่เรียบง่าย: ถ้าคุณอยู่ในลานจอดรถขนาดใหญ่ในรถของคุณและหมุนวงล้อไปทางซ้ายเท่าที่มันจะไปและขับรถเป็นวงกลมรัศมีของวงกลมนั้นคือการเลี้ยวของคุณ รัศมี. รัศมีวงเลี้ยวของ Volkswagen Beetle จะเล็กกว่า SUV ขนาดใหญ่อย่างมากและรัศมีวงเลี้ยวของคนจะน้อยกว่าของหมีตัวใหญ่
สมมติว่าคุณอยู่ในจุดหนึ่ง (จุดกำเนิด) และชี้ไปในทิศทางที่แน่นอนและคุณต้องไปยังจุดอื่น (ปลายทาง) ดังที่แสดงในรูปที่ 5 เส้นทางที่สั้นที่สุดจะพบได้ด้วยการเลี้ยวซ้ายไปจนสุด สามารถไปเป็นวงกลมได้จนกว่าคุณจะชี้ไปที่ปลายทางโดยตรงแล้วไปข้างหน้าหรือเลี้ยวขวาและทำสิ่งเดียวกัน
ในรูปที่ 5 เส้นทางที่สั้นที่สุดคือเส้นสีเขียวที่ด้านล่างอย่างชัดเจน เส้นทางนี้ค่อนข้างตรงไปตรงมาในการคำนวณเนื่องจากความสัมพันธ์ทางเรขาคณิตบางอย่างแสดงในรูปที่ 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
เป็นวิธีง่ายๆอย่างที่ฉันได้กล่าวไปแล้วในความคิดเห็นคุณสามารถลอง 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
) และระยะทางเป้าหมาย
ระบบ Unity Nav mesh เป็นไปได้ว่าจะทำในสิ่งที่คุณต้องการด้วยการเล่นกับค่าเอเจนต์ nav
Nav Meshes ใช้งานง่าย และใช้ได้เฉพาะในการตั้งค่าจากบนลงล่าง (หรืออย่างน้อยใช้ได้เฉพาะกับการเคลื่อนไหว x / z)
Unity Manual Page ในการตั้งค่า nav nav
โดยทั่วไปคุณสามารถใช้รูปร่างตาข่ายเพื่ออบบริเวณการนำทางและเพิ่มตัวแทนการนำทางไปยังวัตถุของคุณและให้พวกเขาค้นหาเส้นทางของพวกเขารอบ ๆ ตาข่ายนำทาง