📦 jkjkil4 / PolygonBorderAdvanced

📄 README.md · 109 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109# PolygonBorderAdvanced

更完善的多边形框  
基于布尔运算进行加减  

更简单的版本:[https://gitee.com/jkjkil4/PolygonBorder](https://gitee.com/jkjkil4/PolygonBorder)

### 介绍
在GMS2(2.3以上版本)中可用的多边形限制框

### 功能
以下列出了我实现的功能
- **判断点是否在框内**
- **得到点与多边形框最近的位置(用于在出框后限制回框内)**
- **对多边形内部区域进行遮罩(将显示范围限制在框内,[示例3](objects/oDemo3)中有涉及)**
- **多边形框旋转**
- **多边形框布尔运算(“加框”和“减框”,[示例2](objects/oDemo2)和[示例3](objects/oDemo3)中有涉及)**

### 使用
- 创建框
    - oPolyBorderAdv 是框的对象
    - 使用 **instance_create_depth** 或 **instance_create_layer** 创建一个框  
    为了方便描述,后文称该框为 **poly**
- 编辑顶点
    - **poly.verts** 为存储多边形的顶点的数组
    - 例如 `poly.verts = [[0, 0], [50, 50], [-50, 50]];`  
    即可将多边形顶点设置为 **(0, 0)**、**(50, 50)**、**(-50, 50)**
    - 其他操作如删除顶点等就不再赘述,对 **verts** 进行操作即可
    - *注:添加的顶点坐标都是相对与多边形原点而言的*
- 加框和减框
    - 每个 oPolyBorderAdv 的实例都使用 **operFlag** 来控制是加框还是减框  
    **OperateFlag.OF_Add** 表示“加框”,**OperateFlag.OF_Sub** 表示“减框”
    - 使用 `mixPoly([poly1, poly2, ...])` 来得到加减后的结果
    - 比如该情况下表示两框相加:
        ```javascript
        ...
        // 默认 OF_Add,不写也行
        poly1.operFlag = OperateFlag.OF_Add;    // “加框”
        poly2.operFlag = OperateFlag.OF_Add;    // “加框”
        mixed = mixPoly([poly1, poly2]);    // 两框相加的结果
        ```
    - 再比如该情况下表示两框相减:
        ```javascript
        ...
        poly1.operFlag = OperateFlag.OF_Add;    // “加框”
        poly2.operFlag = OperateFlag.OF_Sub;    // “减框”
        mixed = mixPoly([poly1, poly2]);    // 两框相减的结果
        ```
    - 如果传入更多的多边形,则按顺序进行运算:
        ```javascript
        ...
        /* poly1, poly2, poly3 的 operFlag 分别为 OF_Add, OF_Sub, OF_Add */
        mixed = mixPoly([poly1, poly2, poly3]); // poly1 先减去 poly2,再加上 poly3
        ```
    - 加减后的结果,是以数组方式存储的边,可以用于 isPointInsidePolylines、limitPoint等,将在后文提到
- 将点限制在框内
    - 为了将点限制在框内,首先要判断是否出框 
        - 使用 `isPointInsidePolylines(x, y, lines)` 即可判断 **(x, y)** 是否在框内
        - 其中 **lines** 表示一个数组,其中存放的是多边形的边,使用上文提到的 **mixPoly(\[...\])** 来得到  
    - 如果出框的话,就需要得到离边框最近的位置
        - 使用 `limitPoint(x, y, lines)` 即可得到 **(x, y)** 离 **lines** 最近的位置  
        返回值是一个长度为2的数组,下标 **0、1** 分别是结果的 **x、y** 
    - 所以最终的做法就是(如[示例1](objects/oDemo1)):
        ```javascript
        // 步事件(Step Event)
        var lines = mixPoly([poly]);    // 得到边

        if !isPointInsidePolylines(playerX, playerY, lines) {   //判断是否在内部
            var pos = limitPoint(playerX, playerY, lines);  //如果不在内部则得到限制结果
            playerX = pos[0];
            playerY = pos[1];
        }
        ```
- 对多边形框内部进行遮罩
    - 当你需要用到遮罩时,需要在对顶点进行更改之后  
    调用 `poly.updateTriangles()` 来更新多边形的三角剖分
    - 为了使用遮罩,你需要创建一个表面(Surface),一般和屏幕大小一致  
    为了方便描述,后文称该表面为 **surf**
    - 与 `mixPoly([...])` 类似,调用 `mixAlpha([..])` 即可使用遮罩,(如[示例3](objects/oDemo3)):
        ```javascript
        //绘制事件(Draw Event)
        if !surface_exists(surf)    //当surf凭空消失时重新创建
            surf = surface_create(/* 宽 */, /* 高 */);
        
        surface_set_target(surf);   //设置在surf上绘制
        
        /* 
            这里写想要被遮罩的东西 
            (一般最开始先draw_clear或draw_clear_alpha清空原有内容,然后再绘制东西)
        */

        clearAlpha(0);      // 将 surf 上的透明度全部设置为 0(完全透明)
        mixAlpha([...]);    // 根据多边形来对透明度进行修改

        surface_reset_target();     // 设置在屏幕上绘制
        draw_surface(surf, 0, 0);   // 绘制 surf
        ```
- 多边形框旋转
    - 调整 **poly.rot** 即可调整旋转角度(顺时针)
    - 调整 **poly.rotSpeed** 即可调整旋转的速度  
    如 `poly.rotSpeed = 3;` 就是让框每步旋转3度

### 已知缺点
- 当在拐角移动时,可能穿过拐角(不会出框,原本是要绕过去)
- 只能限制点(对于较小的物体实际上也可以当成一个点)
- 编辑不便
- 使用多个框时,如果两个框有两条边比较近,但是没有合并在一起  
玩家移动时也有可能跨越这两个多边形