2017-03-24修正
在以前版本中有一個錯誤之處需求修正,當坐標朝向是4,5,6的時候算出來的角度是錯誤的;導致這個時候攻擊怪物的時候矩形,扇形都無法攻擊;
現在附錄最新修正值
1 case 4: 2 case 5: 3 case 6: 4 case 7: 5 case 8: 6 if (vz > 0) { 7 aTan = -90 - aTan; 8 } else { 9 aTan = 270 - aTan; 10 } 11 break;
算出來的360°角度是錯誤的;
正確的算法應該是這樣的,
1 /** 2 * 根據0-90朝向角度,計算360° 3 * 4 * @param aTan 0 - 90 度 5 * @param vector12 6 * @param vx 7 * @param vz 8 * @return 9 */ 10 public static double getATan360ByaTan(double aTan, int vector12, int vx, int vz) { 11 switch (vector12) { 12 case 0: 13 case 1: 14 case 2: 15 case 3: 16 if (vector12 == 0 && vx < 0) { 17 aTan = 360 - aTan; 18 } else if (vector12 == 3 && vz < 0) { 19 aTan = 90 + aTan; 20 } else { 21 aTan = 90 - aTan; 22 } 23 break; 24 case 4: 25 case 5: 26 case 6: 27 case 7: 28 case 8: 29 if (vx > 0) { 30 aTan = 90 + aTan; 31 } else { 32 aTan = 270 - aTan; 33 } 34 break; 35 case 9: 36 case 10: 37 case 11: 38 if (vz > 0) { 39 aTan = 270 + aTan; 40 } else { 41 aTan = 270 - aTan; 42 } 43 break; 44 } 45 return aTan; 46 }
s
前瞻回顧
上一篇文章中《游戲里12方向,任意方向計算正前方矩形規則》中講到,游戲12方向任意矩形規則計算問題,
在后來測試發現這個算法其實有問題,因為算錯矩形的時候ABCD,矩形四個坐標點必須是順序坐標點,才能計算出任意點位
是否在坐標中;如果方向變化,后坐標點其實位置就錯誤了,驗證是否在矩形方案就錯了;
后來在網友幫助下,用射線算法,解決多邊形問(本方案只能適用於凸多邊形計算),坐標點是否在多邊形內,不限於四邊形。
傷害范圍划分
在我做的游戲中,出現的計算傷害范圍方式分為
圓形,矩形(正方向或者長方形),三角形,扇形,
當前圖中所有A點(中心點或者場景對象坐標點)位當前需要計算的傷害范圍起始點或者叫中心點,
傷害范圍圓形
我相信圓形其實是做好計算的,那就是說只需要判斷兩個點位距離即可;
1 /** 2 * 計算兩點距離 3 * 4 * @param x1 5 * @param z1 6 * @param x2 7 * @param z2 8 * @return 9 */ 10 public static double distance(double x1, double z1, double x2, double z2) { 11 x1 -= x2; 12 z1 -= z2; 13 return Math.sqrt(x1 * x1 + z1 * z1); 14 }
圓形計算方式,最為簡單,連方向都不需要計算,
游戲中360度方向計算
我們需要一個類Vector表示當前攻擊朝向

