Cocos Creator:奇妙的物理世界_物理切割

前言

游戏开发中,物理系统的试用越来越多,导致试用花样也是越来越多,只有你想不到的,没有做不到的。前段时间自己在其他地方看见了一个比较好玩的物理切割类的游戏,出于好奇自己也实验了一把。其实游戏已经上线小游戏平台(微信,抖音,今日头条,搜索《切片小达人》)一周多了,一直没时间整理文章,今天终于可以整理一下了。

效果展示

体验路径

微信小游戏搜索:切片小达人

抖音或者今日头条搜索:切片小达人

视频连接:哔哩哔哩 或者浏览器输入(https://www.bilibili.com/video/bv1QK411N7Ae)

正文

1.demo效果展示

2.文档资料

在这里给大家推荐两篇文章,有兴趣的朋友可以看一下,

CocosCreator之KUOKUO带你做物理切割:https://blog.csdn.net/kuokuo666/article/details/104411083

多边形切割:https://blog.csdn.net/zengyun_cool_2008/article/details/80745234

3.切割

切割:字面意思理解,将一个平面分成几个部分。运用到游戏中就是将处于两点(起点和终点)之间连线上的物体,以连线作为分割线,分割成多个部分。

要达到切割,首先要知道几个数据:

  • 1.切割线的起点和终点
  • 2.多边形物体的边缘坐标点

有了上边两个数据,我们可以算出:

  • 1.切割线是否与多边形物体有交点
  • 2.交点的坐标
  • 3.是否满足切割条件
  • 4.切割后新的坐标点

如果仅仅是切割,做到上边的这几点差不多就可以了。但是,咱们今天要说的是物理切割,也就是满足物理效果的切割。

3.1 creator 物理系统

文档:物理与碰撞系统:http://docs.cocos.com/creator/manual/zh/physics/

  • 开启物理系统:
物理系统默认是关闭的,如果需要开启物理系统需要手动通过代码实现
onLoad() {
        var manager = cc.director.getCollisionManager();
        manager.enabled = true;
        manager.enabledDebugDraw = true;
        manager.enabledDrawBoundingBox = true;
        cc.director.getPhysicsManager().enabled = true;
    }
  • 给需要切割的物体绑定多边形刚体组件

3.2 物理切割

  • 检测起点和终点 绘制切割线
start() {
    this.initEvent();
}
initEvent(): void {
    this.node.on(cc.Node.EventType.TOUCH_START, this.uiNodeStartEvent, this);
    this.node.on(cc.Node.EventType.TOUCH_MOVE, this.uiNodeMoveEvent, this);
    this.node.on(cc.Node.EventType.TOUCH_END, this.uiNodeEndEvent, this);
    this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.uiNodeEndEvent, this);
}

uiNodeStartEvent(e: cc.Event.EventTouch): void {
    this.touchStartLocal = null;
    this.touchMoveLocal = null;
    this.touchStartLocal = this.node.convertToNodeSpaceAR(e.getLocation());
    //初始化切割线的位置和长度
    this.line.setPosition(this.touchStartLocal);
    this.line.width = 0;

}
//
uiNodeMoveEvent(e: cc.Event.EventTouch): void {
    if (!this.touchStartLocal) return;
    console.log("移动");
    this.touchMoveLocal = this.node.convertToNodeSpaceAR(e.getLocation());
    //计算切割线旋转角度 和长度
    this.line.angle = -this.rotationTarget(this.touchStartLocal, this.touchMoveLocal) + 90;
    this.line.width = Math.abs(this.line.getPosition().sub(this.touchMoveLocal).mag());
}

//
uiNodeEndEvent(e: cc.Event.EventTouch): void {
    if (!this.touchStartLocal) return;
    let touchEndLocal: cc.Vec2 = this.node.convertToNodeSpaceAR(e.getLocation());
    let touchStartLocal: cc.Vec2 = this.node.convertToNodeSpaceAR(e.getStartLocation());
    this.line.width = 0;
}
  • 检测切割

