Jump to content

Physics Movement


MackeyK24
 Share

Recommended Posts

Yo @fenomas  your code sets xdir and zdir and then check in javascript like this:

if (xdir || zdir)

I would think that check for NON -NULL or in Javascript is it checking for NOT-ZERO ???

I hate the 'loosy goosy' nature of javascript... anything can be anything and anything can change to anything... That is why I love coding with typescript...

even though it ends up javascript... but it FEELS like coding in C# or something for the web... actually I used to write Apache Flex Enterprise Application using ActionScript 3 and typescript FEELS ALOT like that :)

Anyways... I think I should be check NOT ZERO :)

Link to comment
Share on other sites

Looks how nice and neat this class is... This is my equivalent of Unity's Character Controller... To provide basic movement for characters via is API move function... So if you were making a Third person (or any controller for your character) you can move that like like you would in unity (if staying in the spirit of unity design when using the toolkit to make your game)...

Anyways the class is fuck sweet... Thanks to all the 'GUYS' work SMOOTHLY and PERFECTLY :

And it handle the STATE OF CHARACTER MOVEMENT... Am I Jumping, Falling or Grounded States All built - in...

(THAT FRICTION WAS REALLY SCREWING ME UP... BUT FIXED NOW)

module BABYLON {
    export class CharacterController extends BABYLON.MeshComponent {
        public avatarHeight:number = 2.0;
        public avatarRadius:number = 0.25;
        public fallingVelocity:number = 0.1;
        public isJumping():boolean { return this._jumping; }
        public isFalling():boolean { return this._falling; }
        public isGrounded():boolean { return this._grounded; }
        public getVelocity():BABYLON.Vector3 { return this._velocity; }
        public getRotation():BABYLON.Vector3 { return this.manager.getAngularVelocity(this.mesh); }
        public onPhysicsContact:(collider:BABYLON.AbstractMesh, tag:string)=>void = null;
        private _jumping:boolean = false;
        private _falling:boolean = false;
        private _grounded:boolean = true;
        private _threashold:number = 0.5;
        private _velocity:BABYLON.Vector3 = BABYLON.Vector3.Zero();
        private _angularVelocity:BABYLON.Vector3 = BABYLON.Vector3.Zero();
        private _jumpingVelocity:BABYLON.Vector3 = BABYLON.Vector3.Zero();
        public constructor(owner: BABYLON.AbstractMesh, scene: BABYLON.Scene, tick: boolean = true, propertyBag: any = {}) {
            super(owner, scene, tick, propertyBag);
            this.avatarHeight = this.getProperty("avatarHeight", 2.0);
            this.avatarRadius = this.getProperty("avatarRadius", 0.25);
            this.fallingVelocity = this.getProperty("fallingVelocity", 0.1);
        }
        protected start():void {
            this._jumping = false;
            this._falling = false;
            this._grounded = true;
            this.updateGroundingState();
            this.onCollisionEvent((collider:BABYLON.AbstractMesh, tag:string) => {
                if (this.manager.checkCollisionContact(this.mesh, collider, BABYLON.CollisionContact.Bottom, this._threashold) === true) {
                    this._jumping = false;
                    this.updateGroundingState();
                }
                if (this.onPhysicsContact != null) this.onPhysicsContact(collider, tag);
            });
        }

        protected update() :void {  this.updateGroundingState(); }
        protected after() :void {  this.updateGroundingState(); }
        protected updateGroundingState():void {
            this._velocity = this.manager.getLinearVelocity(this.mesh);
            this._falling = (this._jumping === false && this._velocity != null && this._velocity.y < (-this.fallingVelocity));
            this._grounded = (this._jumping === false && this._falling === false);
        }
        
        /* Public Character Controller Movement Functions */
        