1 package net.sz.game.engine.struct; 2 3 import java.io.Serializable; 4 import org.apache.log4j.Logger; 5 6 /** 7 * 表示朝向,位移量 8 * <br> 9 * author 失足程序員<br> 10 * mail 492794628@qq.com<br> 11 * phone 13882122019<br> 12 */ 13 public class Vector implements Serializable { 14 15 private static final Logger log = Logger.getLogger(Vector.class); 16 private static final long serialVersionUID = -8252572890329345857L; 17 18 /*表示當前朝向修正值 0 - 11 包含*/ 19 private int dir; 20 /*表示未修正的x方向正負位移量 只能是1或者-1*/ 21 private int dir_x; 22 /*表示未修正的y方向正負位移量 只能是1或者-1*/ 23 private int dir_y; 24 /*表示未修正的z方向正負位移量 只能是1或者-1*/ 25 private int dir_z; 26 /*在x軸方向位移 偏移量 >=0 */ 27 @Deprecated 28 private double vrx; 29 /*在z軸方向的位移 偏移量 >=0*/ 30 @Deprecated 31 private double vrz; 32 /*角 a 度數 0 - 90 包含*/ 33 private double atan; 34 /*角 a 度數 0 ~ 360° 不包含 360*/ 35 private double atan360; 36 37 public Vector() { 38 } 39 40 public Vector(Vector vector) { 41 this.dir = vector.dir; 42 this.dir_x = vector.dir_x; 43 this.dir_y = vector.dir_y; 44 this.dir_z = vector.dir_z; 45 this.atan = vector.atan; 46 this.atan360 = vector.atan360; 47 this.vrx = vector.vrx; 48 this.vrz = vector.vrz; 49 } 50 51 public void copyVector(Vector vector) { 52 this.dir = vector.dir; 53 this.dir_x = vector.dir_x; 54 this.dir_y = vector.dir_y; 55 this.dir_z = vector.dir_z; 56 this.atan = vector.atan; 57 this.atan360 = vector.atan360; 58 this.vrx = vector.vrx; 59 this.vrz = vector.vrz; 60 } 61 62 public int getDir() { 63 return dir; 64 } 65 66 public void setDir(int dir) { 67 this.dir = dir; 68 } 69 70 public int getDir_x() { 71 return dir_x; 72 } 73 74 public void setDir_x(int dir_x) { 75 this.dir_x = dir_x; 76 } 77 78 public int getDir_y() { 79 return dir_y; 80 } 81 82 public void setDir_y(int dir_y) { 83 this.dir_y = dir_y; 84 } 85 86 public int getDir_z() { 87 return dir_z; 88 } 89 90 public void setDir_z(int dir_z) { 91 this.dir_z = dir_z; 92 } 93 94 public double getAtan() { 95 return atan; 96 } 97 98 public void setAtan(double atan) { 99 this.atan = atan; 100 } 101 102 public double getAtan360() { 103 return atan360; 104 } 105 106 public void setAtan360(double atan360) { 107 this.atan360 = atan360; 108 } 109 110 @Deprecated 111 public double getVrx() { 112 return vrx; 113 } 114 115 @Deprecated 116 public void setVrx(double vrx) { 117 this.vrx = vrx; 118 } 119 120 @Deprecated 121 public double getVrz() { 122 return vrz; 123 } 124 125 @Deprecated 126 public void setVrz(double vrz) { 127 this.vrz = vrz; 128 } 129 130 @Override 131 public String toString() { 132 return "dir=" + dir + ", dir_x=" + dir_x + ", dir_z=" + dir_z + ", atan=" + atan + ", atan360=" + atan360; 133 } 134 135 }
然后如何獲得朝向?
1,通過連個坐標點獲得朝向問題
比如獲取攻擊對象鎖定目標的釋放技能,或者給定坐標點比如地面魔法施法類型

