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

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

  • 相关阅读:
    排查线上问题常用的几个Linux命令
    OAuth2简易实战(一)-四种模式
    程序员必备的网站推荐
    C++ sizeof
    C++ 求余运算符
    C++ mutable(可变的)
    C++ const_cast用法
    C++常变量和文字常量
    C++中 <iso646.h>头文件
    java-网络编程-使用URLDecoder和URLEncoder
  • 原文地址:https://www.cnblogs.com/shizuchengxuyuan/p/5977682.html
Copyright © 2011-2022 走看看