一个简易的画线刚体Demo
效果
抱歉,放错图了,以上是 孙二喵 iwae
https://forum.cocos.org/t/topic/142673[1] 的效果图。本Demo是根据文章的思路,合成的代码。首先,感谢孙二喵的技术分享。
以下是最终效果图
使用
版本 Cocos Creator 3.8.1
创建一个
Empty(2D)
项目
保存场景,新建一个
Game.ts
脚本,把代码复制进去(代码在最后面)
拖入
Game.ts
脚本至场景中
(可选)在场景中添加一些静态刚体和碰撞体
运行预览
原理
坐标转换
触点坐标转到节点坐标
getUILocation
UITransform.convertToNodeSpaceAR
推荐阅读纯干货!一文搞懂 Cocos Creator 3.0 坐标转换原理
https://mp.weixin.qq.com/s/mV5EY4NMrpgCP9XFocrcGA
计算碰撞体
首先问题分解:已知:
两个点的坐标
线宽
求:
围成该线段的四个点的坐标
回顾一下,2D中的旋转的矩阵是:
旋转90度的矩阵为
旋转-90度的矩阵为
先计算方向向量,然后2个垂直方向的向量,分别乘以我们线段一半的宽度,最后起始点和结束点分别加上这2个向量,4个路径点
//方向向量
d = (end - start).normalize();
//垂直向量1
d1 = R_1 * d = (d.y,-d.x)
//垂直向量2
d2 = R_2 * d = (-d.y,d.x)
//求4个点
p1 = start + d1 * widhtHalf
p2 = start + d2 * widhtHalf
p3 = end + d1 * widhtHalf
p4 = end + d2 * widhtHalf
代码
import { _decorator, Component, EventTouch, find, Node, macro, Graphics, v2, Vec2, UITransform, v3, Color, RigidBody2D, PolygonCollider2D, PhysicsSystem2D } from 'cc';
const { ccclass, property } = _decorator;const __tempV2 = v2()
const __tempV3 = v3()type TypePoint = {x: number,y: number
}@ccclass('Game')
export class Game extends Component {private _canvasNode: Nodestart() {macro.ENABLE_MULTI_TOUCH = false;PhysicsSystem2D.instance.debugDrawFlags = 1;this._canvasNode = find("Canvas")this._canvasNode.on(Node.EventType.TOUCH_START, this.onTouchStart, this)this._canvasNode.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this)this._canvasNode.on(Node.EventType.TOUCH_END, this.onTouchEnd, this)this._canvasNode.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this)}private getUIPos(pos: Vec2) {__tempV3.set(pos.x, pos.y, 0)this._curGraphics.node.getComponent(UITransform).convertToNodeSpaceAR(__tempV3, __tempV3)pos.set(__tempV3.x, __tempV3.y)return pos;}private _curGraphics: Graphics;private onTouchStart(evt: EventTouch) {evt.getUILocation(__tempV2)this._pointList.length = 0;const node = new Node()node.layer = this._canvasNode.layer;this._canvasNode.addChild(node);this._curGraphics = node.addComponent(Graphics)this._curGraphics.strokeColor = Color.WHITE;this._curGraphics.lineWidth = 10;const { x, y } = this.getUIPos(__tempV2)this._curGraphics.moveTo(x, y)this._pointList.push({ x, y })}private _preK: number = 0private _pointList: TypePoint[] = []private onTouchMove(evt: EventTouch) {evt.getUILocation(__tempV2)const { x, y } = this.getUIPos(__tempV2)const { x: preX, y: preY } = this._pointList[this._pointList.length - 1];const diffX = x - preX;const diffY = y - preY;const dis = (Math.abs(diffX) + Math.abs(diffY))if (dis >= this._curGraphics.lineWidth) {const d = 0.001const curK = Math.abs(diffX) < d ? (Number.MAX_SAFE_INTEGER * Math.sign(diffX) * Math.sign(diffY)) : (diffY / diffX)if (this._pointList.length > 1) {const diffK = curK - this._preK;if (Math.abs(diffK) < d) {// 斜率相同去掉前一个点this._pointList.pop()}}this._pointList.push({ x, y })this._curGraphics.lineTo(x, y)this._curGraphics.stroke();this._preK = curK;}}private onTouchEnd(evt: EventTouch) {console.log(this._pointList.length)if (this._pointList.length > 1) {this._curGraphics.addComponent(RigidBody2D);for (let index = 0; index < this._pointList.length - 1; index++) {const start = this._pointList[index];const end = this._pointList[index + 1];const poly = this._curGraphics.addComponent(PolygonCollider2D);const d = v2(end.x - start.x, end.y - start.y).normalize();const widhtHalf = this._curGraphics.lineWidth / 2;const p1 = v2(d.y, -d.x).multiplyScalar(widhtHalf).add2f(start.x, start.y)const p2 = v2(-d.y, d.x).multiplyScalar(widhtHalf).add2f(start.x, start.y)const p3 = v2(d.y, -d.x).multiplyScalar(widhtHalf).add2f(end.x, end.y)const p4 = v2(-d.y, d.x).multiplyScalar(widhtHalf).add2f(end.x, end.y)poly.points = [p1, p2, p4, p3];poly.apply()}} else {this._curGraphics.node.destroy();}this._curGraphics = null;}
}
小结
简单来说,画线刚体就是根据路径点和线宽去生成碰撞体。
参考资料
[1]
https://forum.cocos.org/t/topic/142673: https://forum.cocos.org/t/topic/142673
“点赞“ ”在看” 鼓励一下▼