精华内容
下载资源
问答
  • 直连路由、静态路由:直连路由:接口配置正确的IP地址和掩码,物理UP和协议...注:静态路由的下一跳可以不是直连路由,路由器会使用递归路由进行多次查询当网络拓扑发生变化时,静态路由不会自动适应拓扑改变,而是...

    直连路由、静态路由:

    直连路由:接口配置正确的IP地址和掩码,物理UP和协议UP

    静态路由:由管理员手动配置和维护的路由。静态路由配置简单,并且无需像动态路由那样占用路由器的CPU资源来计算和分析路由更新,度量值为0。

    条件:出接口状态物理UP和协议UP且下一跳地址一定需要可达。

    注:静态路由的下一跳可以不是直连路由,路由器会使用递归路由进行多次查询

    当网络拓扑发生变化时,静态路由不会自动适应拓扑改变,而是需要管理员手动进行调整。静态路由一般适用于结构简单的网络。

    aef9d9a114f9c069fcc849195ec3e5eb.png

    1、负载分担:

    当源网络和目的网络之间存在多条链路时,可以通过等价路由来实现流量负载分担。这些等价路由具有相同的目的网络和掩码、管理距离和度量值。

    在RTB上配置了两条静态路由,它们具有相同的目的IP地址和子网掩码、管理距离(都为1)、度量值(都为0),但下一跳不同。在RTB需要转发数据给RTA时,就会使用这两条等价静态路由将数据进行负载分担。

    2、路由备份/浮动静态路由:

    在配置多条静态路由时,可以修改静态路由的管理距离,使一条静态路由的管理距离高于其他静态路由,从而实现静态路由的备份,也叫浮动静态路由。

    RTB上配置了两条静态路由。正常情况下,这两条静态路由是等价的。通过配置路由的管理距离,使第二条静态路由的管理距离要高于第一条。路由器只把管理距离低的静态路由加入到路由表中。当加入到路由表中静态路由出现故障时,优先级高的静态路由才会加入到路由表并承担数据转发。

    注:在静态路由配置后面加上permanent,可以使得该条静态路由永久有效(除非使用命令clear ip route *)。

    cbfe7a45c677c91ffc72472622700c17.png

    3、路由过滤:在某种路由协议中,将一个接口宣告进该协议,会实现对于该协议报文的收发,被宣告进该协议的接口路由以及通过这些接口获悉的邻居传递过来的属于该协议并加入路由表的路由;在距离矢量环境中,可以使用静态路由实现对某条路由条目的传递过滤,但在链路状态协议中是无效的。

    423e55f606ec97fa8ebae7768866a46b.png

    4、递归表查询:

    分析:当管理员使用静态路由时,只配置了下一跳地址没有出接口时,路由器会先查找路由表,匹配了这条静态之后,再进行二次查表,确定出接口之后才能进行数据转发,这就是递归查询,这样五无疑会增加路由器的CPU消耗,所以建议管理员在配置静态路由时,后面加上出接口和下一跳地址。

    5、递归路由:

    分析:假如R4后面有一个园区网,大约有N条路由,如果使用常规方式写静态路由,工作量非常大且无法在R2/R3上实现负载均衡;可以使用递归路由解决这个问题;先在R1写N条去往R4身后园区网的静态路由,下一跳使用R4 e0/0接口的地址,在R1写一条递归路由,出接口、下一跳使用R2/R3 e0/0接口地址。

    注:写主静态路由时一定不能包含出接口,否则路由器就不会执行递归表查询了。

    6、服务等级协议SLA:一种网络性能测量和诊断工具,通过主动在多个端点之间发送探针/测试报文(使用协议有ICMP、TCP、UDP等等),对网络性能和服务质量进行分析,并为用户提供网络服务质量的各种参数,例如:网络服务评估、网络故障诊断、抖动延迟,文件传输速率,TCP时延等等。

    注:可以使用SLA联动浮动静态路由,路由器可以更清晰的感知一条完整链路的运行状态,当主路径down了,可以实时的进行链路切换。

    9ae7d7a90cfe892cc9ba530907245163.png

    分析:园区R1和园区R2之间通过使用浮动静态路由实现互联,园区之间申请了一根电信线路作为主路径,另外一根移动线路作为备用路径;在使用常规的浮动静态路由时,当电信内网R2、R3、R5之间的链路出现故障时,静态路由是不会感知到链路故障,down掉主路径的静态路由自动切换到备份路径的;当使用SLA联动浮动静态路由时,SLA会周期性发送探针探测整条主路径的状态,当主路径某一位置出现故障时,主路径路由就会自动从R1的路由表中消失,移动的备份路径就会出现在R1的路由表进行数据转发。

    7、黑洞路由和路由黑洞

    NULL0口是个伪接口,不能配置地址也不能被封装,接口总是UP状态;但是从来不转发或接受任何数据流量,对于所有发到该接口的数据都会直接被丢弃;在配置静态路由时,把出接口指向null0接口的路由就被称为黑洞路由;在一些使用路由汇总或聚合的情况中,正确使用黑洞路由可以消除路由环路。

    ip route 10.0.0.0 255.255.0.0 null0(黑洞路由相当于是出现故障情况下的备用路由,所以可以把该条静态黑洞路由的优先级设置低一点(值大一点))

    展开全文
  • OpenCV实现微信跳一跳

    千次阅读 2018-01-23 13:11:47
    在前段时间因为要考试,所以没有怎么写程序,考试结束了,这几天重新搞了搞,到1.22晚上终于把算法改进地差不多了,写这篇博客记录一下。 完整的源码在我的github上:https://github.com/myzcl/WeChat-Jump 后续...

    OpenCV实现微信跳一跳

    最近微信上的跳一跳可是非常火,因为自己又对计算机视觉有感兴趣,所有就想写一个程序,实现自动跳一跳。在前段时间因为要考试,所以没有怎么写程序,考试结束了,这几天重新搞了搞,到1.22晚上终于把算法改进地差不多了,写下这篇博客记录一下。
    完整的源码在我的github上:https://github.com/myzcl/WeChat-Jump
    后续更新都会在Github上。

    github上有一个项目已经很成熟了,大家可以去看一看
    https://github.com/wangshub/wechat_jump_game
    微信现在已经加大反作弊的力度了
    这里写图片描述

    adb工具使用

    adb配置

    adb工具主要是为了与Android手机进行通讯,实现获取屏幕截图和按压屏幕等操作。adb工具包在网上搜一下就可以下载到。如果不想下载的话,在这有网盘链接:
    链接:https://pan.baidu.com/s/1mjRVRZy 密码:cz7w
    adb工具环境变量的配置。将adb工具报的路径添加到环境变量中,如我的路径是D:\Program Files\ADB\platform-tools-latest-windows\platform-tools,如图:
    这里写图片描述
    就将这个目录添加到环境变量中,如图:
    这里写图片描述
    adb命令使用详解,在网上找到有个讲的非常好的文章,分享一下:http://blog.csdn.net/u010375364/article/details/52344120

    遇到的问题:

    在运行指令时,可能会遇到这种情况,出现这种情况的原因是,端口被手机助手给占用了。详情见http://blog.csdn.net/liguilicsdn/article/details/50902194
    这里写图片描述
    解决的方法就是打开任务管理器,结束相关进程,如图:
    这里写图片描述

    C++调用Python

    因为最近在学习python,所以就用Python调用adb命令,再通过C++调用Python,Python的按抓个方法再此就不赘述了,主要讲一下调用Python遇到的问题。

    遇到的问题

    1.配置问题
    配置步骤和VS下配置OpenCV一样,如图:
    这里写图片描述
    这里写图片描述
    这里写图片描述
    2.x64配置
    因为Python我用的是x64版本,所以在VS中也得选择成x64版本,不然会报错:
    这里写图片描述
    3.向Python传参数
    C++调用Python一般的方法大家可自行百度,需要注意的是:
    一定要设定Python文件的目录,例如我的是:
    PyRun_SimpleString("sys.path.append('E:/vs2013test/3.py-test/py-test')");
    否则会找不到Python文件。
    传递参数可参考以下代码:

        //按压屏幕
    void press(int x1, int y1, int x2, int y2, int dist)
    {
        Py_Initialize();    //初始化Python
    
        // 检查初始化是否成功  
        if (!Py_IsInitialized())
            cout << "python init failed!" << endl;
    
        PyRun_SimpleString("import os");
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('E:/vs2013test/3.py-test/py-test')");   //设定Python路径
        PyObject *pModule = NULL;
        PyObject *pFunc = NULL;
        PyObject *pArg = NULL;
        PyObject *pResult = NULL;
    
        pModule = PyImport_ImportModule("py_called");   //找到Python文件
        if (!pModule)
            cout << "pModule erro!" << endl;
    
        //pFunc = PyObject_GetAttrString(pModule, "add_func");  //找到add_func函数
        //pArg = Py_BuildValue("(i,i)", 10, 25);    //传入参数 两个整形的参数
        //pResult = PyEval_CallObject(pFunc, pArg); //执行函数
    
        pFunc = PyObject_GetAttrString(pModule, "press_value");
        pArg = Py_BuildValue("(i, i, i, i, i)", x1, y1, x2, y2, dist);
        PyEval_CallObject(pFunc, pArg);
    
        Py_Finalize();  //关闭Python  
    }

    OpenCV算法

    检测的思路是这样的:
    1.0:因为棋子的形状,大小不发生变化,所以采用的就是简单暴力的模板匹配。关于下一个目标点,原先采用的是Canny算法,找到目标的轮廓,然后通过预估,确定目标点。但是实验了几次以后,感觉效果不是很好,当背景和目标的颜色相近是,就会检测不到边缘,导致目标点不准确。最后采用的是图像的特征进行识别。用这个方法,全自动跳只能跳一百多分。
    2.0:通过分析可知,目标的周围都是背景,并且目标一直处于背景最上部,所以可以每一行每一行进行检测,设定阈值,当检测到到从背景到目标,记录这个位置,在此基础上,再检测到由目标到背景,再记录这个位置,最后,两个位置进行求均值。经过实验,这个方法的准确性非常高。
    具体代码:
    main.cpp

    #include <math.h>
    #include <iostream>
    #include <Python.h>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    //二值化
    void mythreshold(Mat &img, uchar T)
    {
        int n1 = img.rows;
        int nc = img.cols * img.channels();
        if (img.isContinuous())//判断图像是否连续
        {
            nc = nc * n1;
            n1 = 1;
        }
        for (int i = 0; i < n1; i++)
        {
            uchar *p = img.ptr<uchar>(i);
            for (int j = 0; j < nc; j++)
            {
                if (p[j] < T)
                    p[j] = 0;
                else p[j] = 255;
            }
        }
    }
    
    //获取截图
    void get_screen()
    {
        Py_Initialize();    //初始化Python
    
        // 检查初始化是否成功  
        if (!Py_IsInitialized())
            cout << "python init failed!" << endl;
    
        PyRun_SimpleString("import os");
        PyRun_SimpleString("os.system('adb shell screencap -p //sdcard//src.png')");
        int py_test = PyRun_SimpleString("os.system('adb pull //sdcard//src.png')");
        if (py_test != -1)
            cout << "获取截图成功" << endl;
        else cout << "获取截图失败" << endl;
    
        Py_Finalize();  //关闭Python  
    }
    
    //按压屏幕
    void press(int x1, int y1, int x2, int y2, int dist)
    {
        Py_Initialize();    //初始化Python
    
        // 检查初始化是否成功  
        if (!Py_IsInitialized())
            cout << "python init failed!" << endl;
    
        PyRun_SimpleString("import os");
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('E:/vs2013test/3.py-test/py-test')");   //设定Python路径
        PyObject *pModule = NULL;
        PyObject *pFunc = NULL;
        PyObject *pArg = NULL;
        PyObject *pResult = NULL;
    
        pModule = PyImport_ImportModule("py_called");   //找到Python文件
        if (!pModule)
            cout << "pModule erro!" << endl;
    
        //pFunc = PyObject_GetAttrString(pModule, "add_func");  //找到add_func函数
        //pArg = Py_BuildValue("(i,i)", 10, 25);    //传入参数 两个整形的参数
        //pResult = PyEval_CallObject(pFunc, pArg); //执行函数
    
        pFunc = PyObject_GetAttrString(pModule, "press_value");
        pArg = Py_BuildValue("(i, i, i, i, i)", x1, y1, x2, y2, dist);
        PyEval_CallObject(pFunc, pArg);
    
        Py_Finalize();  //关闭Python  
    }
    
    //获取棋子位置
    void loca_start(Mat img_src, Mat img_model, Point &point)
    {
        /************************************模板匹配****************************************/
    
        //创建输出结果的矩阵
        int result_cols = img_src.cols - img_model.cols + 1;
        int result_rows = img_src.rows - img_model.rows + 1;
        Mat result(Size(result_cols, result_rows), CV_8UC1, Scalar(0));
    
        //进行匹配和标准化
        int match_method = 3;//选择 匹配的方式
        /*  
            CV_TM_SQDIFF = 0,
            CV_TM_SQDIFF_NORMED = 1,
            CV_TM_CCORR = 2,
            CV_TM_CCORR_NORMED = 3,
            CV_TM_CCOEFF = 4,
            CV_TM_CCOEFF_NORMED = 5
        */
        matchTemplate(img_src, img_model, result, match_method);
        normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
    
        // 通过函数 minMaxLoc 定位最匹配的位置
        double minVal; double maxVal; Point minLoc; Point maxLoc;
        minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
    
        // 对于方法 SQDIFF 和 SQDIFF_NORMED, 越小的数值代表更高的匹配结果. 而对于其他方法, 数值越大匹配越好
    
        Point matchLoc;
        if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
        {
            matchLoc = minLoc;
            //cout << "匹配相似度为:" << minVal * 100 << endl;
        }
        else
        {
            matchLoc = maxLoc;
            //cout << "匹配相似度为:" << maxVal * 100 << endl;
        }
    
    
        //画出棋子位置
        //rectangle(img_src, matchLoc, Point(matchLoc.x + img_model.cols, matchLoc.y + img_model.rows), Scalar(0, 255, 0), 2);
    
        //画出中心位置
        Point point_cir = Point(matchLoc.x + (img_model.cols >> 1), matchLoc.y + img_model.rows - 8);
        //circle(img_src, point_cir, 5, Scalar(0, 0, 255), -1);
        point = point_cir;
    
        //imshow("result", result);
        /************************************模板匹配****************************************/
    }
    
    //获取目标位置
    void loca_next(Mat img_gray, Point point_start, Point &point_next)
    {
        Rect area_0(0, 0, (img_gray.cols >> 3) * 4, (img_gray.rows >> 2));
        if (point_start.x <= (img_gray.cols >> 1))      //棋子在左边
        {
            //area_0.x = (img_gray.cols >> 3) * 3;
            area_0.x = img_gray.cols >> 1;
            area_0.y = (img_gray.cols >> 1) + 50;
        }
        else
        {
            area_0.x = 10;
            area_0.y = (img_gray.cols >> 1) + 50;
            area_0.width = img_gray.cols >> 1;
        }
        画出下一个目标大体位置
        //rectangle(img_src, area_0, Scalar(0, 255, 0), 2);
    
        Mat img_scan = img_gray(area_0).clone();
    
        Point p_node1 = Point(0, 0);
        Point p_node2 = Point(0, 0);
        Point p_node = Point(0, 0);
        bool flag1 = false;
        for (int i = 5; i < img_scan.rows; i++)
        {
            bool flag = false;
    
            Vec3b *p = img_scan.ptr<Vec3b>(i);
            for (int j = 0; j < img_scan.cols - 1; j++)
            {
                int val_l = p[j + 1][0] + p[j + 1][1] + p[j + 1][2] - p[j][0] - p[j][1] - p[j][2];
                int val_r = p[j][0] + p[j][1] + p[j][2] - p[j + 1][0] - p[j + 1][1] - p[j + 1][2];
                if (val_l > 10 && flag1 == false)
                {
                    //cout << "1:" << val_l << endl;
                    p_node1.x = j;
                    p_node1.y = i;
                    flag1 = true;
                }
                if (val_r > 10 && flag1 == true)
                {
                    //cout << "2:" << val_r << endl;
                    p_node2.x = j;
                    p_node2.y = i;
                    flag = true;
                    break;
                }
            }
            if (flag == true)
                break;
        }
        if (p_node1.x != 0 && p_node2.y != 0)
        {
            //cout << "already" << endl;
            p_node.x = (p_node1.x + p_node2.x) >> 1;
            p_node.y = (p_node1.y + p_node2.y) >> 1;
            circle(img_scan, p_node1, 10, Scalar(255, 0, 0), -1);
            circle(img_scan, p_node2, 10, Scalar(255, 0, 0), -1);
            circle(img_scan, p_node, 10, Scalar(0), 2);
            p_node.x += area_0.x;
            p_node.y += area_0.y;
            point_next = p_node;
        }
    
        imshow("img_scan", img_scan);
    }
    
    //计算比例
    void dist(Point start, Point next, float &dist_val)
    {
        float xx = abs((float)next.x - (float)start.x);
        float distance = xx / cos(3.1415926 / 6);
    
        //float yy = abs((float)start.y - (float)next.y);
        //float distance = xx / sin(3.1415926 / 6);
    
        //int distance = sqrt(pow(next.x - start.x, 2) + pow(start.y - next.y, 2));
        dist_val = (float)distance * 2.8419 + 8.4488;   //dist_val = (float)distance * 2.8619 + 1.4488;
        cout << "距离:" << distance << "  按压时间:" << dist_val << endl;
    }
    
    Point point_mouse = Point(0, 0);
    void on_mouse(int event, int x, int y, int flags, void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号  
    {
        if (event == CV_EVENT_LBUTTONDOWN)//左键按下,读取初始坐标
        {
            point_mouse.x = x;
            point_mouse.y = y;
            //cout << "  鼠标值已更新" << point_mouse << endl;
        }
    }
    
    int main()
    {
        //通过鼠标确定下一位置(半自动)
        namedWindow("img_src");
        setMouseCallback("img_src", on_mouse, 0);//调用回调函数
    
        int count = 0;
        while (1)
        {
            //产生一定范围内的随机数,模拟手指进行按压,否则得分会被清除
            srand((int)time(NULL));
            int myrnd_x = (rand() % (800 - 700 + 1)) + 700 - 1;
            int myrnd_y = (rand() % (1500 - 1400 + 1)) + 1400 - 1;
    
            //得到手机截图
            get_screen();
    
            Mat img_src = imread("E:\\vs2013test\\3.py-test\\py-test\\src.png");
            resize(img_src, img_src, Size(img_src.cols >> 1, img_src.rows >> 1));   //540, 960
            //载入棋子模板
            Mat img_model = imread("E:\\vs2013test\\3.py-test\\py-test\\img_model.jpg");
            resize(img_model, img_model, Size(img_model.cols >> 1, img_model.rows >> 1));
    
            //模板匹配得到棋子位置
            Point point_start;
            loca_start(img_src, img_model, point_start);
            circle(img_src, point_start, 5, Scalar(0, 0, 255), -1);
    
            Mat img_gray;
            img_src.copyTo(img_gray);
            //cvtColor(img_src, img_gray, COLOR_BGR2GRAY);
    
    
            //边缘检测得到目标位置
            Point point_next;
            loca_next(img_gray, point_start, point_next);
            circle(img_src, point_next, 5, Scalar(0, 255, 0), -1);//画出下一个目标点
    
    
            /*通过鼠标获取位置*/
            //Point point_next;
            //point_next = point_mouse;
            //circle(img_src, point_next, 5, Scalar(0, 255, 0), -1);//画出下一个目标点
    
    
            imshow("img_src", img_src);
            waitKey(10);
    
    
            //起始点和目标点都存在,则发送指令
            if (point_start.x != 0 && point_start.y != 0 /*&& point_next.x != 0*/)
            {
                cout << "start: " << point_start << "  next: " << point_next << endl;
                float dist_val = 0;
                dist(point_start, point_next, dist_val);
    
    
                //发送指令按压屏幕
                press(myrnd_x, myrnd_y, myrnd_x, myrnd_y, (int)dist_val);
                count++;
                cout << "跳的次数:" << count << endl;
                cout << endl;
    
    
                鼠标位置清零
                //point_mouse.x = 0;
                //point_mouse.y = 0;
    
                char key = waitKey(1000);//一定的延时
            }
            //waitKey(0);
    
    
    
    
            //if (key == 27)
            //  break;
        }
    
        //system("pause");
        return 0;
    }

    下图就是用程序跳一跳的成绩截图:
    这里写图片描述

    总结与反思

    1.没做检测游戏结束的处理。今天早上试了一下,用的也是模板匹配,效果不好,就放弃了。
    2.还没能准确检测到目标的准确位置,现在的检测方法只是检测到了差不多准确的x方向的位置,对y方向还没有什么好的办法。
    如果大家有什么更好的算法,欢迎一起来讨论。

    QQ: 1570553025
    github: https://github.com/myzcl
    CSDN: http://blog.csdn.net/qq_36327203
    扫描二维码即可关注公众号:
    这里写图片描述

    展开全文
  • 前两天手机微信升级到了最新版,多了个跳一跳的游戏,无聊玩了几把,奈何手残,最高只玩到70多分,就想着能不能搞个工具辅助,于是有了下边的工具: 工具的简单原理如下: 根据前后两个方块的距离计算出一个按...

    前两天手机微信升级到了最新版,多了个跳一跳的游戏,无聊玩了几把,奈何手残,最高只玩到70多分大哭,就想着能不能搞个工具辅助下大笑,于是有了下边的工具:

    工具的简单原理如下:

    根据前后两个方块的距离计算出一个按下的时间,然后发送相应按下时间的touch事件给小程序,实现跳跃。

    将问题分解:

    1)怎样发送指定时间的touch事件给小程序?

      怎么简单怎么来 ,反正手机root了, 可以直接在shell下 使用‘input swipe 30 30 30 30 “ + 时间毫秒数(input swipe 30 30 30 30  500 就是长按500ms

    2)怎样计算按下时间?

      最简单的模型,  距离正比于时间, 怎么拿到比例? 人肉实验....吐舌头

    3)怎么计算距离?

    最笨的方法....手指点  然后代码计算两点的屏幕距离.

    问题都已经有解决方案 ,接下来设计交互方案:

    还是一切从简,试用android的悬浮窗, 在跳一跳小游戏上边加个蒙层,游戏开始后,每次跳跃时,手动点一个当前位置和即将跳跃的位置,获得屏幕距离, 辅助工具根据该距离计算出要长按的时间,发送一个长按的事件给跳一跳小程序,小程序完成跳跃。

    下边放上代码:

    https://github.com/cosmos-chou/jump_tool.git

    改工具使用需手机root,系统kitkat版本以上。我在三星s5和nexus 6p上实验过,可以使用,但是上边说的比例值略有差异,应用提供了设置项,可以根据自己手机手动调节,比例值越小,相同距离下按下的时间越长。

    使用方法:

    1),手动打开系统设置中相应应用的悬浮权限

    2),打开应用点击 running,屏幕上方会出现相应的工具栏

    3),进入跳一跳游戏,点击工具栏的START,出现蒙层

    4),点击当前位置和下一个要跳跃的位置,工具完成跳跃。




    展开全文
  • 最近刚好在《Cocos Creator游戏开发实战》中看到物理系统有个射线检测,于是,基于这个射线检测,写了个反复横的瞄准线效果。一起往看吧!文章底部获取完整项目!国际惯例,先上最终效果!在讲解之前我们...

    44dc51c2e7bd051999cc68191029311f.png
    最近有小伙伴问我瞄准线遇到各种形状该怎么处理?如何实现反复横跳的瞄准线?最近刚好在《Cocos Creator游戏开发实战》中看到物理系统有一个射线检测,于是,基于这个射线检测,写了一个反复横跳的瞄准线效果。一起往下看吧!文章底部获取完整项目!

    国际惯例,先上最终效果!

    d31feab8cd1dc8cd6ae20a0b50ce044c.gif

    在讲解之前我们需要一些向量的知识,简单的介绍一些吧!

    向量的加法,OA + AB = OB

    786929257067c4d2ba0530ac971f049f.png

    向量的点乘,表示一个向量在另一个向量上的投影,是个标量,有正负之分。向量夹角小于 90度 为正数,等于 90度 为 零,大于 90度 为负数。

    476d6f9dbb847eac1aaf5c0c7a0974ff.png

    向量的叉乘,结果为向量,正好垂直于两个向量构成的平面(右手系),也称为法向量。这里暂时没用到,顺便提一下。

    接下来进入正题,已知入射向量(单位向量),法向量(单位向量),如何得出反射向量?

    681443aa175f39eed126259253ddfae1.png

    我们将反射向量平移至入射向量起点,延长法向量与其相交,这个延长线的长度,刚好是 入射向量在法向量上的投影的相反数的两倍 。再根据投影和向量加法可以推出反射向量的计算公式。

    c8a7020b86f86c9252602532cbed6d6f.png

    清楚了么?不清楚也没关系,记得最后的公式就可以了,接下来进入 cocos creator 操作环节。

    既然是物理系统中的碰撞检测,我们在编辑器里添加的是物理系统中的碰撞器,而不是引擎的碰撞器,不要选错了哦。

    c52aededd3ccaf3156c10ed8533b0226.png

    不动的刚体类型设为 static ,添加完所有的物理碰撞器后如下所示。

    44ce7a7d826ffff24eafdf9ba1def23c.png

    用到物理引擎自然要把物理引擎打开。

    cc.director.getPhysicsManager().enabled = true;

    如何进行射线检测的?通过起始点、入射方向和剩余线段的长度获取射线检测的结果。如果检测到碰撞体,就画入射线段,并计算反射方向,再次进行射线检测;如果未检测到碰撞体,就把剩余线段画完。主要代码如下:

    /**
     * @description 计算射线
     * @param startLocation 起始位置 世界坐标系
     * @param vector_dir 单位方向向量
     */
    private drawRayCast(startLocation: cc.Vec2, vector_dir: cc.Vec2) {
        // 剩余长度
        const left_length = AIM_LINE_MAX_LENGTH - this._cur_length;
        if (left_length <= 0) return;
        // 计算线的终点位置
        const endLocation = startLocation.add(vector_dir.mul(left_length));
        // 射线测试
        const results = cc.director.getPhysicsManager().rayCast(startLocation, endLocation, cc.RayCastType.Closest);
        if (results.length > 0) {
            const result = results[0];
            // 指定射线与穿过的碰撞体在哪一点相交。
            const point = result.point;
            // 画入射线段
            this.drawAimLine(startLocation, point);
            // 计算长度
            const line_length = point.sub(startLocation).mag();
            // 计算已画长度
            this._cur_length += line_length;
            // 指定碰撞体在相交点的表面的法线单位向量。
            const vector_n = result.normal;
            // 入射单位向量
            const vector_i = vector_dir;
            // 反射单位向量
            const vector_r = vector_i.sub(vector_n.mul(2 * vector_i.dot(vector_n)));
            // 接着计算下一段
            this.drawRayCast(point, vector_r);
        } else {
            // 画剩余线段
            this.drawAimLine(startLocation, endLocation);
        }
    }

    如何画瞄准线小圈圈?通过结束位置和起始位置计算数量和间隔向量,画出一个个小圆圈。参考代码如下。

    /**
     * @description 画瞄准线
     * @param startLocation 起始位置 世界坐标系
     * @param endLocation 结束位置 世界坐标系
     */
    private drawAimLine(startLocation: cc.Vec2, endLocation: cc.Vec2) {
        // 转换坐标
        const graphic_startLocation = this.graphic_line.node.convertToNodeSpaceAR(startLocation);
        this.graphic_line.moveTo(graphic_startLocation.x, graphic_startLocation.y);
        // 画小圆圆
        // 间隔
        const delta = 20;
        // 方向
        const vector_dir = endLocation.sub(startLocation);
        // 数量
        const total_count = Math.round(vector_dir.mag() / delta);
        // 每次间隔向量
        vector_dir.normalizeSelf().mulSelf(delta);
        for (let index = 0; index < total_count; index++) {
            graphic_startLocation.addSelf(vector_dir)
            this.graphic_line.circle(graphic_startLocation.x, graphic_startLocation.y, 2);
        }
    }

    ff6dba2eaece499940f03893669c16ce.png

    完整代码

    9e700be0a8d2199de1143f932ce9f227.png

    展开全文
  • 注明:这篇文章是南大计算机系的周志华教授写的 在美求学的学生回国结婚,两口子专门来看我们。...我惊,怎么会这样,南大计算机最近几年上升很明显啊,怎么反倒让人觉得不行了? 细问之个主...
  • 最近刚好在《Cocos Creator游戏开发实战》中看到物理系统有个射线检测,于是,基于这个射线检测,写了个反复横的瞄准线效果。一起往看吧!文章底部获取完整项目! 国际惯例,先上最终效果! 在讲解之前...
  • 最近刚好在《Cocos Creator游戏开发实战》中看到物理系统有个射线检测,于是,基于这个射线检测,写了个反复横的瞄准线效果。一起往看吧!国际惯例,先上最终效果!在讲解之前我们需要一些向量的知识,简单...
  • 个坑到另个坑,这就是it男的苦逼生活,不管是做前端还是后端,或许你在上家公司挖了坑,没准你在下家公司就入了坑了,入职新公司个月时间(实际上还差天),那么我们就开始聊聊这个月我是怎么过来的 ...
  • 今天客户反应说他电脑,每次开机都报个错误,错误如图所示:目前没有可用的Internet连接。要查看已保存在您计算上的Internet内容,请单击“脱机工作”。单击“重试”,再连接次。查看原因是,只要电脑开机后,...
  • cout请输入需要赋值计算的多项式名称(提示:个大写字母):"; cin>>name; site=int(name-'A'); if(list[site].empty()) return wrong; display(name); cout请问:您确认要进行赋值计算吗?(Y/y):...
  • 面试大概不到个小时,整体面试感觉难度还行,问的都比较基础。之前打算放弃算法了,所以很多知识都没回顾,面试官人还挺好,我答不上来的就直接过 1.大部分时间还是围绕做的项目和研究展开提问【做了图像质量...
  • 右边的框找到 print spooler 这个服务(你可以键盘上按P,可以快速到P开头发服务) 双击,点击停止。 然后开始菜单-运行(也可以按win+R),输入spool,回车。会跳出个文件夹窗口,把printers文件夹(里面的...
  • 计算机组成.运动中的小数点.浮点数

    千次阅读 2016-05-11 10:15:11
    我又来复习了 上篇二进制那么多阅读量,,,小心脏怦怦,,, 后来发现我最后的复习计划也被列到目录中了,,,大概是这个原因吧 浮点数与科学记数法 ...十进制科学记数法,就是将个数表
  • 那么Windows系统下怎么安装Office2016呢?具体方法如下:Office 2016安装错误率略高 即使错误,不要灰心,按照步骤重复操作几遍,总会安装成功,如果电脑之前没有安装过office,直接到第二步安装步骤。第步,...
  • 前言在看这篇文章的时候对其中超时控制块儿有点好奇。通过时间轮来控制超时?啥是时间轮?怎么控制的?文章会先介绍常见的计时超时处理,再引入时间轮介绍及 netty 在实现时的一些细节,最后总结实现的一些优...
  • 直连路由、静态路由:直连路由:接口配置正确的IP地址和掩码,物理UP和协议...注:静态路由的下一跳可以不是直连路由,路由器会使用递归路由进行多次查询当网络拓扑发生变化时,静态路由不会自动适应拓扑改变,而是...
  • 直连路由、静态路由:直连路由:接口配置正确的IP地址和掩码,物理UP和协议...注:静态路由的下一跳可以不是直连路由,路由器会使用递归路由进行多次查询当网络拓扑发生变化时,静态路由不会自动适应拓扑改变,而是...
  • 在美国怎么样找工作

    千次阅读 2012-06-29 21:05:51
    和大多数误入EE的朋友一样,高考填志愿之时总有个大山炮出来宣称计算机专业已经饱和,毕业不好找工作云云。选了个专业自称光机电算全部涵盖,到最后我是什么也没学会,大学四年唯一学术突破就是考了个还像样...
  • 为了让沫沫能非常愉快的享受这次聚餐,善解人意的灰灰和渣渣决定帮他计算,他们应该怎么选择菜才能使沫沫最开心地吃完这次聚餐。 输入格式: 第行是个整数T,(T )表示测试案例的个数 对于每个测试...
  • 图:2.选择语句2.1最简单的if语句Python使用保留字if来组成选择语句,其格式如下:if表达式:代码块表达式可以是个单纯的布尔值或者变量,也可以是比较表达式或者逻辑表达式,如果表达式值为真,则执行“代码...
  • 静态路由跨网段访问配置方法和...静态路由有5个主要的参数:目的地址和掩码、出接口和下一跳、优先级。使用静态路由的好处是配置简单、可控性高,当网络结构比较简单时,只需配置静态路由就可以使网络正常工作。在复...
  • 原文:《Python 数据分析与数据化运营》第4章:过运营数据分析和挖掘的“大坑”聚类是数据挖掘和计算的基本任务,是将大量数据集中具有“相似”特征的数据点或样本划分为个类别。聚类常用于数据探索或挖掘前期,...
  • 为了让沫沫能非常愉快的享受这次聚餐,善解人意的灰灰和渣渣决定帮他计算,他们应该怎么选择菜才能使沫沫最开心地吃完这次聚餐。 输入格式: 第行是个整数T,(T )表示测试案例的个数 对于每个测试案例,...
  • 数据是如何传递到服务器上,服务器是如何把数据传送到客户端。 客户端若想访问网页,访问域名...数据包:第一块是数据本身,ip地址决定了最终到哪去,mac地址决定了下一跳怎么走。 注意路由器和交换机的区别!! ...
  • 这个代码怎么实现? 或者在网上看到段代码,不太会改, fo = open('dic_test.txt', 'w+', encoding='UTF-8') 这行嘛意思? 加行代码去停用词...
  • 计算机并不像人,它只能识别机器语言,我们学的高级编程语言在通过编译后转化成机器语言,再由CPU的寄存器进行运算和存储处理,顺序执行时,决定程序流程的程序计数器通过地址的+1一直就是下一下一条。条件分支和...
  • 1、下一跳地址是怎么来的? 2、下一跳地址是唯一的吗? 3、下一跳地址是最佳的吗? 4、路由器那么多,它们如何协同工作? 那么用什么样的算法去解决此问题呢? 每一个顶点表示一个网络、路由器或计算机 每...
  • 我的职业生涯

    2008-10-14 01:07:00
    在计算机这行混了9年了,上班也上了五年了,自从从我的第个软件公司出去以后,一直想写点东西,方面是对自己软件生涯的个小节,另外方面也想对那个公司的成败说一些自己的看法,但是一直都没想好怎么写,...
  • 下一跳地址是怎么来的? ◆ 下一跳地址是唯一的吗? ◆ 下一跳地址是最佳的吗? ◆ 路由器怎么多,他们是怎么协同工作的? 需要一个好的算法去解决这些事情! 路由算法实际上是图论的算法 路由算法要比图论的算法...

空空如也

空空如也

1 2 3 4 5 6
收藏数 108
精华内容 43
关键字:

怎么计算下一跳