        public move(velocity:BABYLON.Vector3, rotation:number = 0.0, jump:number = 0.0):void {
            this.rotate(0.0, rotation, 0.0);
            this.manager.setLinearVelocity(this.mesh, velocity);
            if (jump > 0.0) {
                this._jumping = true;
                this._jumpingVelocity.copyFromFloats(0.0, jump, 0.0);
                this.manager.applyImpulse(this.mesh, this._jumpingVelocity, this.mesh.getAbsolutePosition());
                this.updateGroundingState();
            }
        }
        public rotate(x: number, y: number, z: number):void {
            this._angularVelocity.copyFromFloats(x, y, z);
            this.manager.setAngularVelocity(this.mesh, this._angularVelocity);
        }
    }
}

 

SWEET :)

 

And @fenomas I AM NOT FIGHTING THE PHYSICS ANYMORE... So I am going to bother you in a few days about how to get a little hover at the top of jumps :)

 

Link to comment
Share on other sites

Glad it's working out!

 

57 minutes ago, MackeyK24 said:

if (xdir || zdir)

I would think that check for NON -NULL or in Javascript is it checking for NOT-ZERO ???

It does both. In JS, null and zero are both "falsey" values - that is, they evaluate to false when casted to Boolean, so code like the above works fine.

With that said, I only wrote it that way because for me it's idiomatic. If it looks wrong to you, by all means change it!

If you're curious, here's the full list of falsey values in JS:

false, null, 0, '', undefined, NaN

All other values are "truthy" - i.e. evaluate to true inside an if statement.

 

Oh, and please tag me if you post something you want me to check - I don't visit the forum that often, and miss a lot of threads.

Link to comment
Share on other sites

I smell something.  :)

Smell it?  It's like... self-blown ass-smoke.  I think Mackey blew some smoke up his own ass.   heh.

You KNOW what you REALLY want, doncha, Mackey McWhacky?  https://previews.123rf.com/images/lucadp/lucadp1305/lucadp130500032/20006727-one-carton-box-with-legs-and-smiling-face-3d-render--Stock-Photo.jpg

Two legs, each with ankle, knee, and hip joints - full physics.  You want to fire an up/forward impulse under the left foot.  It launches the shoe... up/forward, bending at ankle, knee and hip joints a bit, and then the shoe's mass drops it all to the floor again. Then the other leg.  Then the first again.  Pulse, pulse, pulse, the ol' locomotion begins - baby's first steps.  Box rocks back and forth just a little... and Mackey's BiPedophile comes to life!   Errr... maybe that's not a good name.  :D

C'mon Mack... you know you're not satisfied.  The gloss-over will come back to haunt you.  Truth is, the Unity mover and the BJS mover... both suck, right?  You'll need to code up new ones for both systems.  :D  No?  (I'm just having some fun with ya, M... but I'm right, right?)

Jiggle the camera.pos.y a bit when each foot hits the floor?  You bet!   I'd work on it with ya... in a playground.  BiPed Imperial Walker 1.0.  Yay!  I need the same thing for some landing gear for a flying machine... but the hinge joints need... springy-constraint... just like real knees.  I haven't learned to do that, yet.

You got time for a 6-month tangent-from-main-project, right M?  Winter is coming... let's build legs over the winter.  :)

Link to comment
Share on other sites

4 hours ago, Wingnut said:

I smell something.  :)

Smell it?  It's like... self-blown ass-smoke.  I think Mackey blew some smoke up his own ass.   heh.

You KNOW what you REALLY want, doncha, Mackey McWhacky?  https://previews.123rf.com/images/lucadp/lucadp1305/lucadp130500032/20006727-one-carton-box-with-legs-and-smiling-face-3d-render--Stock-Photo.jpg

Two legs, each with ankle, knee, and hip joints - full physics.  You want to fire an up/forward impulse under the left foot.  It launches the shoe... up/forward, bending at ankle, knee and hip joints a bit, and then the shoe's mass drops it all to the floor again. Then the other leg.  Then the first again.  Pulse, pulse, pulse, the ol' locomotion begins - baby's first steps.  Box rocks back and forth just a little... and Mackey's BiPedophile comes to life!   Errr... maybe that's not a good name.  :D