检测切割的步骤:

  • 1.获取切割线上的所有刚体(可以使用物理系统自带的射线检测)

    详细文档射线检测:http://docs.cocos.com/creator/manual/zh/physics/physics/physics-manager.html

    在这里给大家列出一下射线检测的类型

      cc.RayCastType.Any
      检测射线路径上任意的碰撞体,一旦检测到任何碰撞体,将立刻结束检测其他的碰撞体,最快。

      cc.RayCastType.Closest
      检测射线路径上最近的碰撞体,这是射线检测的默认值,稍慢。

      cc.RayCastType.All
      检测射线路径上的所有碰撞体,检测到的结果顺序不是固定的。在这种检测类型下,一个碰撞体可能会返回多个结果,这是因为 box2d 是通过检测夹具(fixture)来进行物体检测的,而一个碰撞体中可能由多个夹具(fixture)组成的,慢。更多细节可到 物理碰撞组件 查看。

      cc.RayCastType.AllClosest
      检测射线路径上所有碰撞体,但是会对返回值进行删选,只返回每一个碰撞体距离射线起始点最近的那个点的相关信息,最慢。
  • 2.碰撞体筛选

    因为咱们在上一步检测的是所有的刚体,而在这种检测类型下,一个碰撞体可能有多个返回结果,所以需要进行筛选,筛选的目的在于确定这个碰撞体与射线相交(其实大家也可以是试用AllClosest类型,这样就用进行筛选了)

