Character Controller

Ask other users for help.

Character Controller

Postby Kevin » Fri Dec 17, 2010 5:56 pm

Hi,
I just downloaded Jitter, and from what I've seen so far it looks pretty cool. But now I want to use it in order to implement a character controller for my game, but I have no clue how to do this...
I started by creating a rigid body with a capsule shape, but what now? Are there any samples or tutorials on how to implement a character controller (I mean it's needed in almost every game :D ).
Thanks in advance.

best regards,
Kevin
Kevin
 
Posts: 4
Joined: Fri Dec 17, 2010 5:51 pm

Re: Character Controller

Postby noone » Fri Dec 17, 2010 6:39 pm

Hi Kevin!

I started by creating a rigid body with a capsule shape, but what now?


Good start :) I think you want to prevent the capsule from rotating around. You have to set the inverse inertia to a zero matrix. This is done by:

Code: Select all
body.UseUserMassProperties(JMatrix.Zero, 1.0f/playermass, true);


The "only" thing left is to move the character around. This can be done in many ways. You could add force, directly set the velocity or use impulses,. I would suggest the last. I don't know your coding skills, but you have to derive from the constraint class and override the "Iterate" method. Just calculate an impulse to reach your wanted player velocity and apply it there. impulse=mass*velocity . You should do this within the Iterate method of a constraint because in this way the engine is (hopefully) able to find a global solution for your movement (e.g. moving other physic objects apart without penetrating them). Just try this and report back. Feel free to ask :)
User avatar
noone
Site Admin
 
Posts: 437
Joined: Wed Jul 28, 2010 2:02 pm

Re: Character Controller

Postby Kevin » Fri Dec 17, 2010 9:19 pm

Hi,
Thanks for your detailed answer.
This is my player controller class:
Code: Select all
    public class PlayerController : Constraint
    {
        public JVector Velocity { get; set; }

        public PlayerController(float height, float mass) : base(new RigidBody(new CapsuleShape(height, 0.5f)), null) {
            Body1.UseUserMassProperties(JMatrix.Zero, 1.0f / mass, true);
        }

        public override void AddToDebugDrawList(List<Jitter.LinearMath.JVector> lineList, List<Jitter.LinearMath.JVector> pointList) { }

        public override void PrepareForIteration(float timestep) { }

        public override void Iterate()
        {
            accImpulse = Body1.Mass * Velocity;
        }

    }

The Velocity is set by my player class, which uses the controller. Furthermore I've added the Controller to the world:
Code: Select all
World.AddConstraint(controller);

But when I put a breakpoint into the Iterate method, I noticed that the method never gets called...
Any idea why?
Kevin
 
Posts: 4
Joined: Fri Dec 17, 2010 5:51 pm

Re: Character Controller

Postby noone » Fri Dec 17, 2010 9:42 pm

Here is a short example :) Writing a character controller includes alot of tweaking - take this as a start point.

Initialization

Code: Select all
            player = new RigidBody(new CapsuleShape(1.0f, 0.5f));
            player.UseUserMassProperties(JMatrix.Zero, 1.0f, true);
            player.Restitution = 0.0f;

            controller = new CharacterController(World, player);
            this.World.AddBody(player);
            this.World.AddConstraint(controller);


Controlling

Code: Select all
            JVector targetVelocity = JVector.Zero;
            if (keyState.IsKeyDown(Keys.Down)) targetVelocity += JVector.Left;
            if (keyState.IsKeyDown(Keys.Up)) targetVelocity += JVector.Right;
            if (keyState.IsKeyDown(Keys.Left)) targetVelocity += JVector.Backward;
            if (keyState.IsKeyDown(Keys.Right)) targetVelocity += JVector.Forward;
           
            if(targetVelocity.LengthSquared() > 0.0f) targetVelocity.Normalize();
            targetVelocity *= 10.0f;
           
            controller.TryJump = keyState.IsKeyDown(Keys.Space);
            controller.TargetVelocity = targetVelocity;




CharacterController.cs