C'mon Mack... you know you're not satisfied.  The gloss-over will come back to haunt you.  Truth is, the Unity mover and the BJS mover... both suck, right?  You'll need to code up new ones for both systems.  :D  No?  (I'm just having some fun with ya, M... but I'm right, right?)

Jiggle the camera.pos.y a bit when each foot hits the floor?  You bet!   I'd work on it with ya... in a playground.  BiPed Imperial Walker 1.0.  Yay!  I need the same thing for some landing gear for a flying machine... but the hinge joints need... springy-constraint... just like real knees.  I haven't learned to do that, yet.

You got time for a 6-month tangent-from-main-project, right M?  Winter is coming... let's build legs over the winter.  :)

I dont understand any of what you just said here... I am going to try go animation heavy with maybe the future possibility of some FootIK to plant feet on ground... if it can be done in babylonJS... I saw a BoneIKController... maybe thats where I will start for that ...

But yeah... I am pretty happy with the Physics Movement modeled after the Unity Character Controller... But my own add features... I am working on the state machine now to switch/blend animation states... Working pretty good so far... Besides ... I have NOTHING else to go on since we (babylon) has no existing character controller type deal...

And once you get the toolkit... you can also use ALL th toolkit features to put your game together and in your script components you can go as NUTS as you want to ... after all is the same typescript babylon api. ... just run within a Component Life Cycle :)

 

Link to comment
Share on other sites

Hey @fenomas  I am sometimes experience the player mesh/collider get STUCK when colliding with the some the boxes... specially if I jump and land on the corner edges... sometimes it will get STUCK there... Unity Character Controller us e a 'SkinWidth' property that they use in there physics to help with character getting STUCK on colliders... Do we have anything like to deal with getting STUCK when colliding ?

Link to comment
Share on other sites

8 hours ago, MackeyK24 said:

I dont understand any of what you just said here

Yeah, I don't, either.  :)

Are you still mixing physics engine impostors... with mesh.ellipsoid/.checkCollisions? 

Something to try:  After a "jump-upon" collision, down-scale your ellipsoid collider for a moment, and then return it to normal size.  No promises... but it MIGHT get your collider un-stuck.

A nice test might be... onCollideWithJumpedUponThing... register a new beforeRender... that VERY SLOWLY down-scales/reduces the Y-height of the jumpedUponThing.ellipsoid.  See if your player starts sinking into the jumped-upon mesh, or slides off edge, or some other ugly thing.  This would tell us IF the size of the collision ellipsoid is being live-updated, even while in a possible "stuck" condition.

You might even have to down-scale/up-scale the player.ellipsoid or jumpedUponThing.ellipsoid... in tiny steps... but still in a fast for-loop.  You might not need to down-scale very far, though.  In other words, if you are collider-stuck, reduce the height/size of ellipsoids by .5%, then another .5%, then another .5%, and then back to normal size.  It might only take 1-3 of those .5% reductions... to get UN-stuck.

This is hard to explain, but, you can do a FAST down-scale, but the up-scaling back to normal scale... might need to be done in smaller steps.  Know why?

When player jumps on box, it can land "too deep" into the ellipsoid collider (gets stuck).  Then you reduce the size of the jumpedUponThing.ellipsoid, and IF your gravity is still active, player will begin sinking into mesh.  Then, if you SUDDENLY go back to ellipsoid full size, you have caused the two ellipsoids to overlap even worse than the original overlap.  The player ellipsoid didn't have time to get out of the way of the suddenly-expanding jumpedUponThing.ellipsoid.

I would highly-recommend using/improving the .showEllipsoid func from the barrels demo.  Seeing your colliders... is rather handy.

So... the secret here might be... reduce ellipsoid size fast, but bring it back to normal-sized... somewhat gradually.  Not necessarily slowly, though.  Do it as fast as possible, but do it in small steps, so the player has time to rise... with the expanding jumpedUponThing.ellipsoid.  No promises, just thoughts.  Report findings, if you do experiments with this, ok?  (you usually do, thx for that)  I'll shut up now.  byee.  :)

