游戏里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方向,任意点位任意方向计算正前方矩形范围生产以及验证过程。

不知道还有没有大神有更好的方式进行处理!!!

原文地址:https://www.cnblogs.com/shizuchengxuyuan/p/5977682.html