游戲里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方向,任意點位任意方向計算正前方矩形范圍生產以及驗證過程。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM