Player Object movement questions

Hi again all,

Back again with some more coding questions.

I have a quick and dirty movement system set up for my player object. (the object is a craft that the player flies around, with a camera attached to the back). It’s all very simple at the moment and needs work.

The controls (w,a,s,d, space and c) work fine to move it forward, back, left, right, up and down, And I have the E key set as a very simple ‘afterburner’ key, with ‘steering’ handled by the mouse, and it’s all working as it should.

Now the problem I’m having is that the object just starts and stops dead, which is obviously a bit nasty, I did have another method setup (from the lunar lander tutorial) which had nice intertia etc. on it, but I couldn’t seem to get it to work in terms of flying in the direction the mouse was pointed.

Also, another problem (which I understand from reading on here is because I’m not using the ‘entity.rigidbody’ method to move my ship, so I guess that would be fixed with the movement system using a force.

Here is my code if it’s needed

pc.script.create('player', function (app) {
// Creates a new Player instance
var Player = function (entity) {
    this.entity = entity;
    this.thrustVec = new pc.Vec3();
    

    // Camera euler angle rotation around x and y axes
    var eulers = this.entity.getEulerAngles()
    this.ex = eulers.x;
    this.ey = eulers.y;


    // Disabling the app menu stops the browser displaying a menu when
    // you right-click the page
    app.mouse.disableContextMenu();
    app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
    app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);

};

Player.prototype = {
   update: function (dt) {
        // Update the camera's orientation
        this.entity.setEulerAngles(this.ex, this.ey, 0);


        if (app.keyboard.isPressed(pc.KEY_E)) {
            SPEED = 30;
        } else {
            SPEED = 15;
        }

        // Update the camera's position
        if (app.keyboard.isPressed(pc.KEY_W)) {
            this.entity.translateLocal(0, 0, -SPEED*dt);
        }
        
        if (app.keyboard.isPressed(pc.KEY_S)) {
            this.entity.translateLocal(0, 0, SPEED*dt);
        }

        if (app.keyboard.isPressed(pc.KEY_A)) {
            this.entity.translateLocal(-SPEED*dt, 0, 0);
        } else if (app.keyboard.isPressed(pc.KEY_D)) {
            this.entity.translateLocal(SPEED*dt, 0, 0);
        }
        
        if (app.keyboard.isPressed(pc.KEY_C)) {
            this.entity.translateLocal(0, -SPEED*dt, 0);
        } else if (app.keyboard.isPressed(pc.KEY_SPACE)) {
            this.entity.translateLocal(0, SPEED*dt, 0);
        }
        
    },

    onMouseMove: function (event) {
        // Update the current Euler angles, clamp the pitch.
        this.ex -= event.dy / 5;
        this.ex = pc.math.clamp(this.ex, -30, 30);
        this.ey -= event.dx / 5;
    },

    onMouseDown: function (event) {
        // When the mouse button is clicked try and capture the pointer
        if (!pc.Mouse.isPointerLocked()) {
            app.mouse.enablePointerLock();
        }
    },

};
return Player;
});

Would anyone be willing to help me out, or point me in the direction of examples? I’ve looked at the api for the rigidbody stuff, but tbh, I’ve always found api documentation quite confusing. :-/

Thanks
TheMightySpud

You are right that using forces would solve the problems you’re facing. Basically if you have a rigidbody component on an Entity, then the Entity is controlled by the physics system. From that point on the way to move that Entity would be to either directly set the velocity of the rigid body, or by applying forces to the rigid body.

So in your case what I would do is when the user presses the movement keys, then apply some force towards the desired direction. The force must be applied constantly every frame in order to effectively move the rigid body. To apply force you use this method: http://developer.playcanvas.com/en/engine/api/stable/symbols/pc.RigidBodyComponent.html#applyForce

So in your update() method you would do something like

this.entity.rigidbody.applyForce(desiredForce);

You need to experiment with the magnitude of the force to suit your game.

I should also mention that if you have a rigidbody component on an Entity and you want to directly set the position of that Entity yourself, then you should use this method instead of entity#setPosition: http://developer.playcanvas.com/en/engine/api/stable/symbols/pc.RigidBodyComponent.html#teleport

So you would do

this.entity.rigidbody.teleport(x, y, z);

I would just add that if you are faking movement and acceleration etc - which is sometimes nice and all you need, then you can set your rigidbody to by Kinematic. Then you move it as your are right now, (using teleport or this.entity.rigidbody.syncEntityToBody() after you’ve moved it).

Then you also need to fake acceleration. What I usually do is have a vspeed and an hspeed variable and then add an acceleration to that based on what key is pressed.

