Пример #1
0
    public static bool presolveCollisionWithOneway(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        // if collision was from below then continue with oneway platform logic
        if (GameObjectTools.isHitFromBelow(arbiter))
        {
            arbiter.Ignore();
            return(false);
        }

        Player player = shape1.getOwnComponent <Player>();

        // if player wants to climb down (once it is over the platform) then disable the collision to start free fall
        if (player.GetComponent <ClimbDownFromPlatform>().isClimbingDown())
        {
            player.jump.reset();             // set state as if were jumping
            arbiter.Ignore();
            return(false);
        }

        // let the collision happens
        return(true);
    }
Пример #2
0
    public static bool beginCollisionWithPowerUp(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        KoopaTroopa koopa   = shape1.getOwnComponent <KoopaTroopa>();
        PowerUp     powerUp = shape2.getOwnComponent <PowerUp>();

        powerUp.Invoke("destroy", 0f);         // a replacement for Destroy
        koopa.stop();

        // hide or kill the koopa
        if (koopa._hide.isHidden())
        {
            koopa.die();
        }
        else
        {
            koopa.hide();
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(false);
    }
Пример #3
0
    public static bool beginCollisionWithScenery(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Player player = shape1.getOwnComponent <Player>();

        if (player.isDying())
        {
            return(false);            // stop collision with scenery since this frame
        }
        player.exitedFromScenery = false;

        // Avoid ground penetration (Y axis). Another way: see collisionBias and/or minPenetrationForPenalty config in CollisionManagerCP.
        // Currently is being addressed by AirGroundControlUpdater and in WalkAbs

        /*if (GameObjectTools.isGrounded(arbiter)) {
         *      Vector2 thePos = player.body.position;
         * float depth = arbiter.GetDepth(0);
         *      thePos.y -= depth;
         * player.body.position = thePos;
         * }*/

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(true);
    }
Пример #4
0
    public static bool beginCollisionWithAny(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        // change direction of movement whenever hit something like a wall
        if (GameObjectTools.isWallHit(arbiter))
        {
            Patrol p1 = shape1.GetComponent <Patrol>();
            if (p1 != null && p1.enabled)
            {
                p1.toogleDir();
            }
            Patrol p2 = shape2.GetComponent <Patrol>();
            if (p2 != null && p2.enabled)
            {
                p2.toogleDir();
            }
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(true);
    }
Пример #5
0
    public static bool beginCollisionWithKoopaTroopa(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        KoopaTroopa koopa1    = shape1.GetComponent <KoopaTroopa>();
        KoopaTroopa koopa2    = shape2.GetComponent <KoopaTroopa>();
        bool        hidden1   = koopa1._hide.isHidden();
        bool        hidden2   = koopa2._hide.isHidden();
        bool        bouncing1 = koopa1.bounce.isBouncing();
        bool        bouncing2 = koopa2.bounce.isBouncing();

        // avoid koopa1 pushes hidden koopa2
        Chase chase = shape1.GetComponent <Chase>();

        if (chase != null && chase.isChasing())
        {
            chase.stopChasing();
            chase.enableOperateWhenOutOfSensor();
        }
        // avoid koopa2 pushes hidden koopa1
        chase = shape2.GetComponent <Chase>();
        if (chase != null && chase.isChasing())
        {
            chase.stopChasing();
            chase.enableOperateWhenOutOfSensor();
        }

        // is koopa above the other koopa?
        if (GameObjectTools.isGrounded(arbiter))
        {
            if (!hidden1)
            {
                koopa1.jump.forceJump(koopa1.jumpSpeed);
            }
            else
            {
                koopa2.jump.forceJump(koopa1.jumpSpeed);
            }
            // NOTE: I assume here the isGrounded() works as expected
            return(false);            // avoid the collision to continue since this frame
        }
        // kills koopa 2
        else if (bouncing1 && !hidden2 && !bouncing2)
        {
            //koopa2.die();
            koopa2.hide();
        }
        // kills koopa 1
        else if (bouncing2 && !hidden1 && !bouncing1)
        {
            //koopa1.die();
            koopa1.hide();
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(true);
    }
Пример #6
0
    public static bool beginCollisionWithScenery(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Jump jump = shape1.GetComponent <Jump>();

        // if is jumping and hits a wall then continue the collision

        /*if (jump != null && jump.isJumping && GameObjectTools.isWallHit(arbiter))
         *      return true;*/

        if (jump != null && GameObjectTools.isGrounded(arbiter))
        {
            if (jump.foreverJump)
            {
                jump.forceJump(jump.foreverJumpVel);
            }
            // if it was jumping then reset jump behavior
            else if (jump.isJumping)
            {
                jump.stop();
            }
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(true);
    }
Пример #7
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        Goomba goomba = shape1.GetComponent <Goomba>();
        Player player = shape2.GetComponent <Player>();

        if (goomba.dieAnim.isDying() || player.isDying())
        {
            arbiter.Ignore();         // avoid the collision to continue since this frame
            return(false);            // avoid the collision to continue since this frame
        }

        goomba.idle.setIdle(true);

        // if collides from top then kill the goomba
        if (GameObjectTools.isHitFromAbove(goomba.transform.position.y, shape2.body, arbiter))
        {
            goomba.die();
            // makes the player jumps a little upwards
            player.forceJump();
        }
        // kills Player
        else
        {
            arbiter.Ignore();                     // avoid the collision to continue since this frame
            LevelManager.Instance.loseGame(true); // force die animation
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(true);
    }
Пример #8
0
    public static bool beginCollisionWithKoopaTroopa(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        KoopaTroopa koopa1    = shape1.getOwnComponent <KoopaTroopa>();
        KoopaTroopa koopa2    = shape2.getOwnComponent <KoopaTroopa>();
        bool        hidden1   = koopa1._hide.isHidden();
        bool        hidden2   = koopa2._hide.isHidden();
        bool        bouncing1 = koopa1.bounce.isBouncing();
        bool        bouncing2 = koopa2.bounce.isBouncing();

        // avoid koopa1 pushes hidden koopa2
        Chase chase1 = shape1.GetComponent <Chase>();

        if (chase1 != null && chase1.isChasing())
        {
            chase1.stop();
            chase1.enableOperateWhenOutOfSensor();
        }
        // avoid koopa2 pushes hidden koopa1
        Chase chase2 = shape2.GetComponent <Chase>();

        if (chase2 != null && chase2.isChasing())
        {
            chase2.stop();
            chase2.enableOperateWhenOutOfSensor();
        }

        // is koopa1 above the koopa2?
        if (GameObjectTools.isGrounded(arbiter))
        {
            if (!hidden1 && koopa1.jump.isJumping())
            {
                koopa1.jump.forceJump(koopa1.jumpSpeed);
            }
            else if (hidden1 && koopa2.jump.isJumping())
            {
                koopa2.jump.forceJump(koopa1.jumpSpeed);
            }
            return(false);            // avoid the collision since this frame
        }
        // hide koopa 2
        else if (bouncing1 && !hidden2 && !bouncing2)
        {
            koopa2.hide();
        }
        // hide koopa 1
        else if (bouncing2 && !hidden1 && !bouncing1)
        {
            //koopa1.die();
            koopa1.hide();
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(true);
    }
Пример #9
0
    public static void endCollisionWithScenery(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        shape1.GetComponent <Player>().exitedFromScenery = true;
    }
Пример #10
0
    public static void endCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        shape1.getOwnComponent <Goal>().flagTargetOutside(shape1._handle.ToInt32());
    }
    private void MarkCollision(ChipmunkArbiter arbiter)
    {
        ChipmunkShape a, b;

        arbiter.GetShapes(out a, out b);
        a.GetComponent <Ball>().parent = b.GetComponent <Ball>();

        Debug.DrawLine(a.transform.position, b.transform.position, Color.white);
    }
    protected bool ChipmunkBegin_player_pit(ChipmunkArbiter arbiter)
    {
        ChipmunkShape player, pit;

        arbiter.GetShapes(out player, out pit);

        player.SendMessage("OnFellInPit");

        return(true);
    }
Пример #13
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        KoopaTroopa koopa  = shape1.getOwnComponent <KoopaTroopa>();
        Player      player = shape2.getOwnComponent <Player>();

        if (player.isDying())
        {
            arbiter.Ignore();         // avoid the collision to continue since this frame
            return(false);            // avoid the collision to continue since this frame
        }

        bool collisionFromAbove = GameObjectTools.isHitFromAbove(koopa.transform.position.y, shape2.body, arbiter);

        if (collisionFromAbove)
        {
            // if koopa was jumping then stop forever jumping
            if (koopa.jump.isJumping())
            {
                koopa.stopJumping();
            }
            // hide the koopa troopa or stop the bouncing of the hidden koopa
            else if (!koopa._hide.isHidden() || koopa.bounce.isBouncing())
            {
                koopa.hide();
            }
            // kills the koopa
            else
            {
                koopa.die();
            }
            // makes the player jumps a little upwards
            player.forceJump();
        }
        // koopa starts bouncing
        else if (koopa._hide.isHidden() && !koopa.bounce.isBouncing())
        {
            koopa.stop();
            koopa.bounce.bounce(Mathf.Sign(koopa.transform.position.x - player.transform.position.x));
        }
        // kills Player
        else
        {
            koopa.stop();
            arbiter.Ignore();                     // avoid the collision to continue since this frame
            LevelManager.Instance.loseGame(true); // force die animation
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(true);
    }
Пример #14
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        LevelManager.Instance.updateLastSpawnPosition(shape2.GetComponent <SpawnPositionTrigger>().sps);

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(false);
    }
    protected bool ChipmunkBegin_player_bumpable(ChipmunkArbiter arbiter)
    {
        if (arbiter.GetNormal(0).y > 0.9f)
        {
            ChipmunkShape player, bonusBlock;
            arbiter.GetShapes(out player, out bonusBlock);

            bonusBlock.SendMessage("Bump");
        }

        return(true);
    }
Пример #16
0
    public static void endCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Chase chase = shape1.GetComponent <Chase>();

        chase.stopChasing();
        chase.target = null;
        chase.enableOperate();
    }
Пример #17
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        shape1.getOwnComponent <Goal>().flagTargetInside(shape1._handle.ToInt32());

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(false);
    }
Пример #18
0
    public static bool beginCollisionWithUnlockSensor(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Player player = shape1.GetComponent <Player>();

        player.restoreWalkVel();

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(false);
    }
Пример #19
0
    public static bool beginCollisionWithPowerUp(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        Ghost   ghost   = shape1.GetComponent <Ghost>();
        PowerUp powerUp = shape2.GetComponent <PowerUp>();

        powerUp.Invoke("destroy", 0f);         // a replacement for Destroy
        ghost.die();

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(false);
    }
Пример #20
0
    public static void endCollisionWithOneway(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Player player = shape1.getOwnComponent <Player>();

        //player.jump.resetStatus(); // set state as if were jumping
        player.exitedFromScenery = true;

        // If was traversing the platform from below then the player is over the platform.
        // Correct inner state is treated by the invoked method
        player.GetComponent <ClimbDownFromPlatform>().handleSeparation();
    }
    protected bool ChipmunkBegin_player_jumpshroom(ChipmunkArbiter arbiter)
    {
        ChipmunkShape player, shroom;

        arbiter.GetShapes(out player, out shroom);

        if (arbiter.GetNormal(0).y < -0.9f)
        {
            ChipmunkBody body = player.GetComponent <ChipmunkBody>();
            body.velocity = new Vector2(body.velocity.x, 50f);
            return(false);
        }
        else
        {
            return(true);
        }
    }
Пример #22
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        Ghost ghost = shape1.GetComponent <Ghost>();

        ghost.stop();

        // kills player
        arbiter.Ignore();                     // avoid the collision to continue since this frame
        LevelManager.Instance.loseGame(true); // force die animation

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(false);
    }
