1. 程式人生 > >遊戲裡12方向,任意方向計算正前方矩形規則

遊戲裡12方向,任意方向計算正前方矩形規則

此文章意在記錄我是如何處理遊戲裡面特殊技能需求處理方案,

之前做遊戲很多年,技能打出去都是扇形,圓形為主的攻擊範圍獲取傷害;

然後昨天策劃提出一個需求,從玩家當前座標點開始打出正前方一個矩形返回獲取傷害值計算;

 1     //<editor-fold defaultstate="collapsed" desc="獲取角度 public static int getATan(float x1, float y1, float x2, float y2)">
 2     public static int getATan(float x1, float y1, float
x2, float y2) { 3 //正切(tan)等於對邊比鄰邊;tanA=a/b 4 int a = 0; 5 if (x1 == x2) { 6 //x座標相同的情況表示正上或者正下方移動 7 a = 90; 8 } else if (y1 != y2) { 9 //三角函式的角度計算 10 float ta = Math.abs(y1 - y2) / Math.abs(x1 - x2); 11 //Math.sin(sina * (2 * Math.PI / 360))
12 Double atan = Math.atan(ta); 13 //Math.tan(x * (2 * Math.PI / 360)); 14 a = (int) Math.round(atan / (2 * Math.PI / 360)); 15 } 16 return a; 17 } 18 //</editor-fold>

這兩個函式可以計算出兩個點位的12方向計演算法則,

由於真實環境是360°,然後在實際計算是12方向,所以修正值,正移偏移12°包含值是正方向;

 1
// <editor-fold defaultstate="collapsed" desc="獲取方向 static public int getVector12(float x1, float y1, float x2, float y2)"> 2 /** 3 * 獲取方向 4 * <br> 5 * 根據特點,0方向是x軸正方向,順時針移動 6 * 7 * @param x1 8 * @param y1 9 * @param x2 10 * @param y2 11 * @return 12 */ 13 static public byte getVector12(float x1, float y1, float x2, float y2) { 14 15 byte vector = 0; 16 //正切(tan)等於對邊比鄰邊;tanA=a/b 17 int a = getATan(x1, y1, x2, y2); 18 19 if (0 <= a && a <= 15) { 20 if (x1 > x2) { 21 vector = 6; 22 } else { 23 vector = 0; 24 } 25 } else if (15 < a && a <= 45) { 26 if (x1 < x2) { 27 if (y1 < y2) { 28 vector = 11; 29 } else { 30 vector = 1; 31 } 32 } else if (y1 < y2) { 33 vector = 7; 34 } else if (y1 > y2) { 35 vector = 5; 36 } 37 } else if (45 < a && a <= 75) { 38 if (x1 < x2) { 39 if (y1 < y2) { 40 vector = 10; 41 } else { 42 vector = 2; 43 } 44 } else if (y1 < y2) { 45 vector = 8; 46 } else if (y1 > y2) { 47 vector = 4; 48 } 49 } else { 50 if (y1 > y2) { 51 vector = 3; 52 } else { 53 vector = 9; 54 } 55 } 56 57 return vector; 58 } 59 // </editor-fold>

把我難住了,難點在哪裡呢??

難點是在於玩家是是以12方位做基礎運算物件,那麼他在座標系裡面就有可能是任意座標點,和任意朝向,

相對於當前方向垂直的左右延伸座標法系,算出四個座標點。如下圖:

圖中我只是提出,最簡單的移動的圖形,當玩家當前朝向是y軸正方向,左右延伸,D和C兩個點,

然後還要計算出A,B、兩個座標點,

然而在實際做法中,玩家當前朝向肯定是很多朝向,

所以,在計算矩形範圍的時候是需要使用三角函式,來就是X軸和Y實際座標點的位移量。

我是把方向都切分了,不存在鈍角三角形一說,所以計算方式略有不同。

下面我們來看程式碼

 1     // <editor-fold defaultstate="collapsed" desc="保留四位小時函式 static Double getDouble4(float souse)">
 2     /**
 3      * 保留四位小時函式
 4      *
 5      * @param souse
 6      * @return
 7      */
 8     static float getDouble4(float souse) {
 9         BigDecimal b = new BigDecimal(souse);
10         float df = b.setScale(4, BigDecimal.ROUND_HALF_UP).floatValue();
11         return df;
12     }
13     // </editor-fold>

三角函式計算公式

 1     // <editor-fold defaultstate="collapsed" desc="位移是y軸 static float getV12Y(int vector, float offset)">
 2     /**
 3      * 位移是y軸
 4      *
 5      * @param vector 方向向量,正上方位1起點順時針旋轉 12方向
 6      * @param offset 位移量
 7      * @return
 8      */
 9     public static float getV12Y(int vector, float offset) {
10         int sina = 0;
11         switch (vector) {
12             case 3:
13             case 9:
14                 sina = 90;
15                 break;
16             case 0:
17             case 6:
18                 sina = 0;
19                 break;
20             case 2:
21             case 4:
22             case 8:
23             case 10:
24                 sina = 60;
25                 break;
26             case 1:
27             case 5:
28             case 7:
29             case 11:
30                 sina = 30;
31                 break;
32         }
33         /* 三角函式計算器 */
34         float sinr = (float) (offset * Math.sin(sina * (2 * Math.PI / 360)));
35         /* 拿到保留4位小數計算器 */
36         float double2 = getDouble4(sinr);
37         /* 根據方向計算向量位移是增加還是減少 */
38         if ((0 < vector && vector < 6)) {
39             return -1 * double2;
40         } else {
41             return double2;
42         }
43     }
44     // </editor-fold>
45 
46     // <editor-fold defaultstate="collapsed" desc="位移時的X軸 static float getV12X(int vector, float offset)">
47     /**
48      * 位移時的X軸
49      *
50      * @param vector 方向向量,正上方位1起點順時針旋轉 12方向
51      * @param offset 位移量
52      * @return
53      */
54     public static float getV12X(int vector, float offset) {
55         int cosa = 0;
56         /* 這裡根據方向拿到對應的實際座標系角度 */
57         switch (vector) {
58             case 3:
59             case 9:
60                 cosa = 90;
61                 break;
62             case 0:
63             case 6:
64                 cosa = 0;
65                 break;
66             case 2:
67             case 4:
68             case 8:
69             case 10:
70                 cosa = 60;
71                 break;
72             case 1:
73             case 5:
74             case 7:
75             case 11:
76                 cosa = 30;
77                 break;
78         }
79         /* 三角函式計算器 */
80         float cosr = (float) (offset * Math.cos(cosa * (2 * Math.PI / 360)));
81         /* 拿到保留4位小數計算器 */
82         float double2 = getDouble4(cosr);
83         /* 根據方向計算向量位移是增加還是減少 */
84         if ((0 <= vector && vector <= 3) || (9 <= vector && vector <= 11)) {
85             return double2;
86         } else {
87             return -1 * double2;
88         }
89     }
90     // </editor-fold>

上面的三角函式計算公式,就能計算出12方向任意方向位移的偏移量

我們以12方向為例,任意方向90°位移,都是左右偏移三個方向計算,

然後我們是12為單位的;

1         int vdir = 3; //相對玩家的90°朝向偏移量
2         /* 減方向偏移量 */
3         int attdir1 = dir - vdir;
4         if (attdir1 < 0) {
5             /* 12方向修正,12是一個輪迴 */
6             attdir1 = 12 + attdir1;
7         }
8         /* 加方向偏移量 12方向修正,12是一個輪迴*/
9         int attdir2 = (dir + vdir) % 12;

當我們得到一個方向的需要計算一次,左右兩個偏移位移的方向

 1 /**
 2      * 90°朝向矩形,以傳入的座標點為AB邊中心點距離
 3      *
 4      * @param dir
 5      * @param x
 6      * @param y
 7      * @param vr_width 偏移量,左右各偏移0.2m直線是0.4m
 8      * @return
 9      */
10     static public java.awt.Polygon getRectangle(int dir, float x, float y, float vr_width, float vr_hight) {
11 
12         int vdir = 3; //相對玩家的90°朝向偏移量
13         /* 減方向偏移量 */
14         int attdir1 = dir - vdir;
15         if (attdir1 < 0) {
16             /* 12方向修正,12是一個輪迴 */
17             attdir1 = 12 + attdir1;
18         }
19         /* 加方向偏移量 12方向修正,12是一個輪迴*/
20         int attdir2 = (dir + vdir) % 12;
21         /* 根據三角函式計算出 A 點偏移量 */
22         float v12_A_X = getV12X(attdir1, vr_width);
23         float v12_A_Y = getV12Y(attdir1, vr_width);
24         /* 由於在計算12方向位移函式裡面已經計算偏移量是正負值 */
25         float A_X = x + v12_A_X;
26         float A_Y = y + v12_A_Y;
27 
28         /* 根據三角函式計算出 B 點偏移量 */
29         float v12_B_X = getV12X(attdir2, vr_width);
30         float v12_B_Y = getV12Y(attdir2, vr_width);
31         /* 由於在計算12方向位移函式裡面已經計算偏移量是正負值 */
32         float B_X = x + v12_B_X;
33         float B_Y = y + v12_B_Y;
34 
35         /* 根據三角函式計算出 C 或者 D 點偏移量 */
36         float v12_CD_X = getV12X(dir, vr_hight);
37         float v12_CD_Y = getV12Y(dir, vr_hight);
38 
39         /* C 點應該是 A 點的垂直方向也就是原來玩家的移動方向 由於在計算12方向位移函式裡面已經計算偏移量是正負值*/
40         float C_X = A_X + v12_CD_X;
41         float C_Y = A_Y + v12_CD_Y;
42 
43         /* D 點應該是 B 點的垂直方向也就是原來玩家的移動方向 由於在計算12方向位移函式裡面已經計算偏移量是正負值*/
44         float D_X = B_X + v12_CD_X;
45         float D_Y = B_Y + v12_CD_Y;
46 
47         Point2D.Double pointA = new Point2D.Double(A_X, A_Y);
48         Point2D.Double pointB = new Point2D.Double(B_X, B_Y);
49         Point2D.Double pointC = new Point2D.Double(C_X, C_Y);
50         Point2D.Double pointD = new Point2D.Double(D_X, D_Y);
51 
52         java.awt.Polygon p = new Polygon();
53 
54         int px = (int) (pointC.x * TIMES);
55         int py = (int) (pointC.y * TIMES);
56         p.addPoint(px, py);
57 
58         px = (int) (pointD.x * TIMES);
59         py = (int) (pointD.y * TIMES);
60         p.addPoint(px, py);
61 
62         px = (int) (pointB.x * TIMES);
63         py = (int) (pointB.y * TIMES);
64         p.addPoint(px, py);
65 
66         px = (int) (pointA.x * TIMES);
67         py = (int) (pointA.y * TIMES);
68         p.addPoint(px, py);
69         return p;
70     }
71 
72     static final int TIMES = 1000;
73 
74     // 驗證一個點是否在矩形內
75     static public boolean checkRectangle(float x, float y, java.awt.Polygon polygon) {
76         int px = (int) (x * TIMES);
77         int py = (int) (y * TIMES);
78         return polygon.contains(px, py);
79     }

由於我們在遊戲中獲取周圍玩家或者怪物的時候,往往需要很多座標點驗證,所以驗證函式獨立出來,是為了減少驗證計算次數

測試程式碼

 1     public static void main(String[] args) throws FileNotFoundException, IOException, Exception {
 2 
 3         float x = 0.0f;
 4         float y = 0.0f;
 5         int dir = 9;//當前玩家朝向
 6         Polygon rectangle = getRectangle(dir, x, y, 0.4f, 0.4f);
 7         log.error(checkRectangle(x + 0.2f, y + 0.1f, rectangle));
 8         log.error(checkRectangle(x - 0.2f, y + 0.1f, rectangle));
 9         log.error(checkRectangle(x + 1.2f, y + 0.1f, rectangle));
10         log.error(checkRectangle(x + 0.2f, y + 1.1f, rectangle));
11     }

以上是本次12方向,任意點位任意方向計算正前方矩形範圍生產以及驗證過程。

不知道還有沒有大神有更好的方式進行處理!!!