此文章意在记录我是如何处理游戏里面特殊技能需求处理方案,
之前做游戏很多年,技能打出去都是扇形,圆形为主的攻击范围获取伤害;
然后昨天策划提出一个需求,从玩家当前坐标点开始打出正前方一个矩形返回获取伤害值计算;
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方向,任意点位任意方向计算正前方矩形范围生产以及验证过程。
不知道还有没有大神有更好的方式进行处理!!!