1 /** 2 * 獲取兩個坐標點的朝向 3 * 4 * @param x1 5 * @param z1 6 * @param x2 7 * @param z2 8 * @return 9 */ 10 public static Vector getV12Vector(double x1, double z1, double x2, double z2) { 11 Vector vector = new Vector(); 12 getV12Vector(vector, x1, z1, x2, z2); 13 return vector; 14 } 15 16 /** 17 * 獲取兩個坐標點的朝向 18 * 19 * @param vector 20 * @param x1 21 * @param z1 22 * @param x2 23 * @param z2 24 */ 25 public static void getV12Vector(Vector vector, double x1, double z1, double x2, double z2) { 26 vector.setAtan(getATan(x1, z1, x2, z2)); 27 vector.setDir(_getVector12(vector.getAtan(), x1, z1, x2, z2)); 28 vector.setDir_x(getVector12_x(x1, x2)); 29 vector.setDir_z(getVector12_z(z1, z2)); 30 vector.setAtan360(getATan360ByaTan(vector.getAtan(), vector.getDir(), vector.getDir_x(), vector.getDir_z())); 31 } 32 33 /** 34 * 獲取兩個坐標點的朝向 35 * 36 * @param x1 37 * @param z1 38 * @param x2 39 * @param z2 40 * @return 41 */ 42 public static double getATan360(double x1, double z1, double x2, double z2) { 43 double aTan = getATan(x1, z1, x2, z2); 44 byte _getVector12 = _getVector12(aTan, x1, z1, x2, z2); 45 byte vector12_x = getVector12_x(x1, x2); 46 byte vector12_z = getVector12_z(z1, z2); 47 return getATan360ByaTan(aTan, _getVector12, vector12_x, vector12_z); 48 } 49 50 /** 51 * 朝向是有修正,在修正下真實朝向,有正負區分 52 * 53 * @param z1 54 * @param z2 55 * @return 56 */ 57 static public byte getVector12_z(double z1, double z2) { 58 byte vector = 1; 59 if (z1 > z2) { 60 /*表示z方向遞減*/ 61 vector = -1; 62 } 63 return vector; 64 } 65 66 /** 67 * 朝向是有修正,在修正下真實朝向,有正負區分 68 * 69 * @param x1 70 * @param x2 71 * @return 72 */ 73 static public byte getVector12_x(double x1, double x2) { 74 byte vector = 1; 75 if (x1 > x2) { 76 /*表示x方向遞減*/ 77 vector = -1; 78 } 79 return vector; 80 } 81 82 // <editor-fold defaultstate="collapsed" desc="位移是z軸 static float getV12Z(int vector, double offset)"> 83 public static double getV12ZD(double offset, double sin) { 84 offset = Math.abs(offset); 85 /* 三角函數計算器 */ 86 double sinr = (offset * Math.sin(Math.toRadians(sin))); 87 /* 拿到保留4位小數計算器 */ 88 return BitUtil.getDouble4(sinr); 89 } 90 // </editor-fold> 91 92 // <editor-fold defaultstate="collapsed" desc="位移時的X軸 static float getV12X(int vector, double offset)"> 93 public static double getV12XD(double offset, double cos) { 94 offset = Math.abs(offset); 95 /* 三角函數計算器 */ 96 double cosr = (offset * Math.cos(Math.toRadians(cos))); 97 /* 拿到保留4位小數計算器 */ 98 return BitUtil.getDouble4(cosr); 99 } 100 // </editor-fold>. 101 102 //<editor-fold defaultstate="collapsed" desc="獲取角度 public static int getV12ATan(double x1, double y1, double x2, double y2)"> 103 public static double getATan(double x1, double z1, double x2, double z2) { 104 //正切(tan)等於對邊比鄰邊;tanA=a/b 105 double a = 0; 106 if (x1 == x2) { 107 //x坐標相同的情況表示正上或者正下方移動 108 a = 90; 109 } else if (z1 != z2) { 110 //三角函數的角度計算 111 double ta = Math.abs(z1 - z2) / Math.abs(x1 - x2); 112 double atan = Math.atan(ta); 113 a = BitUtil.getDouble4(Math.toDegrees(atan)); 114 } 115 return a; 116 } 117 //</editor-fold>
2,通過360度朝向計算坐標點問題;
通過360°朝向是因為比如場景中的陷阱,炮塔之類的,默認配置初始朝向,可能不在改變朝向
在計算360朝向的時候,我們游戲是和客戶端u3d,模擬方式,在z軸正方向為360°起始點方向
然后划分12方向;

