模拟水浮力

11赞

大佬你好,我想让漂浮的物体,露出水面的面积更多,应该改哪里呢?

import GameManager from “./GameManager”;

const { ccclass, property } = cc._decorator;
@ccclass
export default class BuoyancyLiquid extends cc.Component {

@property({ tooltip: "密度" })
private density: number = 1;
@property({ tooltip: "角速度阻力" })
private angularDrag: number = 1;
@property({ tooltip: "线速度阻力" })
private linearDrag: number = 1;

private inFluid = [];
private gravity: cc.Vec2 = null;
private fluidBody: any = null;

onLoad() {
    GameManager.Physical_Manager();
    GameManager.Physical_Controller(true);
    // GameManager.Physical_DebugModel(1);
    this.gravity = cc.v2(GameManager.Physical_Manager().gravity.x, -GameManager.Physical_Manager().gravity.y);
};
start() {
    this.createFluid();
}
// called every frame, uncomment this function to activate update callback
update(dt) {
    for (let i = 0, l = this.inFluid.length; i < l; i++) {
        this.applyBuoyancy(this.inFluid[i]);
    }
};
createFluid() {
    let body: cc.RigidBody = this.node.getComponent(cc.RigidBody);
    body.type = 0;
    body.enabledContactListener = true;

    let polygonCollider = this.node.getComponent(cc.PhysicsPolygonCollider);
    // let w = this.node.width / 2;
    // let h = this.node.height / 2;
    // polygonCollider.points = [cc.v2(-w, -h), cc.v2(w, -h), cc.v2(w, h), cc.v2(-w, h)];
    polygonCollider.sensor = true;
    polygonCollider.density = this.density;
    polygonCollider.apply();

    this.fluidBody = body["_b2Body"];
};
findIntersectionAreaAndCentroid(body) {

    let fixtureB = body.m_fixtureList;

    if (!fixtureB || fixtureB.GetType() !== 2) {
        return;
    }
    let centroid = cc.v2(0, 0);
    let area = 0;
    let mass = 0;
    while (fixtureB) {
        let outputList = this.getVertices(this.fluidBody);
        let clipPolygon = this.getVertices(body);

        let cp1 = clipPolygon[clipPolygon.length - 1];
        for (let j = 0; j < clipPolygon.length; j++) {
            let cp2 = clipPolygon[j];
            let inputList = outputList;
            outputList = [];
            let s = inputList[inputList.length - 1]; //last on the input list
            for (let i = 0; i < inputList.length; i++) {
                let e = inputList[i];
                if (this.inside(cp1, cp2, e)) {
                    if (!this.inside(cp1, cp2, s)) {
                        outputList.push(this.intersection(cp1, cp2, s, e));
                    }
                    outputList.push(e);
                }
                else if (this.inside(cp1, cp2, s)) {
                    outputList.push(this.intersection(cp1, cp2, s, e));
                }
                s = e;
            }
            cp1 = cp2;
        }
        let ac = this.computeAC(outputList);
        let density = fixtureB.GetDensity();
        mass += ac[0] * density;
        area += ac[0];

        //centroid.addSelf(ac[1].mul(density));
        centroid.x += ac[1].x * density;
        centroid.y += ac[1].y * density;
        fixtureB = fixtureB.GetNext();
    }

    centroid.mulSelf(1 / mass);

    return [area, centroid];

};


onBeginContact(contact, selfCollider, otherCollider) {
    let bodyB = otherCollider.body._b2Body;
    this.inFluid.push(bodyB);
    contact.disabled = true;
};

onEndContact(contact, selfCollider, otherCollider) {
    let bodyB = otherCollider.body._b2Body;
    let index = this.inFluid.indexOf(bodyB);
    this.inFluid.splice(index, 1);
    contact.disabled = true;
};

applyBuoyancy(body) {
    let AC: Array<any> = this.findIntersectionAreaAndCentroid(body);//get the area and centroid
    if (AC[0] !== 0) {
        let mass = AC[0] * this.density;
        let centroid = AC[1];
        let buoyancyForce = cc.v2(mass * this.gravity.x, mass * this.gravity.y);
        body.ApplyForce(buoyancyForce, centroid);

        let body_vw = cc.v2();
        let fluidBody_vw = cc.v2();
        body.GetLinearVelocityFromWorldPoint(centroid, body_vw);
        this.fluidBody.GetLinearVelocityFromWorldPoint(centroid, fluidBody_vw);
        let velDir = body_vw.sub(fluidBody_vw);


        let dragMag = this.density * this.linearDrag * mass;
        let dragForce = velDir.mul(-dragMag);
        body.ApplyForce(dragForce, centroid);

        let torque = -body.GetInertia() / body.GetMass() * mass * body.GetAngularVelocity() * this.angularDrag;
        body.ApplyTorque(torque);
    }

};


getVertices(body) {
    let shape = body.m_fixtureList.m_shape;

    let vertices = [];
    for (let i = 0; i < shape.m_count; i++) {

        let pos = cc.v2(shape.m_vertices[i].x, shape.m_vertices[i].y);

        let pos_w = cc.v2();
        body.GetWorldPoint(pos, pos_w);
        vertices.push(pos_w);
    }

    return vertices;
};



inside(cp1, cp2, p) {
    return (cp2.x - cp1.x) * (p.y - cp1.y) > (cp2.y - cp1.y) * (p.x - cp1.x);
}

intersection(cp1, cp2, s, e) {
    let dc = cc.v2(cp1.x - cp2.x, cp1.y - cp2.y);
    let dp = cc.v2(s.x - e.x, s.y - e.y);
    let n1 = cp1.x * cp2.y - cp1.y * cp2.x;
    let n2 = s.x * e.y - s.y * e.x;
    let n3 = (dc.x * dp.y - dc.y * dp.x);
    return cc.v2((n1 * dp.x - n2 * dc.x) / n3, (n1 * dp.y - n2 * dc.y) / n3);
}

computeAC(vs): Array<any> {
    let count = vs.length;
    let c = cc.v2(0, 0);
    let area = 0.0;
    let p1X = 0.0;
    let p1Y = 0.0;
    let inv3 = 1.0 / 3.0;
    for (let i = 0; i < count; ++i) {
        let p2 = vs[i];
        let p3 = i + 1 < count ? vs[i + 1] : vs[0];
        let e1X = p2.x - p1X;
        let e1Y = p2.y - p1Y;
        let e2X = p3.x - p1X;
        let e2Y = p3.y - p1Y;
        let D = (e1X * e2Y - e1Y * e2X);
        let triangleArea = 0.5 * D; area += triangleArea;
        c.x += triangleArea * inv3 * (p1X + p2.x + p3.x);
        c.y += triangleArea * inv3 * (p1Y + p2.y + p3.y);
    }
    return [area, c];
}

}

修改密度,或者修改漂浮物的重力值和密度试一试

总感觉以后用的上

mark 一下 :2:

感谢大佬分享

感谢大佬分享,干货呀

mark
·····

这个感觉很硬

如果是圆的物体。大佬要怎么做呢?