How to build a (working ;) elevator?

hey there,
so i’m trying to build an elevator, but somehow it’s not working and i can’t find a solution… Can someone please point me in the right direction? thanks!

EDIT: PG → https://playground.babylonjs.com/#1UU4WF#2

so i have a player being followed by a FollowCamera().

player.checkCollisions, player.applyGravity and player.collisionsEnabled are all set to true.

i move the player around via player.moveWithCollisions(new BABYLON.Vector3(0, 0, 0.2)); which works fine, the player runs against walls as intendet.

now i want an elevator to lift the player up along the z-axis. fist i tried an animation, but the elevator-tile just moved trough the player not affecting it.

then i build the elevator-tile the same way i build my player, moving it with moveWithCollisions, too. but it still moves through the player :confused:

can someone please explain to me, why my player is running correctly against walls, but my elevator-tile is not “running” against my player nor affecting it in any way?

many thanks!

1 Like

I am looking forward to hear some answers here, but will share what I did previously and why it’s not a good solution. I had the same issues you have come across as well on a game I had made in 2017.

In my game I have cylinders that go up and down and if objects in the game are on the cylinder when it goes up or down, I wanted those objects on the cylinder to also go up or down.

My code snippets are something like this:

const toggleLift = (onComplete: () => void): void => {
  var animationLower = new BABYLON.Animation(
    'liftAnimation',
    'position.y',
    30,
    BABYLON.Animation.ANIMATIONTYPE_FLOAT,
    BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT
  );
  if (this.lift.physicsImpostor !== null) {
    this.lift.physicsImpostor.sleep(); // turns off physics on this body
  }
  animationLower.setKeys(...);

  let easingFunction = new BABYLON.ExponentialEase(9.7);
easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
  animationLower.setEasingFunction(easingFunction);
  animationTarget.animations.push(animationLower);

  // code here to find all objects on the cylinder and parent them to the cylinder
  // and to sleep their impostors and and end up animation wakeup and unparent.

  scene.beginAnimation(animationTarget, 0, 100, false, 1, () => {
    if (this.lift.physicsImpostor !== null) {
        this.lift.physicsImpostor.wakeUp();
    }
    onComplete();
});
}

I think I tried using SetLinearVelocity, but the sphere objects that were on top of the cylinder would go flying. I think I had also tried applying impulses to guide the cylinder and it got messy.

My solution above isn’t good, because it doesn’t maintain true physics. ie: if a ball rolls onto the cylinder when it’s going up then the velocity was lost. All in all it was not a good solution, but sometimes how not to do it from somebody else who struggled may be helpful.

Anyway, I’m looking forward to finding solutions to the same problem!

1 Like

Hey there, I made a few changes to the playground to get it working:

I changed the ellipsoid sizes to match the mesh sizes (they were too big I think), changed the z positions to be the same for player and elevator (0), and changed the parameter passed to moveCollisions to be the position delta, not the final position.

And a simple way to smoothen the movement is to set a velocity in the keyboard handler and call moveWithCollisions each frame instead of calling it on each key press event, like in this playground for example.

I suspect using a physics engine like Cannon could produce a better-looking elevator motion, accounting for things like mass and gravity, but I haven’t used that much so will share this documentation link instead, which also includes playground examples of applying forces. :slightly_smiling_face:

1 Like

hey brianzinn and blake,

thanks for your replies! sooo… if i understand you correctly moving a player just by colliding the elevator-tile into him is not possible - without using a physics engine?

thanks for your pg @Blake . now the player is interacting with the tile (by stopping it), but unfortunately it is still not able to lift him up…

so i experimented some more:
https://playground.babylonjs.com/#1UU4WF#6

i tried setting up a physicsimposter. my idea was/is, that the heavier object (elevator-tile) sould pass its kinetic energy on to the lighter one(player). The kinetic energy should be generated via moveWithCollisions?

but its not working. all i achieved by applying mass was that player and tile now fall - what is propably not the ideal behaviour for an elevator :slight_smile:

so i followed your @brianzinn idea and set a velocity. i am able to katapult the player into the air, but when i apply the velocity to the tile the player still stops it (so i asume?)…

maybe i’m all wrong, but if i’m able to pass on the impulse/kinetic energy from the tile to the player both should move up…?

does anybody have an idea of how to achive this?