1 /** 2 * 3 * @param atan360 4 * @return 5 */ 6 public static Vector getVectorBy360Atan(double atan360) { 7 Vector vector = new Vector(); 8 vector.setAtan360(atan360); 9 setAtan360(vector); 10 return vector; 11 } 12 13 /** 14 * 根據360度算出各種朝向問題 15 * 16 * @param vector 17 */ 18 public static void setAtan360(Vector vector) { 19 double atan360 = vector.getAtan360(); 20 if (0 <= atan360 && atan360 <= 15) { 21 vector.setDir(0); 22 vector.setDir_x(1); 23 vector.setDir_z(1); 24 vector.setAtan(90 - atan360); 25 } else if (15 < atan360 && atan360 <= 45) { 26 vector.setDir(1); 27 vector.setDir_x(1); 28 vector.setDir_z(1); 29 vector.setAtan(90 - atan360); 30 } else if (45 < atan360 && atan360 <= 75) { 31 vector.setDir(2); 32 vector.setDir_x(1); 33 vector.setDir_z(1); 34 vector.setAtan(90 - atan360); 35 } else if (75 < atan360 && atan360 <= 90) { 36 vector.setDir(3); 37 vector.setDir_x(1); 38 vector.setDir_z(1); 39 vector.setAtan(90 - atan360); 40 } else if (90 < atan360 && atan360 <= 105) { 41 vector.setDir(3); 42 vector.setDir_x(1); 43 vector.setDir_z(-1); 44 vector.setAtan(atan360 - 90); 45 } else if (105 < atan360 && atan360 <= 135) { 46 vector.setDir(4); 47 vector.setDir_x(1); 48 vector.setDir_z(-1); 49 vector.setAtan(atan360 - 90); 50 } else if (135 < atan360 && atan360 <= 165) { 51 vector.setDir(5); 52 vector.setDir_x(1); 53 vector.setDir_z(-1); 54 vector.setAtan(atan360 - 90); 55 } else if (165 < atan360 && atan360 <= 180) { 56 vector.setDir(6); 57 vector.setDir_x(1); 58 vector.setDir_z(-1); 59 vector.setAtan(atan360 - 90); 60 } else if (180 < atan360 && atan360 <= 195) { 61 vector.setDir(6); 62 vector.setDir_x(-1); 63 vector.setDir_z(-1); 64 vector.setAtan(270 - atan360); 65 } else if (195 < atan360 && atan360 <= 225) { 66 vector.setDir(7); 67 vector.setDir_x(-1); 68 vector.setDir_z(-1); 69 vector.setAtan(270 - atan360); 70 } else if (225 < atan360 && atan360 <= 255) { 71 vector.setDir(8); 72 vector.setDir_x(-1); 73 vector.setDir_z(-1); 74 vector.setAtan(270 - atan360); 75 } else if (255 < atan360 && atan360 <= 270) { 76 vector.setDir(9); 77 vector.setDir_x(-1); 78 vector.setDir_z(1); 79 vector.setAtan(270 - atan360); 80 } else if (270 < atan360 && atan360 <= 285) { 81 vector.setDir(9); 82 vector.setDir_x(-1); 83 vector.setDir_z(1); 84 vector.setAtan(atan360 - 270); 85 } else if (285 < atan360 && atan360 <= 315) { 86 vector.setDir(10); 87 vector.setDir_x(-1); 88 vector.setDir_z(1); 89 vector.setAtan(atan360 - 270); 90 } else if (315 < atan360 && atan360 <= 345) { 91 vector.setDir(11); 92 vector.setDir_x(-1); 93 vector.setDir_z(1); 94 vector.setAtan(atan360 - 270); 95 } else if (345 < atan360) { 96 vector.setDir(0); 97 vector.setDir_x(-1); 98 vector.setDir_z(1); 99 vector.setAtan(atan360 - 270); 100 } 101 }
以上兩種方式獲得攻擊朝向以后方便接下來的計算
傷害范圍扇形
扇形傷害計算范圍,我們需要計算當前攻擊朝向,扇形夾角度,和半徑范圍
在處理扇形之前,我們需要獲得方向,在之前的代碼里面我們已經知道如果去當前中心點朝向性問題后,
計算扇形范圍,
其實起算扇形范圍用360°朝向是非常好算,首先計算扇形的兩個邊360°表現形式的角度,然后計算在
A到任意坐標點距離以及點和點之前的360°夾角換算就知道是否在扇形攻擊范圍內了;
通過當前朝向的360°角度往左(A1)和往右(A2)偏移夾角度得到扇形夾角,兩邊的360°表象;
如果往左(A1)偏移出來的值大於往右(A2)偏移出來的扇形邊360°的值,
那么任意點位的朝向360°(C點表示) (A1<= C && C<=360) || (0<=C && C<=A2)
否則是正常狀態
A2<=C && C<=A1
1 private static final Logger log = Logger.getLogger(ATest.class); 2 3 public static void main(String[] args) { 4 5 /*攻擊方坐標點是 2,2 被攻擊 6,7*/ 6 Vector vector = MoveUtil.getV12Vector(2, 2, 6, 7); 7 log.error(vector); 8 /*扇形半徑為5碼*/ 9 double vr = 5; 10 /*我們當前扇形是70°攻擊范圍*/ 11 double skillAngle = 35; 12 /*有角度 為扇形*/ 13 double atan360 = vector.getAtan360(); 14 /*往左偏移 A1*/ 15 double aTan360_A1 = MoveUtil.getATan360(atan360, -1 * skillAngle); 16 /*往右偏移 A2*/ 17 double aTan360_A2 = MoveUtil.getATan360(atan360, skillAngle); 18 /*求證 5,5 點位是否在矩形內*/ 19 if (MoveUtil.distance(2, 2, 5, 5) <= vr) { 20 double tmpTan360 = MoveUtil.getATan360(2, 2, 5, 5); 21 log.error("當前點位(5, 5)在扇形內 360°=" + tmpTan360); 22 if ((aTan360_A1 > aTan360_A2 && ((aTan360_A1 <= tmpTan360 && tmpTan360 <= 360) || (0 <= tmpTan360 && tmpTan360 <= aTan360_A2))) 23 || (aTan360_A1 < aTan360_A2 && aTan360_A1 <= tmpTan360 && tmpTan360 <= aTan360_A2)) { 24 /*"修正后的夾角:" + aTan360_A1 + " ~ 360 和 0 ~" + aTan360_A2*/ 25 log.error("當前點位(5, 5)在扇形 內"); 26 } else { 27 log.error("當前點位(5, 5)在扇形 外"); 28 } 29 } 30 31 /*求證 1,1 點位是否在矩形內*/ 32 if (MoveUtil.distance(2, 2, 1, 1) <= vr) { 33 double tmpTan360 = MoveUtil.getATan360(2, 2, 1, 1); 34 log.error("當前點位(1, 1)在扇形內 360°=" + tmpTan360); 35 if ((aTan360_A1 > aTan360_A2 && ((aTan360_A1 <= tmpTan360 && tmpTan360 <= 360) || (0 <= tmpTan360 && tmpTan360 <= aTan360_A2))) 36 || (aTan360_A1 < aTan360_A2 && aTan360_A1 <= tmpTan360 && tmpTan360 <= aTan360_A2)) { 37 /*"修正后的夾角:" + aTan360_A1 + " ~ 360 和 0 ~" + aTan360_A2*/ 38 log.error("當前點位(1, 1)在扇形 內"); 39 } else { 40 log.error("當前點位(1, 1)在扇形 外"); 41 } 42 } 43 }
測試結果:
1 --- exec-maven-plugin:1.2.1:exec (default-cli) @ net.sz.game.engine --- 2 [02-15 20:07:53:0101:ERROR: sz.ATest.main():19 ] -> dir=1, dir_x=1, dir_z=1, atan=51.3402, atan360=38.6598 3 [02-15 20:07:53:0105:ERROR: sz.ATest.main():33 ] -> 當前點位(5, 5)在扇形內 360°=45.0 4 [02-15 20:07:53:0105:ERROR: sz.ATest.main():37 ] -> 當前點位(5, 5)在扇形 內 5 [02-15 20:07:53:0106:ERROR: sz.ATest.main():46 ] -> 當前點位(1, 1)在扇形內 360°=225.0 6 [02-15 20:07:53:0106:ERROR: sz.ATest.main():52 ] -> 當前點位(1, 1)在扇形 外 7 ------------------------------------------------------------------------
傷害范圍多邊形
多邊形分為,三角形,矩形,五邊形,六邊形;
由於五邊形及以上多邊形其實和圓形區別不大,我沒有細化;目前只處理了三角形和矩形
矩形輔助代碼