Link to comment
Share on other sites

8 hours ago, MackeyK24 said:

Hey @fenomas  I am sometimes experience the player mesh/collider get STUCK when colliding with the some the boxes... specially if I jump and land on the corner edges... sometimes it will get STUCK there... Unity Character Controller us e a 'SkinWidth' property that they use in there physics to help with character getting STUCK on colliders... Do we have anything like to deal with getting STUCK when colliding ?

STUCK isn't a specific enough problem to solve. My first guess is, the code to turn off friction isn't firing for whatever reason, and the friction makes it seem like the character can't move. But that's just a shot in the dark!

Link to comment
Share on other sites

3 hours ago, fenomas said:

STUCK isn't a specific enough problem to solve. My first guess is, the code to turn off friction isn't firing for whatever reason, and the friction makes it seem like the character can't move. But that's just a shot in the dark!

Friction seems to be the culprit again... I am current APPLYING friction if IM GROUNDED and NO vertical or horizontal input is given in that frame otherwise I am using the baseFriction... Like your demo... Just to test.. On the Player ONLY I just ZERO the friction (leaving 0.1 friction on the other obstacles and boxes)

Seems to work a lot better... Can/Should I just leave the Player Friction at zero ... I don't seems to get any EXTRA SLIDING or anything when contacting the ground... Note I am moving using setLinearVelocity and NOT applyForce

 

What do you think about ZERO friction on Character Controller using setLinearVelocity for its movement (and all other things have some sort of friction on them) ???

Link to comment
Share on other sites

@MackeyK24 Honestly, it comes down to what you want. I like using forces and friction because that's what I normally expect from platformers - whether it's super mario, Quake, or whatever, you usually don't go from motionless to full speed and back, you gradually speed up and slow down, and using forces does that.

As for zeroing friction, again it depends what you want. I suspect that you probably don't want zero friction all the time though - e.g. if the player is standing motionless on a ramp, with no friction they'll start sliding down it, which may not be what you expect.

Link to comment
Share on other sites

7 minutes ago, fenomas said:

@MackeyK24 Honestly, it comes down to what you want. I like using forces and friction because that's what I normally expect from platformers - whether it's super mario, Quake, or whatever, you usually don't go from motionless to full speed and back, you gradually speed up and slow down, and using forces does that.

As for zeroing friction, again it depends what you want. I suspect that you probably don't want zero friction all the time though - e.g. if the player is standing motionless on a ramp, with no friction they'll start sliding down it, which may not be what you expect.

You right (as always) ... I just REMOVED the isGrounded check.... If I am applying horse or vert user input AT ALL ... ApplyFriction(0) else ApplyFriction(base)

Link to comment
Share on other sites

34 minutes ago, fenomas said:

I like using forces and friction because that's what I normally expect from platformers - whether it's super mario, Quake, or whatever, you usually don't go from motionless to full speed and back, you gradually speed up and slow down, and using forces does that.

I can't get ApplyForce to work at all... I tried: mesh.physicsImposter.applyForce(vector, mesh.getAbosulutePosition)... It does nothing :(

EDIT:  I got applyForce to work... Must havee been type-o or something... I see the effect is has when doing a hard change direction.

I will probably make it a Drop Down choice on the Character Controller to move with 'Velocity' or 'Forces'

Again... Bro... Thanks for al the AWESOME advise you give :)

 

Link to comment
Share on other sites

1 hour ago, Pryme8 said:

I wonder if I can dig up my old PG that shows the difference between force and impulse.  It was like 2 years ago almost now though so not sure how to track it down.

I think I get em... Is working pretty freakin awesome ... Can just use a switch in the editor inspector to say the character controller is working in 'Direct Velocity' mode which give you that Unity NON-RIGIDBODY type character movement MOST of the Tutorials will be using... Then you can always set to 'Applied Forces' mode which give the Super Mario direct change using 'Forces'... My main move functions on the Character Controller are Nice and Clean and should handle all the movement types:

