Box2d 物理畫線,Cocos Creator 3.8
一個(gè)簡(jiǎn)易的畫線剛體Demo
效果
抱歉,放錯(cuò)圖了,以上是 孫二喵 iwae https://forum.cocos.org/t/topic/142673[1] 的效果圖。本Demo是根據(jù)文章的思路,合成的代碼。首先,感謝孫二喵的技術(shù)分享。
以下是最終效果圖
使用
版本 Cocos Creator 3.8.1
-
創(chuàng)建一個(gè) Empty(2D)項(xiàng)目
-
保存場(chǎng)景,新建一個(gè) Game.ts腳本,把代碼復(fù)制進(jìn)去(代碼在最后面)
-
拖入 Game.ts腳本至場(chǎng)景中
-
(可選)在場(chǎng)景中添加一些靜態(tài)剛體和碰撞體
-
運(yùn)行預(yù)覽
原理
坐標(biāo)轉(zhuǎn)換
觸點(diǎn)坐標(biāo)轉(zhuǎn)到節(jié)點(diǎn)坐標(biāo)
-
getUILocation -
UITransform.convertToNodeSpaceAR
推薦閱讀純干貨!一文搞懂 Cocos Creator 3.0 坐標(biāo)轉(zhuǎn)換原理
https://mp.weixin.qq.com/s/mV5EY4NMrpgCP9XFocrcGA
計(jì)算碰撞體
首先問題分解:已知:
-
兩個(gè)點(diǎn)的坐標(biāo) -
線寬
求:
-
圍成該線段的四個(gè)點(diǎn)的坐標(biāo)
回顧一下,2D中的旋轉(zhuǎn)的矩陣是:
旋轉(zhuǎn)90度的矩陣為
旋轉(zhuǎn)-90度的矩陣為
先計(jì)算方向向量,然后2個(gè)垂直方向的向量,分別乘以我們線段一半的寬度,最后起始點(diǎn)和結(jié)束點(diǎn)分別加上這2個(gè)向量,4個(gè)路徑點(diǎn)
//方向向量
d = (end - start).normalize();
//垂直向量1
d1 = R_1 * d = (d.y,-d.x)
//垂直向量2
d2 = R_2 * d = (-d.y,d.x)
//求4個(gè)點(diǎn)
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: Node
start() {
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 = 0
private _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.001
const 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) {
// 斜率相同去掉前一個(gè)點(diǎn)
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;
}
}
小結(jié)
簡(jiǎn)單來說,畫線剛體就是根據(jù)路徑點(diǎn)和線寬去生成碰撞體。
參考資料
https://forum.cocos.org/t/topic/142673: https://forum.cocos.org/t/topic/142673
“點(diǎn)贊“ ”在看” 鼓勵(lì)一下
▼
評(píng)論
圖片
表情