1 package net.sz.game.engine.struct; 2 3 import net.sz.game.engine.utils.BitUtil; 4 5 /** 6 * 任意多邊形, 7 * 8 */ 9 public class PolygonCheck { 10 11 12 /*多邊形的頂點*/ 13 double[] pointXs; 14 double[] pointZs; 15 /*當前已經添加的坐標點*/ 16 int pointCount = 0; 17 18 /** 19 * 20 * @param size 多邊形的頂點數 21 */ 22 public PolygonCheck(int size) { 23 pointXs = new double[size]; 24 pointZs = new double[size]; 25 } 26 27 /** 28 * 29 * @param x 坐標點 30 * @param z 坐標點 31 */ 32 public void add(double x, double z) { 33 add(pointCount, x, z); 34 pointCount++; 35 } 36 37 /** 38 * 39 * @param index 當前索引 40 * @param x 坐標點 41 * @param z 坐標點 42 */ 43 public void add(int index, double x, double z) { 44 if (0 <= index && index < pointXs.length) { 45 pointXs[index] = BitUtil.getDouble2(x); 46 pointZs[index] = BitUtil.getDouble2(z); 47 } else { 48 throw new UnsupportedOperationException("index out of"); 49 } 50 } 51 52 /** 53 * 判斷點是否在多邊形內 <br> 54 * ----------原理---------- <br> 55 * 注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那么這條射線與多邊形的交點必為奇數,<br> 56 * 如果P在多邊形外部,則交點個數必為偶數(0也在內)。<br> 57 * 58 * @param x 要判斷的點 59 * @param z 要判斷的點 60 * @return 61 */ 62 public boolean isInPolygon(double x, double z) { 63 boolean inside = false; 64 double p1x = 0, p1z = 0, p2x = 0, p2z = 0; 65 66 for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++) { 67 /*第一個點和最后一個點作為第一條線,之后是第一個點和第二個點作為第二條線,之后是第二個點與第三個點,第三個點與第四個點...*/ 68 p1x = pointXs[i]; 69 p1z = pointZs[i]; 70 71 p2x = pointXs[j]; 72 p2z = pointZs[j]; 73 74 if (z < p2z) {/*p2在射線之上*/ 75 if (p1z <= z) {/*p1正好在射線中或者射線下方*/ 76 if ((z - p1z) * (p2x - p1x) >= (x - p1x) * (p2z - p1z))/*斜率判斷,在P1和P2之間且在P1P2右側*/ { 77 /*射線與多邊形交點為奇數時則在多邊形之內,若為偶數個交點時則在多邊形之外。 78 由於inside初始值為false,即交點數為零。所以當有第一個交點時,則必為奇數,則在內部,此時為inside=(!inside) 79 所以當有第二個交點時,則必為偶數,則在外部,此時為inside=(!inside)*/ 80 inside = (!inside); 81 } 82 } 83 } else if (z < p1z) { 84 /*p2正好在射線中或者在射線下方,p1在射線上*/ 85 if ((z - p1z) * (p2x - p1x) <= (x - p1x) * (p2z - p1z))/*斜率判斷,在P1和P2之間且在P1P2右側*/ { 86 inside = (!inside); 87 } 88 } 89 } 90 return inside; 91 } 92 }
矩形,重要的是,根據A1,當前坐標點為AB邊中心點,延伸A點和B
也就是說A1360°朝向向左偏移90°,位移AB邊一半距離位A點,向右偏移90°位移AB邊一半距離為B點
A點和A1當前朝向位移AD邊距離得到D點,
B點和A1當前朝向位移AD邊距離得到C點,
三角形是以當前坐標點A點的朝向正前方為三角形A點,偏移120°和240°;
相當於是等角三角形等邊三角形;