/* Public Character Controller Movement Functions */

public move(velocity:BABYLON.Vector3, jump:number = 0.0):void {
    if (this.movementType === BABYLON.MovementType.AppliedForces) {
        this.manager.applyForce(this.mesh, velocity, this.mesh.getAbsolutePosition());
    } else {
        this.manager.setLinearVelocity(this.mesh, velocity);
    }
    if (jump > 0.0) {
        this._jumping = true;
        this._jumpingVelocity.copyFromFloats(0.0, jump, 0.0);
        this.manager.applyImpulse(this.mesh, this._jumpingVelocity, this.mesh.getAbsolutePosition());
        this.updateGroundingState();
    }
}
public rotate(x: number, y: number, z: number):void {
    this._angularVelocity.copyFromFloats(x, y, z);
    this.manager.setAngularVelocity(this.mesh, this._angularVelocity);
}
public friction(level:number):void {
    this.manager.applyFriction(this.mesh, level);
}

But now I got a Physics Performance Question for @Pryme8 and @fenomas ...

Right now I am Assuming a TRUE grounded state... If you JUMP I set grounded to false and WAIT for a collision event and check normals at 'BOTTOM' contact... am I 'Standing' on a collider within a certain threshold ... If so... I set JUMP to FALSE and GROUNED to TRUE.

protected start():void {
    this._jumping = false;
    this._falling = false;
    this._sliding = false;
    this._grounded = true;
    this.updateGroundingState();
    this.onCollisionEvent((collider:BABYLON.AbstractMesh, tag:string) => {
        if (this.manager.checkCollisionContact(this.mesh, collider, BABYLON.CollisionContact.Bottom, this._threashold) === true) {
            this._jumping = false;
            this.updateGroundingState();
        }
        if (this.onPhysicsContact != null) this.onPhysicsContact(collider, tag);
    });
}

I would really like a 'Performant Way' on each frame to say 'Hey, am i in contact (standing on) a collider... If so IM GROUNDED... I don't want to depend on getting that collision event to say whether I am grounded or not...

now I see plenty of cannon code the loops thru the word contacts BUT that seems EXPENSIVE:

var upVector = new CANNON.Vec3(0, 1, 0);
var contactNormal = new CANNON.Vec3(0, 0, 0);

world.addEventListener("postStep", function(e) {
    isOnGround = false;

    if(world.contacts.length > 0) {
        for(var i = 0; i < world.contacts.length; i++) {
            var contact = world.contacts[i];
            if(contact.bi.id == object.id || contact.bj.id == object.id) {
                if(contact.bi.id == object.id) {
                    contact.ni.negate(contactNormal);
                } else {
                    contact.ni.copy(contactNormal);
                }

                isOnGround = contactNormal.dot(upVector) > 0.5;
            }
        }
    }
}

Is there a good way of checking by frame if I am in contact with another collider... if so I can use my same check normals to see if I'm standing (I can also check the ANGLE of the standing contact and see if I'm sliding (and velocity.y < -this.slidingVelocity)) ???

 

Link to comment
Share on other sites

6 hours ago, MackeyK24 said:

Is there a good way of checking by frame if I am in contact with another collider... if so I can use my same check normals to see if I'm standing (I can also check the ANGLE of the standing contact and see if I'm sliding (and velocity.y < -this.slidingVelocity)) ???

Cannon supposedly has beginContact / endContact events, but they don't fire for me in the playground - not sure if that's a cannon bug or a version issue or what.

There's also a "world.collisionMatrix.get(body1, body2)" method, which seems to be undocumented, but works for me. But this only covers collisions between two bodies, so it's not really what you want.

http://www.babylonjs-playground.com/#U4F9K1#4

 

7 hours ago, Pryme8 said:

I wonder if I can dig up my old PG that shows the difference between force and impulse.