To something like:

        if(app.keyboard.isKeyPressed(pc.KEY_W)) {
            this.hspeed = Math.min(this.hspeed + this.hacceleration * dt, this.MAX_HSPEED);
        } else {
            this.hspeed = Math.max(this.hspeed - this.hacceleration * dt, this.MIN_HSPEED);
        }


        this.entity.translateLocal(this.hspeed * dt, 0, 0);
        this.entity.rigidbody.syncEntityToBody();

I do all my movement “faked” this way in [Desert Moon Defender][1] and it works quite nicely.
[1]: https://playcanvas.com/project/346780/overview/desert-moon-defender

Thank you for the replies guys, but this is really beginning to get on my nerves. I’m obviously missing something, but for the life of me I can’t figure out what.

Vaios, your method seems to be the way to go with what I want to do, but I just can’t get it to work, my ship just sits there doing nothing. (that’s if I set it to Kinematic, if I set it to Dynamic, as soon as I press the movement key, everything disappears from the screen :-/)

whydoidoit, I tried your method too, but again couldn’t get it to work. I’m probably getting it all wrong in where I’m putting it etc. But I did try your defender game (nice btw:)) to see if I could figure it out from there, but when I tried it none of the keyboard keys worked, and I couldn’t make any sense of the code (not bad code, just my bad reading of it)

I don’t know if it’s of any help, but I have published the thing as it stands, everything is very temporary just to test the concept and to give me an environment to learn in.

Very Early Concept

If not here’s the ‘simplified’ code I’ve been trying to get to work. I’ve taken out all other keys except the Forward key (w) for simple testing.

pc.script.create('player', function (app) {
// Creates a new Player instance
var Player = function (entity) {
    this.entity = entity;

    // Camera euler angle rotation around x and y axes
    var eulers = this.entity.getEulerAngles()
    this.ex = eulers.x;
    this.ey = eulers.y;

    

    // Disabling the app menu stops the browser displaying a menu when
    // you right-click the page
    app.mouse.disableContextMenu();
    app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
    app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);

};

Player.prototype = {
   update: function (dt) {
       
       
        // Update the camera's orientation
        this.entity.setEulerAngles(this.ex, this.ey, 0);

        // Update the camera's position
    
    if (app.keyboard.isPressed(pc.KEY_W)) {
        this.entity.rigidbody.applyForce(0, 0, 100);
    }

    },

    onMouseMove: function (event) {
        // Update the current Euler angles, clamp the pitch.
        this.ex -= event.dy / 5;
        this.ex = pc.math.clamp(this.ex, -45, 45);
        this.ey -= event.dx / 5;
    },

    onMouseDown: function (event) {
        // When the mouse button is clicked try and capture the pointer
        if (!pc.Mouse.isPointerLocked()) {
            app.mouse.enablePointerLock();
        }
    },

};
return Player;
});

Thanks,
TheMightySpud

I made a veeeery simple test project just to demonstrate the use of rigidbody.applyForce:

https://playcanvas.com/project/348547/overview/test-forces

In this project I disabled gravity by going to the scene settings and making Gravity equal to 0, 0, 0 so that my sphere won’t fall down.

If you press W or S the sphere will move up / down. This is the script that controls the movement:

https://playcanvas.com/editor/code/348547/move.js

I can see a couple issues with your code. The first one is I see you are setting the player’s euler angles directly. As I said in my previous post you cannot control the entity’s transform in any way if you have a rigidbody attached - you should call rigidbody.teleport instead (which also accepts angles after the first 3 arguments). You CAN directly set angles / positions if you want to but after you do that you must call

this.entity.rigidbody.syncEntityToBody()

so that the rigidbody will have the same angles / position as the entity.

The other problem is in your call to applyForce you might be giving it a very large force (100). I don’t know if that’s too much but you should try with small values first (e.g. 1 ) and gradually try larger values until you reach the desired effect.

Well now I feel like a bit of an idiot. lol.

I misunderstood about the teleport, so that’s my bad, trying to implement that now onto the mouse controls.

I have the applyForce bits working on all 3 axes now, turns out it was working all along, but being a bit of a moron, I’d edited the mass of the rigid body so it was ridiculously ‘heavy’

With the mouse control, am I right in thinking that I need to get the position of the player to apply to the first 3 arguments in the teleport argument? In my head just adding 0,0,0 would reset the players position to the origin.

Time for some trial and error. lol.

Thank you so much for the help :smile:

TheMightySpud

Okay, I think I’m missing something really obvious here, but can’t for the life of me see it.