1 // <editor-fold defaultstate="collapsed" desc="當前坐標點位中心點的等角(等邊)三角形,當前朝向位A點頂點延伸 static public PolygonCheck getTriangle(Vector vector, double x, double z, double vr)"> 2 /** 3 * 當前坐標點位中心點的等角(等邊)三角形,當前朝向位A點頂點延伸 4 * 5 * @param vector 6 * @param x 7 * @param z 8 * @param vr 中心點偏移位置 9 * @param vr_width 三角形,中心點距離頂點距離 10 * @return 11 */ 12 static public PolygonCheck getTriangle(Vector vector, double x, double z, double vr, double vr_width) { 13 14 if (vr != 0) { 15 /* 根據三角函數計算出 中心點 偏移量 */ 16 double v12_V_X = 0; 17 double v12_V_Y = 0; 18 if (vr < 0) { 19 /* 傳入負數的時候方向剛好是相反方向運動 */ 20 v12_V_X = -1 * vector.getDir_x() * getV12XD(vr, vector.getAtan()); 21 v12_V_Y = -1 * vector.getDir_z() * getV12ZD(vr, vector.getAtan()); 22 } else { 23 /* 正前方移動 */ 24 v12_V_X = vector.getDir_x() * getV12XD(vr, vector.getAtan()); 25 v12_V_Y = vector.getDir_z() * getV12ZD(vr, vector.getAtan()); 26 } 27 x += v12_V_X; 28 z += v12_V_Y; 29 } 30 31 Vector bVector = getVectorBy360Atan(getATan360(vector.getAtan360(), 120)); 32 Vector cVector = getVectorBy360Atan(getATan360(vector.getAtan360(), 240)); 33 34 double ax = x + (vector.getDir_x() * getV12XD(vr, vector.getAtan())); 35 double az = z + (vector.getDir_z() * getV12ZD(vr, vector.getAtan())); 36 37 double bx = x + (bVector.getDir_x() * getV12XD(vr, bVector.getAtan())); 38 double bz = z + (bVector.getDir_z() * getV12ZD(vr, bVector.getAtan())); 39 40 double cx = x + (cVector.getDir_x() * getV12XD(vr, cVector.getAtan())); 41 double cz = z + (cVector.getDir_z() * getV12ZD(vr, cVector.getAtan())); 42 43 PolygonCheck polygonCheck = new PolygonCheck(3); 44 polygonCheck.add(ax, az); 45 polygonCheck.add(bx, bz); 46 polygonCheck.add(cx, cz); 47 if (log.isDebugEnabled()) { 48 log.debug("A_X:" + ax + " A_Y:" + az); 49 log.debug("B_X:" + bx + " B_Y:" + bz); 50 log.debug("C_X:" + cx + " C_Y:" + cz); 51 } 52 return polygonCheck; 53 } 54 // </editor-fold> 55 56 // <editor-fold defaultstate="collapsed" desc="90°朝向矩形,以傳入的坐標點為AB邊中心點距離 static public PolygonCheck getRectangle(Vector vector, double x, double y, double vr, double vr_width, double vr_hight)"> 57 /** 58 * 90°朝向矩形,以傳入的坐標點為AB邊中心點距離 59 * 60 * @param vector 當前朝向 61 * @param x 當前坐標點 62 * @param z 當前坐標點 63 * @param vr 原點偏移量,AB編中心點90°偏移量 偏移,正前方(正數)或者正后方(負數)米數 64 * @param vr_width 偏移量,矩形的寬度,左右各偏移0.2m直線是0.4m 65 * @param vr_hight 偏移量高,矩形的長度 66 * @return 67 */ 68 static public PolygonCheck getRectangle(Vector vector, double x, double z, double vr, double vr_width, double vr_hight) { 69 //寬度修正 70 vr_width = vr_width / 2; 71 72 Vector aVector = getVectorBy360Atan(getATan360(vector.getAtan360(), -90)); 73 Vector bVector = getVectorBy360Atan(getATan360(vector.getAtan360(), 90)); 74 75 if (vr != 0) { 76 /* 根據三角函數計算出 中心點 偏移量 */ 77 double v12_V_X = 0; 78 double v12_V_Y = 0; 79 if (vr < 0) { 80 /* 傳入負數的時候方向剛好是相反方向運動 */ 81 v12_V_X = -1 * vector.getDir_x() * getV12XD(vr, vector.getAtan()); 82 v12_V_Y = -1 * vector.getDir_z() * getV12ZD(vr, vector.getAtan()); 83 } else { 84 /* 正前方移動 */ 85 v12_V_X = vector.getDir_x() * getV12XD(vr, vector.getAtan()); 86 v12_V_Y = vector.getDir_z() * getV12ZD(vr, vector.getAtan()); 87 } 88 x += v12_V_X; 89 z += v12_V_Y; 90 } 91 92 /* 根據三角函數計算出 A 點偏移量 */ 93 double v12_A_X = aVector.getDir_x() * getV12XD(vr_width, aVector.getAtan()); 94 double v12_A_Y = aVector.getDir_z() * getV12ZD(vr_width, aVector.getAtan()); 95 /* 由於在計算12方向位移函數里面已經計算偏移量是正負值 */ 96 double A_X = x + v12_A_X; 97 double A_Y = z + v12_A_Y; 98 99 /* 根據三角函數計算出 B 點偏移量 */ 100 double v12_B_X = bVector.getDir_x() * getV12XD(vr_width, bVector.getAtan()); 101 double v12_B_Y = bVector.getDir_z() * getV12ZD(vr_width, bVector.getAtan()); 102 /* 由於在計算12方向位移函數里面已經計算偏移量是正負值 */ 103 double B_X = x + v12_B_X; 104 double B_Y = z + v12_B_Y; 105 106 /* 根據三角函數計算出 C 或者 D 點偏移量 */ 107 double v12_CD_X = vector.getDir_x() * getV12XD(vr_hight, vector.getAtan()); 108 double v12_CD_Y = vector.getDir_z() * getV12ZD(vr_hight, vector.getAtan()); 109 110 /* C 點應該是 B 點的垂直方向也就是原來玩家的移動方向 由於在計算12方向位移函數里面已經計算偏移量是正負值*/ 111 double C_X = B_X + v12_CD_X; 112 double C_Y = B_Y + v12_CD_Y; 113 /* D 點應該是 A 點的垂直方向也就是原來玩家的移動方向 由於在計算12方向位移函數里面已經計算偏移量是正負值*/ 114 double D_X = A_X + v12_CD_X; 115 double D_Y = A_Y + v12_CD_Y; 116 117 PolygonCheck polygonCheck = new PolygonCheck(4); 118 polygonCheck.add(A_X, A_Y); 119 polygonCheck.add(B_X, B_Y); 120 polygonCheck.add(C_X, C_Y); 121 polygonCheck.add(D_X, D_Y); 122 if (log.isDebugEnabled()) { 123 log.debug("A_X:" + A_X + " A_Y:" + A_Y); 124 log.debug("B_X:" + B_X + " B_Y:" + B_Y); 125 log.debug("C_X:" + C_X + " C_Y:" + C_Y); 126 log.debug("D_X:" + D_X + " D_Y:" + D_Y); 127 } 128 return polygonCheck; 129 } 130 //</editor-fold> 131 132 public static void main(String[] args) { 133 double x1 = 20, z1 = 20, x2 = 20, z2 = 10; 134 Vector v12Vector = getV12Vector(x1, z1, x2, z2); 135 136 log.error("當前朝向:" + v12Vector); 137 138 // double v12X = v12Vector.getDir_x() * getV12X(1d, v12Vector.getAtan()); 139 // log.error("當前位移量-x:" + v12X); 140 // double v12Z = v12Vector.getDir_z() * getV12Z(1d, v12Vector.getAtan()); 141 // log.error("當前位移量-y:" + v12Z); 142 // double aTan = getATan360(v12Vector.getAtan360(), -10); 143 // log.error("修正后的角度:" + aTan); 144 // double aTanDir = getATan360(v12Vector.getAtan360(), 10); 145 // log.error("修正后的角度:" + aTanDir); 146 // 147 // if (aTan > aTanDir) { 148 // log.error("修正后的夾角:" + aTan + " ~ 360 和 0 ~" + aTanDir); 149 // } else { 150 // log.error("修正后的夾角:" + aTan + " ~ " + aTanDir); 151 // } 152 // aTan = getATan360(aTan, -10); 153 // log.error("修正后的角度:" + aTan); 154 // aTanDir = getATan360(aTanDir, -10); 155 // log.error("修正后的角度:" + aTanDir); 156 // 157 // if (aTan > aTanDir) { 158 // log.error("修正后的夾角:" + aTan + " ~ 360 和 0 ~" + aTanDir); 159 // } else { 160 // log.error("修正后的夾角:" + aTan + " ~ " + aTanDir); 161 // } 162 PolygonCheck rectangle = getTriangle(v12Vector, x1, z1, 0, 4); 163 164 log.error("三角形:" + rectangle.isInPolygon(19, 19)); 165 166 }
測試結果
1 --- exec-maven-plugin:1.2.1:exec (default-cli) @ net.sz.game.engine --- 2 [02-15 20:33:34:0522:ERROR: utils.MoveUtil.main():678] -> 當前朝向:dir=6, dir_x=1, dir_z=-1, atan=90.0, atan360=180.0 3 [02-15 20:33:34:0525:DEBUG: utils.MoveUtil.getTriangle():590] -> A_X:20.0 A_Y:20.0 4 [02-15 20:33:34:0526:DEBUG: utils.MoveUtil.getTriangle():591] -> B_X:20.0 B_Y:20.0 5 [02-15 20:33:34:0526:DEBUG: utils.MoveUtil.getTriangle():592] -> C_X:20.0 C_Y:20.0 6 [02-15 20:33:34:0526:ERROR: utils.MoveUtil.main():706] -> 三角形:false 7 ------------------------------------------------------------------------
以上是在攻擊傷害范圍攻擊計算公式;
該公式還夾雜着算偏移量,比如神龍boos(擺尾技能)攻擊的是boos朝向的正后方,一個扇形范圍;
總要的是提供一種思路已經解決訪問,
此次思路最總要的地方在於我們任何方向表示都采用360°圓形無死角計算,提供的精確度是小數的后4位算法;
在攻擊場景對象的時候,就可以做到像MOBa游戲一樣的進准度測試
傷害范圍彈道飛行
本處只提供解決方案而不提供解決代碼;
僅供參考
思路方案是根據彈道飛行速度,計算間隔時間執行比如50ms飛行距離;
我們以扇形為例:
我們得到一個扇形V;扇形的半徑是VR=5
然后我們從A點開始計算,每50ms計算一次飛行距離;
第一次飛行我們得到V1然后計算V1里面可攻擊對象,坐標點半徑小於V1,
第二次飛行,間隔50ms以后,我們計算出V2,那么這時候,
我們需要計算可攻擊的對象的距離是大於V1半徑小於V2半徑位置;
這樣就能得到彈道飛行中獲取可攻擊對象的傷害計算方式;
矩形其實同理計算的;