In most engines (including Cannon AFAIK) they're identical, except that forces get multiplied by the timestep and impulses don't. 

Link to comment
Share on other sites

4 hours ago, Pryme8 said:

why not just add a collision listener to the player body?


player.body.addEventListener("collide",function(e){
              console.log("Collided with:",e.body);
              console.log("Contact:",e.contact);
          });

can we not add this event to the cannon bodies anymore?

I already do that this:

this.onCollisionEvent((collider:BABYLON.AbstractMesh, tag:string) => {
    if (this.manager.checkCollisionContact(this.mesh, collider, BABYLON.CollisionContact.Bottom, this._threashold) === true) {
        this._jumping = false;
        this.updateGroundingState();
    }
    if (this.onPhysicsContact != null) this.onPhysicsContact(collider, tag);
});

and the Scene Component API: OnCollisionEvent:

public onCollisionEvent(handler:(collider:BABYLON.AbstractMesh, tag:string) => void):void {
    if (this._mesh.metadata != null && this._mesh.metadata.api) {
        this._mesh.metadata.collisionEvent = handler;
    }
    if (this._mesh.physicsImpostor != null) {
        var anyImpostor:any = (<any>this._mesh.physicsImpostor);
        if (anyImpostor.onCollideEvent == null) {
            anyImpostor.onCollideEvent = this.updatePhysicsCollisionEvent;
        }
    } else {
        BABYLON.Tools.Warn("Physics imposter not defined for mesh: " + this.mesh.name);
    }
}

And the Actual Event Handler:

private updatePhysicsCollisionEvent(collider: BABYLON.PhysicsImpostor, collidedAgainst:BABYLON.PhysicsImpostor) : void {
    if (collider.object != null && collidedAgainst.object != null) {
        var colliderAny:any = collider.object;
        if (colliderAny != null && colliderAny.metadata != null && colliderAny.metadata.collisionEvent != null) {
            var collidedAgainstAny:any = collidedAgainst.object;
            if (collidedAgainstAny != null) {
                var collidedAgainstTag:string = "Untagged";
                if (collidedAgainstAny.metadata != null && collidedAgainstAny.metadata.tagName != null && collidedAgainstAny.metadata.tagName !== "") {
                    collidedAgainstTag = collidedAgainstAny.metadata.tagName;
                }
                colliderAny.metadata.collisionEvent(collidedAgainstAny, collidedAgainstTag);
            }
        }
    }
}

Works pretty good... I was just checking to see if there was another way to do it WITHOUT the event.. Some kind of frame checking... But it would seem that the collision Event is the ONLY way (without looping thru all the world contacts)

But it does work :)

 

Link to comment
Share on other sites

12 hours ago, Pryme8 said:

why not just add a collision listener to the player body?


player.body.addEventListener("collide",function(e){
              console.log("Collided with:",e.body);
              console.log("Contact:",e.contact);
          });

can we not add this event to the cannon bodies anymore?

As near as I can tell, that event is basically "contactStart", and there's no corresponding contactEnd, is the problem.

Or rather, there seems to be "beginContact/endContact" events in the cannon codebase, but they don't fire in the playground and I'm not sure why.

Link to comment
Share on other sites

On 2017/9/23 at 12:09 PM, fenomas said:

As near as I can tell, that event is basically "contactStart", and there's no corresponding contactEnd, is the problem.

Or rather, there seems to be "beginContact/endContact" events in the cannon codebase, but they don't fire in the playground and I'm not sure why.

I also found out that issue, the reason seems that the pre-built version in GIT is out-of-sync with the source code, please rebuild using grunt again, you can listen the events in the World object, hope this will help

Link to comment
Share on other sites

Yeah, you're right - Cannon added proper contact events but hasn't done a version release since then.

Probably the best answer is for people using Cannon in their project to do a local build and use that. I'm not sure it would make sense for Babylon to pull in a new build if the cannon maintainer isn't going to issue one..

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...