Пример #23
0
    public static bool beginCollisionWithScenery(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        // if chasing then avoid wall penetration
        Chase chase = shape1.GetComponent <Chase>();

        if (chase != null && chase.isChasing() && GameObjectTools.isWallHit(arbiter))
        {
            chase.stopChasing();
            chase.enableOperateWhenOutOfSensor();
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(true);
    }
Пример #24
0
    public static bool beginCollisionWithPlayer(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Chase  chase  = shape1.GetComponent <Chase>();
        Player player = shape2.GetComponent <Player>();

        if (player.isDying() || !chase.isOperable())
        {
            return(false);            // stop collision since this frame
        }
        // start chasing player
        chase.target = player.transform;
        chase.enableChasing();

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(false);
    }
Пример #25
0
    public static bool beginCollisionWithOneway(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        // if collision starts from below then proceed to the oneway platform logic
        if (GameObjectTools.isHitFromBelow(arbiter))
        {
            shape1.GetComponent <ClimbDownFromPlatform>().setTraversingUpwards(true);
            return(true);            // return true so the PreSolve condition continues
        }
        // collisiion from above, then player is on platform
        else
        {
            shape1.GetComponent <ClimbDownFromPlatform>().handleLanding();
        }

        // oneway platform logic was not met
        return(false);
    }
Пример #26
0
    public static bool beginCollisionWithScenery(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        // The order of the arguments matches the order in the function name.
        arbiter.GetShapes(out shape1, out shape2);

        Player player = shape1.GetComponent <Player>();

        /*if (player.isDying())
         *      return false; // stop collision with scenery since this frame*/

        player.exitedFromScenery = false;

        // avoid ground penetration (Y axis)
        // NOTE: to solve this Chipmunk has the property collisionBias and/or minPenetrationForPenalty
        Vector2 thePos = player.body.position;
        float   depth  = arbiter.GetDepth(0);

        thePos.y            -= depth;
        player.body.position = thePos;

        // if isn't a grounded surface then stop velocity and avoid getting inside the object
        if (GameObjectTools.isWallHit(arbiter))
        {
            // get sign direction to know what offset apply to body
            player.signCollision = -Mathf.Sign(player.transform.position.x - shape2.transform.position.x);
            // set moving velocity close to 0 so player can't move against the wall but can change direction of movement
            player.walkVelocity = 0.001f;
            // move back to the contact point and a little more
            thePos               = player.body.position;
            thePos.x            += player.signCollision * (depth - 0.01f);
            player.body.position = thePos;
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next frame.
        return(true);
    }
Пример #27
0
    public static bool beginCollisionWithPowerUp(ChipmunkArbiter arbiter)
    {
        ChipmunkShape shape1, shape2;

        arbiter.GetShapes(out shape1, out shape2);

        Goomba  goomba  = shape1.getOwnComponent <Goomba>();
        PowerUp powerUp = shape2.getOwnComponent <PowerUp>();

        if (goomba.dieAnim.isDying())
        {
            return(false);            // avoid the collision to continue since this frame
        }
        else
        {
            powerUp.Invoke("destroy", 0f);             // a replacement for Destroy
            goomba.die();
        }

        // Returning false from a begin callback means to ignore the collision response for these two colliding shapes
        // until they separate. Also for current frame. Ignore() does the same but next fixed step.
        return(false);
    }
    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, &centroid, 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);
    }