Phaser游戏中如何检测鼠标绘制线条是否穿过曲线两侧?
Level 4 切割检测实现方案
核心思路
将红色宽曲线拆解为两条平行的折线(对应曲线的左右两侧),检测用户绘制的线段是否与这两条折线同时相交,满足条件则判定切割成功。
具体实现步骤
1. 保存关键数据与生成两侧曲线
在场景的create方法中,将原曲线转为类属性,并生成曲线两侧的偏移点集合(偏移距离为红色曲线宽度的一半,即20):
create(){ const graphics = this.add.graphics(); // 将path设为类属性,方便后续调用 this.path = new Phaser.Curves.Path(0, 300); for (let i = 0; i < 8; i++) { if (i % 2 === 0) { this.path.ellipseTo(50, 80, 180, 360, true, 0); } else { this.path.ellipseTo(50, 80, 180, 360, false, 0); } } graphics.lineStyle(40, 0xff0000, 1); this.path.draw(graphics); // 生成红色曲线的两侧偏移点 const pathPoints = this.path.getPoints(200); // 密集采样点保证检测精度 this.leftCurvePoints = []; this.rightCurvePoints = []; const offsetDistance = 20; // 线宽40的一半 for (let i = 0; i < pathPoints.length - 1; i++) { const p1 = pathPoints[i]; const p2 = pathPoints[i + 1]; // 计算线段垂直法向量 const dx = p2.x - p1.x; const dy = p2.y - p1.y; const length = Math.sqrt(dx * dx + dy * dy); if (length === 0) continue; const normalX = -dy / length; const normalY = dx / length; // 左侧偏移点 this.leftCurvePoints.push(new Phaser.Geom.Point(p1.x + normalX * offsetDistance, p1.y + normalY * offsetDistance)); // 右侧偏移点 this.rightCurvePoints.push(new Phaser.Geom.Point(p1.x - normalX * offsetDistance, p1.y - normalY * offsetDistance)); } // 处理最后一个点的偏移 const lastPoint = pathPoints[pathPoints.length - 1]; const prevPoint = pathPoints[pathPoints.length - 2]; const dx = lastPoint.x - prevPoint.x; const dy = lastPoint.y - prevPoint.y; const length = Math.sqrt(dx * dx + dy * dy); if (length > 0) { const normalX = -dy / length; const normalY = dx / length; this.leftCurvePoints.push(new Phaser.Geom.Point(lastPoint.x + normalX * offsetDistance, lastPoint.y + normalY * offsetDistance)); this.rightCurvePoints.push(new Phaser.Geom.Point(lastPoint.x - normalX * offsetDistance, lastPoint.y - normalY * offsetDistance)); } this.lineGraphics = this.add.graphics(); this.input.on("pointerdown", this.startDrawing, this); this.input.on("pointerup", this.stopDrawing, this); this.input.on("pointermove", this.keepDrawing, this); this.isDrawing = false; levelText = this.add.text(13, 11, 'Level 4',{fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif'}); }
2. 添加相交检测辅助函数
实现检测线段与折线曲线是否相交的工具方法:
// 检测线段是否与折线曲线相交 doesLineIntersectCurve(line, points) { for (let i = 0; i < points.length - 1; i++) { const curveSegment = new Phaser.Geom.Line(points[i].x, points[i].y, points[i+1].x, points[i+1].y); if (Phaser.Geom.Line.Intersects(line, curveSegment)) { return true; } } return false; }
3. 完成stopDrawing中的检测逻辑
修改stopDrawing方法,判断用户线段是否与两侧曲线都相交:
stopDrawing(pointer){ this.isDrawing = false; // 创建用户绘制的线段 const userLine = new Phaser.Geom.Line(pointer.downX, pointer.downY, pointer.x, pointer.y); // 检测是否与左右两侧曲线都相交 const intersectLeft = this.doesLineIntersectCurve(userLine, this.leftCurvePoints); const intersectRight = this.doesLineIntersectCurve(userLine, this.rightCurvePoints); if (intersectLeft && intersectRight){ levelText.setVisible(false); this.add.text(190, 300, 'Level 4 complete!',{fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif', fontSize: '60px'}).bringToTop(); } };
完整修改后代码
let level4; window.onload = function() { let gameConfig = { transparent: true, type: Phaser.AUTO, scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH, parent: "thegame", width: 600, height: 700 }, scene: scene4, physics: { default: "matter", matter: { gravity: { y: 0 }, debug: true, } } } level4 = new Phaser.Game(gameConfig); window.focus(); } let levelText; class scene4 extends Phaser.Scene{ constructor(){ super(); } create(){ const graphics = this.add.graphics(); this.path = new Phaser.Curves.Path(0, 300); for (let i = 0; i < 8; i++) { if (i % 2 === 0) { this.path.ellipseTo(50, 80, 180, 360, true, 0); } else { this.path.ellipseTo(50, 80, 180, 360, false, 0); } } graphics.lineStyle(40, 0xff0000, 1); this.path.draw(graphics); // 生成两侧曲线点 const pathPoints = this.path.getPoints(200); this.leftCurvePoints = []; this.rightCurvePoints = []; const offsetDistance = 20; for (let i = 0; i < pathPoints.length - 1; i++) { const p1 = pathPoints[i]; const p2 = pathPoints[i + 1]; const dx = p2.x - p1.x; const dy = p2.y - p1.y; const length = Math.sqrt(dx * dx + dy * dy); if (length === 0) continue; const normalX = -dy / length; const normalY = dx / length; this.leftCurvePoints.push(new Phaser.Geom.Point(p1.x + normalX * offsetDistance, p1.y + normalY * offsetDistance)); this.rightCurvePoints.push(new Phaser.Geom.Point(p1.x - normalX * offsetDistance, p1.y - normalY * offsetDistance)); } const lastPoint = pathPoints[pathPoints.length - 1]; const prevPoint = pathPoints[pathPoints.length - 2]; const dx = lastPoint.x - prevPoint.x; const dy = lastPoint.y - prevPoint.y; const length = Math.sqrt(dx * dx + dy * dy); if (length > 0) { const normalX = -dy / length; const normalY = dx / length; this.leftCurvePoints.push(new Phaser.Geom.Point(lastPoint.x + normalX * offsetDistance, lastPoint.y + normalY * offsetDistance)); this.rightCurvePoints.push(new Phaser.Geom.Point(lastPoint.x - normalX * offsetDistance, lastPoint.y - normalY * offsetDistance)); } this.lineGraphics = this.add.graphics(); this.input.on("pointerdown", this.startDrawing, this); this.input.on("pointerup", this.stopDrawing, this); this.input.on("pointermove", this.keepDrawing, this); this.isDrawing = false; levelText = this.add.text(13, 11, 'Level 4',{fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif'}); } startDrawing(){ this.isDrawing = true; } keepDrawing(pointer){ if(this.isDrawing){ this.lineGraphics.clear(); this.lineGraphics.lineStyle(5, 'black'); this.lineGraphics.moveTo(pointer.downX, pointer.downY); this.lineGraphics.lineTo(pointer.x, pointer.y); this.lineGraphics.strokePath(); } } updateLine(){ this.lineGraphics.lineStyle(15, 'black'); this.lineGraphics.moveTo(linePoints[0].x, linePoints[0].y); for(var i = 1; i < linePoints.length; i++) { this.lineGraphics.lineTo(linePoints[i].x, linePoints[i].y); } this.lineGraphics.strokePath(); } doesLineIntersectCurve(line, points) { for (let i = 0; i < points.length - 1; i++) { const curveSegment = new Phaser.Geom.Line(points[i].x, points[i].y, points[i+1].x, points[i+1].y); if (Phaser.Geom.Line.Intersects(line, curveSegment)) { return true; } } return false; } stopDrawing(pointer){ this.isDrawing = false; const userLine = new Phaser.Geom.Line(pointer.downX, pointer.downY, pointer.x, pointer.y); const intersectLeft = this.doesLineIntersectCurve(userLine, this.leftCurvePoints); const intersectRight = this.doesLineIntersectCurve(userLine, this.rightCurvePoints); if (intersectLeft && intersectRight){ levelText.setVisible(false); this.add.text(190, 300, 'Level 4 complete!',{fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif', fontSize: '60px'}).bringToTop(); } }; };
内容的提问来源于stack exchange,提问作者engineeringstudent1999
相关产品推荐
相关产品推荐