Code: Select all
    public class CharacterController : Constraint
    {
        private const float JumpVelocity = 0.5f;

        private float feetPosition;

        public CharacterController(World world, RigidBody body)
            : base(body, null)
        {
            this.World = world;

            // determine the position of the feets of the character
            // this can be done by supportmapping in the down direction.
            // (furthest point away in the down direction)
            JVector vec = JVector.Down;
            JVector result = JVector.Zero;

            // Note: the following works just for normal shapes, for multishapes (compound for example)
            // you have to loop through all sub-shapes -> easy.
            body.Shape.SupportMapping(ref vec, out result);

            // feet position is now the distance between body.Position and the feets
            // Note: the following '*' is the dot product.
            feetPosition = result * JVector.Down;
        }

        public World World { private set; get; }
        public JVector TargetVelocity { get; set; }
        public bool TryJump { get; set; }
        public RigidBody BodyWalkingOn { get; set; }

        public override void AddToDebugDrawList(List<JVector> lineList, List<JVector> pointList)
        {
            // nothing to debug draw
        }

        private JVector deltaVelocity = JVector.Zero;
        private bool shouldIJump = false;

        public override void PrepareForIteration(float timestep)
        {
            // send a ray from our feet position down.
            // if we collide with something which is 0.05f units below our feets remember this!

            RigidBody resultingBody = null;
            JVector normal; float frac;

            bool result = World.CollisionSystem.Raycast(Body1.Position + JVector.Down * (feetPosition-0.1f), JVector.Down, RaycastCallback,
                out resultingBody, out normal, out frac);

            BodyWalkingOn = (result && frac <= 0.2f) ? resultingBody : null;
            shouldIJump = (result && frac <= 0.2f && Body1.LinearVelocity.Y < JumpVelocity && TryJump);
        }

        private bool RaycastCallback(RigidBody body, JVector normal, float fraction)
        {
            // prevent the ray to collide with ourself!
            return (body != this.Body1);
        }

        public override void Iterate()
        {
            deltaVelocity = TargetVelocity - Body1.LinearVelocity;
            deltaVelocity.Y = 0.0f;

            // determine how 'stiff' the character follows the target velocity
            deltaVelocity *= 0.02f;

            if(deltaVelocity.LengthSquared() != 0.0f)
            {
                // activate it, in case it fall asleep :)
                Body1.IsActive = true;
                Body1.ApplyImpulse(deltaVelocity * Body1.Mass);
            }

            if (shouldIJump)
            {
                Body1.IsActive = true;
                Body1.ApplyImpulse(JumpVelocity * JVector.Up * Body1.Mass);
                System.Diagnostics.Debug.WriteLine("JUMP! " + DateTime.Now.Second.ToString());

                if (!BodyWalkingOn.IsStatic)
                {
                    BodyWalkingOn.IsActive = true;
                    // apply the negative impulse to the other body
                    BodyWalkingOn.ApplyImpulse(-1.0f * JumpVelocity * JVector.Up * Body1.Mass);
                }
               
            }
        }
    }
User avatar
noone
Site Admin
 
Posts: 437
Joined: Wed Jul 28, 2010 2:02 pm

Re: Character Controller

Postby Kevin » Fri Dec 17, 2010 10:02 pm

Cool, thanks. I'll definately take a look at it, but not before tomorrow :D
Kevin
 
Posts: 4
Joined: Fri Dec 17, 2010 5:51 pm

Re: Character Controller

Postby FinalMirage » Sat Dec 18, 2010 4:34 am

How would I go about adding a variable so I can control how much air control the character has?
FinalMirage
 
Posts: 1
Joined: Sat Dec 18, 2010 4:15 am

Re: Character Controller

Postby noone » Sat Dec 18, 2010 10:42 am

Hi and welcome final mirage!

How would I go about adding a variable so I can control how much air control the character has?


In the Iterate method you have this....

Code: Select all
            // determine how 'stiff' the character follows the target velocity
            deltaVelocity *= 0.02f;



Just check if "BodyWalkkingOn" is set to null and multiply by another value:

Code: Select all
            // determine how 'stiff' the character follows the target velocity
            if (BodyWalkingOn == null) deltaVelocity *= 0.0001f;
            else deltaVelocity *= 0.02f;


Creating a character controller has much to do with tweaking and fiddling around what parameters do what. You don't often want correct physical behavior (For example for a jump and run game you want the user to accurately move the player and not be affected that much by inertia...). For this reason a character controller is not directly implemented in Jitter Physics but it can be easily done using the code above.
User avatar
noone
Site Admin
 
Posts: 437
Joined: Wed Jul 28, 2010 2:02 pm

Re: Character Controller

Postby Kevin » Sat Dec 18, 2010 4:42 pm

Okay, I finally managed to implement the character controller for my player and it works almost perfect. Thank you, really nice support :D
Kevin
 
Posts: 4
Joined: Fri Dec 17, 2010 5:51 pm

Re: Character Controller

Postby Firefly09 » Wed Dec 22, 2010 9:56 am

Kevin wrote:Okay, I finally managed to implement the character controller for my player and it works almost perfect. Thank you, really nice support :D


I'll second that :D Thanks noone for this awsome example and this really great engine!!
Firefly09
 
Posts: 3
Joined: Thu Sep 30, 2010 3:57 pm

Re: Character Controller

Postby CodeSpeaker » Mon Jan 10, 2011 7:23 pm

Great feedback noone, and as most people have pointed out, awesome physics engine youve got there.
..however, i have a small follow-up question on this topic :)

It feels like setting the linear velocity gives me the desired (quick) response that my fps style controller should have without the accelerating style movement.
However, when i jump i can get stuck to walls and wall-climb all the way up to the top, probably because the velocity pushes the body into the wall without the gravity taking effect?
If i do it the other way, by applying impulses for movement, then i get the desired "bounce off" the wall behavior but with an accelerating movement until the player reaches his desired speed which feels more sluggish.
Id like to have the instant acceleration but without wall-climbing.

Any idea on how to resolve this? :)
CodeSpeaker
 
Posts: 5
Joined: Mon Jan 10, 2011 7:14 pm

Next

Return to Questions and Help

Who is online

Users browsing this forum: No registered users and 2 guests

cron