2012-09-02 34 views
16

Vì vậy, tôi đang tạo một trò chơi nhỏ, nơi tôi kiểm tra xem nhân vật có thể "nhìn thấy" một nhân vật khác có thể thấy ký tự B nếu A ở trong khoảng cách nhất định của B hay không ở độ A là +/- 45 độ của góc B đang đối mặt.Tính toán nếu một góc nằm giữa hai góc

Hiện nay, tôi làm một chút tính toán nơi tôi đang kiểm tra nếu

(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45) 

này hoạt động tốt trừ khi chúng ta vượt qua ranh giới 360 độ.

Giả sử facingAngle = 359, angleOfTarget = 5. Trong tình huống này, mục tiêu chỉ là 6 độ ra khỏi trung tâm, vì vậy tôi muốn chức năng của tôi trở lại đúng sự thật. Thật không may, 5 không phải là giữa 314 và 404.

+0

có thể trùng lặp của [Xác định xem góc nằm giữa 2 góc độ khác] (http://stackoverflow.com/questions/11406189/determine-if-angle-lies- giữa 2-góc khác) – sschuberth

Trả lời

14

Chỉ cần cố gắng

anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180 

if (anglediff <= 45 && anglediff>=-45) .... 

Nguyên nhân là do sự khác biệt ở các góc là facingAngle - angleOfTarget mặc dù do hiệu ứng gói, có thể bị tắt 360 độ.

Thêm 180 + 360 rồi modulo 360 rồi trừ 180, chỉ chuyển đổi mọi thứ thành phạm vi từ -180 đến 180 độ (bằng cách cộng hoặc trừ 360 độ).

Sau đó, bạn có thể kiểm tra sự khác biệt về góc một cách dễ dàng, cho dù đó là trong phạm vi -45 đến 45 độ.

+1

Tại linh sam Tôi nghĩ nó không hoạt động trong trường hợp chủ đề, nhưng sau đó tôi đã thử nghiệm bằng Python .. Làm việc !! Vì vậy, tôi đã trở lại Pascal để tìm ra lý do tại sao nó không hoạt động ở đó, hóa ra là 'mod' trong Pascal không hoạt động với số âm ... – JHolta

+1

Điều này không thành công trong trường hợp phải đối mặt với 0 và angleOfTarget là 359, ví dụ. Trừ khi tôi bỏ sót điều gì đó, bạn nhận được (0 - 359 + 180)% 360 - 180 = -359. Một giá trị tuyệt đối được yêu cầu xung quanh đối mặt với góc độ - gócOfTự trừ mục tiêu. –

+0

Kiểm tra đầy đủ trong Java (Android). Nó hoạt động. – pascalbros

0

Một giải pháp đơn giản để xử lý gói vào cuối thấp (vào các giá trị âm), chỉ là thêm 360 cho tất cả các giá trị của bạn:

(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405) 

Bằng cách đó, phép trừ của 45 không bao giờ có thể âm, bởi vì nó không còn xảy ra nữa.

Để xử lý gói vào cuối hàng đầu, bạn cần phải kiểm tra một lần nữa, thêm khác 360 với giá trị angleOfTarget:

canSee = (facingAngle + 315 <= angleOfTarget + 360) && 
      (angleOfTarget + 360 <= facingAngle + 405); 
canSee |= (facingAngle + 315 <= angleOfTarget + 720) && 
      (angleOfTarget + 720 <= facingAngle + 405); 
8

Có một giải pháp lượng giác tránh được vấn đề gói.

Tôi giả định rằng bạn có tọa độ (x, y) cho cả hai ký tự P1P2. Bạn đã xác định rằng bạn biết khoảng cách giữa hai cái mà bạn có lẽ được tính toán bằng định lý Pythagoras.

Bạn có thể sử dụng dot sản phẩm của hai vectơ để tính góc giữa chúng:

A . B = |A| . |B| . cos(theta). 

Nếu bạn mất A như facingAngle vector nó sẽ được [cos(fA), sin(fA)], và sẽ có tầm quan trọng |A| trong tổng số 1.

Nếu bạn mất B như vector giữa hai nhân vật, và khoảng cách của bạn ở trên, bạn nhận được:

cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y))/|B| 

trong đó |B| là khoảng cách bạn đã tính toán.

Bạn không cần phải thực sự lấy cosin nghịch đảo để tìm theta, vì phạm vi từ -45 đến +45 bạn chỉ cần kiểm tra cos(theta) >= 0.70710678 (ví dụ: 1/sqrt(2)).

Điều này có vẻ như hơi phức tạp, nhưng cơ hội là bạn đã có tất cả các biến bắt buộc treo xung quanh trong chương trình của mình.

6

Đây là một hàm đơn giản mà tôi tìm thấy trực tuyến và được sửa đổi. Nó hoạt động chính xác cho mọi góc độ (có thể nằm ngoài 0-360). (Chức năng này được thực hiện để làm việc trong c, làm việc trong Xcode.)

Hãy nhớ rằng, nó sẽ kiểm tra COUNTER chiều kim đồng hồ từ góc A đến góc B. Nó trả YES (true) nếu góc giữa :)

Đầu tiên, một chức năng chuyển đổi đơn giản để làm cho tất cả các góc 1-360

//function to convert angle to 1-360 degrees 
static inline double angle_1to360(double angle){ 
angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360 
if(angle>0.0) 
return angle; 
else 
return angle + 360.0; 
} 

Kiểm tra nếu góc giữa :)

//check if angle is between angles 
static inline BOOL angle_is_between_angles(float N,float a,float b) { 
N = angle_1to360(N); //normalize angles to be 1-360 degrees 
a = angle_1to360(a); 
b = angle_1to360(b); 

if (a < b) 
return a <= N && N <= b; 
return a <= N || N <= b; 
} 

enter image description here

Ví dụ: Để kiểm tra xem góc 300 là giữa 180 và 10 độ:

BOOL isBetween=angle_is_between_angles(300, 180,10); 

// RETURNS YES

+1

Dường như làm việc cho Java nếu trunc() được thay thế bằng Math.floor(). – mindoverflow

0

Một cách khác để sử dụng luôn luôn khác biệt tích cực tối thiểu và so sánh với ngưỡng:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection)); 
if (anglediff <= 45) 
0

tái khẳng định câu trả lời Alnitak của theo một cách khác, một giải pháp tránh được góc quấn ở 360 độ là để giải quyết vấn đề trong một hệ tọa độ khác nhau, nơi các góc luôn nhỏ. Đây là mã:

def inside_angle(facing, target): 
    dot = cos(facing)*cos(target) + sin(facing)*sin(target) 
    angle = acos(dot) 

    return angle <= pi/4 

Điều này được thực hiện bằng cách sử dụng phép chiếu vectơ. Giả sử các vectơ facing mặt> = [cos (đối diện) sin (đối diện)] và | target> = [cos (mục tiêu) sin (đích)], khi chiếu mục tiêu vào vectơ đối diện, góc sẽ từ khoảng không, khi mục tiêu chính xác ở vectơ đối diện hoặc sẽ tăng lên ở hai bên. Bằng cách này, chúng ta chỉ có thể so sánh nó với pi/4 (45 độ). Công thức cho các góc như sau:

cos(angle) = <facing|target>/<target|target> <facing|facing> 

Đó là, cosin của góc là dấu chấm sản phẩm giữa các vectơ | phải đối mặt với> và | target> chia module của họ, đó là 1 trong trường hợp này, mà trở thành:

angle = acos(<facing|target>) 

tham khảo: https://en.wikipedia.org/wiki/Vector_projection

Các vấn đề liên quan