protected bool ChipmunkPreSolve_water_crate(ChipmunkArbiter arbiter) { ChipmunkShape water, poly; arbiter.GetShapes(out water, out poly); ChipmunkBody body = poly.body; // Sanity check if (water._handle == IntPtr.Zero || poly._handle == IntPtr.Zero) { Debug.LogError("Invalid shape references. This is likely be a Chipmunk2D bug."); return(false); } // Get the top of the water sensor bounding box to use as the water level. // Chipmunk bounding boxes aren't exposed by ChipmunkShape yet. // They are rarely useful, though this makes a pretty good case for it. float level = ChipmunkBinding._cpShapeGetBB(water._handle).t; // Clip the polygon against the water level int count = ChipmunkBinding.cpPolyShapeGetNumVerts(poly._handle); int clippedCount = 0; Vector2[] clipped = new Vector2[count + 1]; for (int i = 0, j = count - 1; i < count; j = i, i++) { Vector2 a = ChipmunkBinding._cpBodyLocal2World(body._handle, ChipmunkBinding.cpPolyShapeGetVert(poly._handle, j)); Vector2 b = ChipmunkBinding._cpBodyLocal2World(body._handle, ChipmunkBinding.cpPolyShapeGetVert(poly._handle, i)); if (a.y < level) { clipped[clippedCount] = a; clippedCount++; } float a_level = a.y - level; float b_level = b.y - level; if (a_level * b_level < 0.0f) { float t = Mathf.Abs(a_level) / (Mathf.Abs(a_level) + Mathf.Abs(b_level)); clipped[clippedCount] = Vector2.Lerp(a, b, t); clippedCount++; } } // Calculate buoyancy from the clipped polygon area float clippedArea = AreaForPoly(clippedCount, clipped); float displacedMass = clippedArea * FLUID_DENSITY; Vector2 centroid = CentroidForPoly(clippedCount, clipped); Vector2 r = centroid - body.position; for (int i = 0, j = clippedCount - 1; i < clippedCount; j = i, i++) { Vector2 a = clipped[i]; Vector2 b = clipped[j]; Debug.DrawLine(a, b, Color.green); } // ChipmunkDebugDrawPolygon(clippedCount, clipped, RGBAColor(0, 0, 1, 1), RGBAColor(0, 0, 1, 0.1f)); // ChipmunkDebugDrawPoints(5, 1, ¢roid, RGBAColor(0, 0, 1, 1)); float dt = Time.fixedDeltaTime; Vector2 g = Chipmunk.gravity; // Apply the buoyancy force as an impulse. ApplyImpulse(body, g * (-displacedMass * dt), r); // Apply linear damping for the fluid drag. Vector2 v_centroid = body.velocity + (new Vector2(-r.y, r.x)) * body.angularVelocity; float k = KScalarBody(body, r, NormalizeSafe(v_centroid)); float damping = clippedArea * FLUID_DRAG * FLUID_DENSITY; float v_coef = Mathf.Exp(-damping * dt * k); // linear drag // float v_coef = 1.0/(1.0 + damping*dt*cpvlength(v_centroid)*k); // quadratic drag ApplyImpulse(body, (v_centroid * v_coef - v_centroid) / k, r); // Apply angular damping for the fluid drag. float w_damping = MomentForPoly(FLUID_DRAG * FLUID_DENSITY * clippedArea, clippedCount, clipped, -body.position); body.angularVelocity *= Mathf.Exp(-w_damping * dt / body.moment); return(false); }