pc.script.create('player', function (app) {
// Creates a new Player instance
var Player = function (entity) {
    this.entity = entity;
    
    // Camera euler angle rotation around x and y axes
    var eulers = this.entity.getEulerAngles()
    this.ex = eulers.x;
    this.ey = eulers.y;
    this.pos = new pc.Vec3();
    
    
    // Disabling the app menu stops the browser displaying a menu when
    // you right-click the page
    app.mouse.disableContextMenu();
    app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
    app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
    
};

Player.prototype = {
   update: function (dt) {

    var zForce=0;   
    var xForce=0;
    var yForce=0;

    // Update the players orientation
    this.pos = this.entity.getPosition();
    this.entity.rigidbody.teleport(this.pos, this.ex/10, 0, 0);
    // Update the Players position

    if (app.keyboard.isPressed(pc.KEY_W)) {
        zForce = -150;
    }
    
    if (app.keyboard.isPressed(pc.KEY_S)) {
        zForce = 50;
    }
    
    if (app.keyboard.isPressed(pc.KEY_A)) {
        xForce = -50;
    }
    
    if (app.keyboard.isPressed(pc.KEY_D)) {
        xForce = 50;
    }
    
    if (app.keyboard.isPressed(pc.KEY_SPACE)) {
        yForce = 50;
    }
    
    if (app.keyboard.isPressed(pc.KEY_C)) {
        yForce = -50;
    }
    
    this.entity.rigidbody.applyForce(xForce, yForce, zForce); 

    },

    onMouseMove: function (event) {
        // Update the current Euler angles, clamp the pitch.
        this.ex -= event.dy / 5;
        this.ex = pc.math.clamp(this.ex, -45, 45);
        this.ey -= event.dx / 5;

    },

    onMouseDown: function (event) {
        // When the mouse button is clicked try and capture the pointer
        if (!pc.Mouse.isPointerLocked()) {
            app.mouse.enablePointerLock();
        }
    },

};
return Player;
});

As stated before I have the translation movement working really nicely, but the ‘mouselook’ type thing I’m trying to get hates me.

In the code above I’m using the getPosition method, and then applying that to the first 3 arguments of the teleport method, and applying the coordinates that are coming from the onMouseMove function to the last 3 arguments.

Now logically (admittedly in my head) this makes perfect sense and should work. But when I run the thing all I get is a blank screen. I’m very quickly running out of hair to pull out. lol.

This is really frustrating because it really shouldn’t be this hard should it? lol.

Thanks
TheMightySpud

You are calling the teleport method using wrong arguments :slight_smile: If you look in the api docs here:

http://developer.playcanvas.com/en/engine/api/stable/symbols/pc.RigidBodyComponent.html#teleport

You’ll see there are 3 versions of the teleport method.

teleport( pos, rot )  // pos is pc.Vec3, rot is pc.Quat
teleport( pos, angles ) // pos is pc.Vec3, angles is pc.Vec3
teleport( x, y, z, ex, ey, ez ) // x, y, z is position and ex, ey, ez are euler angles

You are doing

teleport(this.pos, this.ex/10, 0, 0);

which is not valid.

It’s always a bit hard to learn new APIs but if you use logging and the debugger and frequently check the API docs you’ll be fine soon enough :slight_smile:

Thanks. :slight_smile: I got it working, sort of. lol. It’s not exactly what I wanted, but it’s something I can live with for the moment.

I’ve always found api’s difficult to get my head around, it always seems to me like the documentation is written for people who already know how the api works. lol.

So, next problem is to get my ship to fly in the right direction. At the moment I can look around with the mouse, but when I try to move around I only move on the ‘world axes’ and not in the direction the ship is pointing.

It’s probably something simple like I have some code in the wrong order or something.

Any ideas before I tear my eyes out? lol.

Thanks
TheMightySpud

The direction an Entity is pointing at can be access like so:

this.entity.forward

assuming of course that it’s the Z axis that is looking forward.

So you can do something like

var direction = this.entity.forward.clone();
var force = direction.scale( forceAmount );
this.entity.rigidbody.applyForce(force);

Aaaah, yeah, that looks familiar, I think I used that method on an earlier version (or something very similar). Thank you, and thank you for your patience :smile:

TheMightySpud

Woohoo, success, more or less, a few little niggles, but I’ll come back to those, been looking at the same little bit of code for way too long now. lol.

Now to fix the collision issues (I think I may know what the problem is, but we’ll see)

Thanks again for all the help :slight_smile:
TheMightySpud

2 Likes