遊戲裡12方向,任意方向計算正前方矩形規則
阿新 • • 發佈:2018-12-30
此文章意在記錄我是如何處理遊戲裡面特殊技能需求處理方案,
之前做遊戲很多年,技能打出去都是扇形,圓形為主的攻擊範圍獲取傷害;
然後昨天策劃提出一個需求,從玩家當前座標點開始打出正前方一個矩形返回獲取傷害值計算;
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, floatx2, 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方向,任意點位任意方向計算正前方矩形範圍生產以及驗證過程。
不知道還有沒有大神有更好的方式進行處理!!!