edit: i’m not a very smart man… :slight_smile: i put the mass of the tile to hight or the velocity to low. now its kinda working…
https://playground.babylonjs.com/#1UU4WF#7 but as you wrote, it’s messy… :slight_smile:

1 Like

Here’s a playground example of moving them together without a physics engine. When the elevator collides with the player, the player is made a child of the elevator so that they move together. Physics is too complex for me to come up with anything RN but seems interesting and powerful. :thinking: :smiley:

EDIT: with this solution you could also just use simple keyframe animations on the elevator position, since moveWithCollisions isn’t used anymore…

2 Likes

YES! Thank you @Blake thats what i’m going with…
(Still not a 100% shure why i have to parent the mesh but nevermind :wink:

///

I experimented some more with the physics-approch, trying to get rid ob the wobbeling, but it is not the most elegant solution i think. nevertheless, maybe someone can use it for scaps in the future. :slight_smile:
https://playground.babylonjs.com/#1UU4WF#10

///

However your approch using the actionmanager to parent the mesh on intersect didn’t work on moving the elevator down - or atleast i couldn’t make it work :slight_smile:

so i came up with the following, which works like a charm:

setup_elevator(){
                var ani_length = 30;
                
                this.elevator.animation1 = new BABYLON.Animation("elevator_move", "position.y", ani_length, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);

                this.elevator.animation1.setEasingFunction(this.easing.inout);
                                
                const keyFrames1 = []; 

                keyFrames1.push({
                    frame: 0,
                    value: 0.0
                });

                keyFrames1.push({
                    frame: ani_length,
                    value: 5
                }); 
                
                this.elevator.animation1.setKeys(keyFrames1);
                
                this.elevator.mesh.animations.push(this.elevator.animation1);
}

and to trigger the animation:

 move_elevator(dir){
                if (this.player.parent !== this.elevator.mesh) {
                    this.player.setParent(this.elevator.mesh);                
                }
                
                if(dir == 'up'){
                    var start   = 0;
                    var stop    = 30;
                }
                else if(dir == 'down'){
                    var start   = 30;
                    var stop    = 0;
                }
                
                var eleani = this.scene.beginAnimation(
                    this.elevator.mesh,
                    start,
                    stop,
                    false,
                );
};

i don’t know if it is necessary, but whenever i try to un-parent my mesh after the successful elevator-ride i crash my approch, because the onAnimationEnd function is triggert to early…

i use

eleani.onAnimationEndObservable.add( () => {this.player.setParent(null)});

is there a possibility to make it trigger in the right moment or is it just unnecessary to unparent the mesh after the ride?

1 Like

Looks good to me, un-parenting after the elevator ride would be needed for the elevator to move independently of the player (otherwise the player will keep moving up or down by the same amount as the elevator, even when not on it). Your code and approach looks good to me thou, so I guess I’d have to see it not working in the playground to try to see where the problem is…

here is a playground:
https://playground.babylonjs.com/#1UU4WF#14

thinking about it, it would probably be better to unparent the elevator, otherwise a player going up by elevator and then down the stairs would probably sink into the ground on calling the elevator again :slight_smile:

thanks for your efford!

1 Like

Ooh, that’s a little trickier, but I think it works well to parent on collision and un-parent when they’re no longer colliding: so whenever the player collides with the elevator from above it rides the elevator until the player moves off of it… Here’s the playground with the collision events added for entering and exiting the collision. :slightly_smiling_face:

2 Likes

i tried your approach with OnIntersectionEnterTrigger and OnIntersectionExitTrigger to unbind two iterations ago but skipped it, because once you go up (and walk around) and re-enter the elevator to go down OnIntersectionEnterTrigger is not trigged (since there is no touching between player and elevator-tile), therefore the player keeps hovering while the elevator goes down… so far, so logical… :slight_smile:
this is why I tried to parent on keypress and to un-parent on onAnimationEnd (which triggers way to early for no good reason… )

so I build an invisible elevator-cabin-mesh (with more volume) bound to the elevator-tile to trigger OnIntersection and bind the player to the elevator-tile. (Pretty obvious, i could have thought of this one earlier… :slight_smile:

Now everything is working as intendet!

dear @Blake , thanks a lot for your feedback and help in building a working elevator!!! :slight_smile:

2 Likes