recalcResults(type: number, touchStartLocal: cc.Vec2, touchEndLocal: cc.Vec2): void {
    let colliderArr = [];
    //获取所有刚体
    let result = cc.director.getPhysicsManager().rayCast(touchStartLocal, touchEndLocal, cc.RayCastType.All);
    for (let i = 0; i < result.length; i++) {
        #遍历每一个结果,筛选出之前没有出现的碰撞体,并且tag介于1-99直接的刚体(水果)
        let collider: any = result[i].collider;
        if (collider.tag > 0 && collider.tag < 100) {   //切割的是水果  并且切割的collider 没有切割
            let isExist: boolean = false;
            for (let j = 0; j < colliderArr.length; j++) {
                if (collider == colliderArr[j]) {
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                colliderArr.push(collider);
                //进行切割
                let cutState = this.checkCutPolygon(type, touchStartLocal, touchEndLocal, collider);
            }
        }

    }
}
  • 3.切割
/**
 * @param touchStartLocal   起点坐标 
 * @param touchEndLocal   终点坐标
 * @param collider     将要切割的刚体
 */
private checkCutPolygon(type, touchStartLocal, touchEndLocal, collider): boolean {
    let body = collider.body;
    let points = collider.points;
    let tag: number = collider.tag;
    // 转化为本地坐标
    let localPoint1 = cc.Vec2.ZERO;
    let localPoint2 = cc.Vec2.ZERO;
    body.getLocalPoint(touchStartLocal, localPoint1);
    body.getLocalPoint(touchEndLocal, localPoint2);

    let isCut: boolean = false;
    let splitResults = [];
    let intersectPoint = [];
    //线段切割刚体
    this.lineCutPolygon(localPoint1, localPoint2, points, splitResults, intersectPoint);
    if (splitResults.length <= 0) {
        return false;
    }

    //回收本体
    collider.node.destroy();
    #克隆
    for (let j = 0; j < splitResults.length; j++) {
        let splitResult = splitResults[j];
        if (splitResult.length < 3) continue;
        this.cloneNode(collider.node, splitResult);
    }

}

至于详细的两点所连线段对多边形的切割,大家可以看gitee中的demo,或者看上边提供的多边形切割连接

  • 4.克隆

物体的切割克隆,实际上就是相同的物体,只不过自身的边缘点不同而已

cloneNode(node: cc.Node, splitResult: Array<any>): boolean {
    //更具节点名字在对象池中获取节点
    let isOk: boolean = false;
    let fruitNode: cc.Node = cc.instantiate(this.fruit);
    fruitNode.position = node.position;
    fruitNode.angle = node.angle;
    fruitNode.name = node.name;
    try {
        this.node.addChild(fruitNode);
        let collider = fruitNode.getComponent(cc.PhysicsPolygonCollider);
        fruitNode.getComponent(cc.PhysicsPolygonCollider).friction = 0.01;
        collider.points = splitResult;
        collider.apply();
        fruitNode.getComponent(Fruit).draw();
        isOk = true;
    } catch (error) {
        console.log("出现异常--,克隆", error);
        fruitNode.destroy();
        isOk = false;
    }
    return isOk;
}
  • 5.遮罩

知道了物体切割后的自身碰撞的边缘点,那么只需要对每个新物体更具碰撞点就行多边形遮罩就可以了

创建切割物体挂在脚本,代码如下

@ccclass
export default class Fruit extends cc.Component {
    onLoad() {
    }
    start() {
        this.draw();
    }
    public draw() {
        //获取碰撞包围盒子的点
        let points: any = this.getComponent(cc.PhysicsPolygonCollider).points;
        let mask = this.getComponent(cc.Mask);
        let graphics: cc.Graphics = (<any>mask)._graphics;
        // // @ts-ignore
        // const grapics = mask._graphics;
        //获取绘制 grapics
        // let grapics:cc.Graphics=this.getComponent(cc.Graphics); 
        // 擦除之前绘制的所有内容的方法。
        graphics.clear();
        // console.log(points);
        // console.log(graphics);
        let len: number = points.length;
        //移动路径起点到坐标(x, y)
        graphics.moveTo(points[len - 1].x, points[len - 1].y);
        for (let i = 0; i < points.length; i++) {
            graphics.lineTo(points[i].x, points[i].y);
        }
        graphics.strokeColor.fromHEX('#000000');
        graphics.lineWidth = 2;
        graphics.fill();
        graphics.stroke();
    }
    update(dt) { }
}

上边的这种遮罩方式,随着物体数量的变多,drawcall会上涨的很明显,导致游戏性能降低,具体的解决办法大家可以在论坛中搜索白玉无冰大佬的多边形裁剪图片(非mask,使用mesh),新增 gizmo 支持 https://forum.cocos.org/t/mask-mesh-gizmo/88288

4.地址

  • gitee:https://gitee.com/carlosyzy/cocos_creator_physical_cutting
  • 微信公众号:搬砖小菜鸟

5.推荐

大家可以微信扫描下边二维码进行体验

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《划线卡车》是一个基于cocos creator 2.2.2开发的物理小游戏,玩家需要控制卡车在各种障碍物之间划线,以完成关卡目标。 源码中主要包含以下几个部分: 1. 游戏界面:游戏界面包括背景、卡车、障碍物等元素的布局和渲染。通过cocos creator的场景编辑器可以快速创建游戏界面,并进行相应的设置。 2. 物理引擎:利用cocos creator内置的物理引擎,为卡车和障碍物之间的互动提供支持。通过设置物体的质量、形状、碰撞检测等属性,实现真实的物理效果。 3. 划线逻辑:玩家通过触摸屏幕来划线,卡车会沿着划线的路径移动。划线逻辑需要处理触摸事件,并根据触摸点的位置计算划线路径,并使卡车按照路径移动。 4. 碰撞检测:游戏中需要检测卡车与障碍物之间的碰撞。当卡车与障碍物碰撞时,游戏失败。通过物理引擎提供的碰撞检测接口,可以方便地实现碰撞检测逻辑。 5. 过关条件判断:每一关都有特定的过关条件,例如在规定时间内完成划线,或者在最少次数内完成划线等。通过判断卡车移动的次数和时间来判断玩家是否完成过关条件。 通过阅读源码,可以学习到如何使用cocos creator进行游戏开发,了解物理引擎的基本原理和使用方法,熟悉游戏逻辑的编写和处理,提升自己的游戏开发能力。同时可以根据源码进行修改和优化,添加新的关卡和玩法,打造属于自己的版本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穿越的杨宗宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值