I'm making an engine for a game. Give me some good advice

I’m making an engine for a game. Give me some good advice.
I did it in a complicated way and it lags, maybe there are options to make it simpler.
I use Kinematics on the character. Because the dynamics don’t suit me

var PlayerController = pc.createScript('playerController');


PlayerController.attributes.add('speed', { type: 'number', default: 7 });

PlayerController.prototype.initialize = function () {
    this.gamepadEnabled = false;
    this.setupUI();

    this.Test = 0;
    this.Test1 = 0;
    this.Test2 = 0;
    

    this.entity.collision.on('collisionstart', this.onCollisionStart, this);
};

PlayerController.prototype.update = function (dt) {
    if (this.app.keyboard.wasPressed(pc.KEY_Q)) {
        this.gamepadEnabled = true;
    }

    if (this.gamepadEnabled) {
        const gamepad = navigator.getGamepads()[0];
        if (gamepad) {
            this.handleMovement(gamepad, dt);
            this.displayGamepadInfo(gamepad);
        }
    }

   
};

PlayerController.prototype.onCollisionStart = function (result) {
    this.Test2 = result.other.name === "Box4" ? 1 : 0;
    this.Test1 = result.other.name === "Box1" ? 1 : 0;
    this.Test = result.other.name === "Box" ? 0 : 0;
    this.Test = result.other.name === "Ramp" ? 1 : 0;
};

PlayerController.prototype.handleMovement = function (gamepad, dt) {
    let horiz = -gamepad.axes[0] || 0;
    let vert = -gamepad.axes[1] || 0;

    const deadZone = 0.2;
    horiz = Math.abs(horiz) < deadZone ? 0 : horiz;
    vert = Math.abs(vert) < deadZone ? 0 : vert;

    let moveX = 0, moveY = 0, moveZ = 0;
    let angle = null;

    if (vert > 0) { moveZ = this.speed * dt; angle = 0; }
    else if (vert < 0) { moveZ = -this.speed * dt; angle = 180; }
    else if (horiz < 0) { moveX = -this.speed * dt; angle = 270; }
    else if (horiz > 0) { moveX = this.speed * dt; angle = 90; }
      if (this.Test1 === 1) {
        moveX = 0;
        const pushBack = 0.5;
        if (gamepad.axes[0] > 0) moveX += pushBack;
        else if (gamepad.axes[0] < 0) moveX -= pushBack;
        this.Test1 = 0;
    }

    if (this.Test2 === 1) {
        moveZ = 0;
        const pushBack = 0.5;
        if (-gamepad.axes[1] > 0) moveZ -= pushBack;
        else if (-gamepad.axes[1] < 0) moveZ += pushBack;
        this.Test2 = 0;
    }

    
    if (this.Test === 1 && moveX !== 0) {
        const rad = 32.3 * (Math.PI / 180);
        const direction = gamepad.axes[0] > 0.1 ? -1 : 1;

        const originalMoveX = moveX;
        moveX *= Math.cos(rad);
        moveY = direction * Math.abs(originalMoveX) * Math.sin(rad);

     
    }

    this.entity.anim.setBoolean('walk', angle !== null);
    if (angle !== null) {
        const targetRot = new pc.Quat().setFromEulerAngles(0, angle, 0);
        this.entity.setRotation(targetRot);
    }

   
    this.entity.translate(moveX, moveY, moveZ);
};

PlayerController.prototype.applyPushback = function (axisValue, strength) {
    if (axisValue > 0.1) return -strength;
    if (axisValue < -0.1) return strength;
    return 0;
};

PlayerController.prototype.displayGamepadInfo = function (gamepad) {
    const pos = this.entity.getPosition();
    this.gamepadInfo.innerHTML =
        `<strong>Gamepad Info:</strong><br>` +
        gamepad.axes.map((val, i) => `Axis ${i}: ${val.toFixed(2)}<br>`).join('') +
        gamepad.buttons.map((btn, j) => `Button ${j}: ${btn.pressed ? 'Pressed' : 'Released'}<br>`).join('') +
        `<br><strong>Position:</strong> X: ${pos.x.toFixed(2)} Z: ${pos.z.toFixed(2)} Y: ${pos.y.toFixed(2)}<br>`;
};

PlayerController.prototype.setupUI = function () {
    this.gamepadInfo = document.createElement('div');
    Object.assign(this.gamepadInfo.style, {
        position: 'absolute',
        top: '50px',
        left: '10px',
        backgroundColor: 'rgba(0,0,0,0.5)',
        color: 'white',
        padding: '10px',
        fontFamily: 'Arial',
        fontSize: '12px'
    });
    document.body.appendChild(this.gamepadInfo);
};

Hi @karbanalexey and welcome!

I’d prefer not to base player movement on collisions and names. Instead, you could consider using a downward raycast to determine ground angles from the hit normal, and possibly some forward raycasts to detect obstacles in front.

Could you please specify what lags and when it lags?

https://youtu.be/P7AYfGtjdVQ Example of game lags

I see what you mean. To be honest, I think it’s just your logic that is failing. For example, maybe the bottom of the collision component has contact with an entity, while the side of the collision component has also contact with an entity.

When you use raycasts, you only need to set the y position to the hit point of the raycast downward. You can use the raycast forward for collision detecting.

I did it a little differently, I lowered the player collider a little bit down, analogous to raycast, and here is the result. Maybe there are lessons or examples somewhere on how engines are created?

1 Like

With engine you mean a game?

Maybe the course below is something that can help.

Thanks a lot !

1 Like

I repeated the script as in the video but there is no turn, what could it be?

var Test = pc.createScript('test');
Test.attributes.add('speed', { type: "number"});
Test.attributes.add('modelEntity', { type: "entity"});
// initialize code called once per entity
Test.prototype.initialize = function() {

};

// update code called every frame
Test.prototype.update = function(dt) {
   var x = 0;
   var z = 0;
if (this.app.keyboard.isPressed(pc.KEY_W)){
    z+=1;
}   
if (this.app.keyboard.isPressed(pc.KEY_S)){
    z-=1;
}   if (this.app.keyboard.isPressed(pc.KEY_A)){
    x+=1;
}   if (this.app.keyboard.isPressed(pc.KEY_D)){
    x-=1;
}   

    
    const movement = new pc.Vec3(x,0,z).normalize().scale(dt*this.speed)
   this.entity.rigidbody.applyForce(movement);

   const newAngle = 90 - (Math.atan2(z,x)*pc.math.RAD_TO_DEG);
   this.modelEntity.setEulerAngles(0,newAngle,0);
    

};

Test video

The Angular Factor of the y-axis should be 1.

I fixed the code, there is already movement but another problem appeared, when descending from the ramp gravity does not work, increasing mass or force or gravity immobilizes the player. What are the options to fix this?
video of lags

var PlayerController = pc.createScript('playerController');


PlayerController.attributes.add('speed', { type: "number" });
PlayerController.attributes.add('modelEntity', { type: "entity" });

PlayerController.prototype.initialize = function () {
    this.gamepadEnabled = false;
    this.setupUI();

   this.force = new pc.Vec3();

   
};

PlayerController.prototype.update = function (dt) {
    if (this.app.keyboard.wasPressed(pc.KEY_Q)) {
        this.gamepadEnabled = true;
    }

    if (this.gamepadEnabled) {
        const gamepad = navigator.getGamepads()[0];
        if (gamepad) {
            this.handleMovement(gamepad, dt);
            this.displayGamepadInfo(gamepad);
        }
    }

 
};



PlayerController.prototype.handleMovement = function (gamepad, dt) {
    let x = -gamepad.axes[0];
    let z = -gamepad.axes[1];
    const deadZone = 0.05;
    z = Math.abs(z) < deadZone ? 0 : z;
    x = Math.abs(x) < deadZone ? 0 : x;

    const isMoving = x !== 0 || z !== 0;

    
    if (this.entity.anim) {
        this.entity.anim.setBoolean('walk', isMoving);
    }

    if (isMoving) {
        this.force.set(x, 0, z).normalize().scale(this.speed);
        this.entity.rigidbody.applyForce(this.force);

        const angleRad = Math.atan2(x, z);
        const targetY = pc.math.RAD_TO_DEG * angleRad;
        const currentEuler = this.modelEntity.getEulerAngles();
        const newY = pc.math.lerpAngle(currentEuler.y, targetY, dt * 100);
        this.modelEntity.setEulerAngles(0, newY, 0);
    }

    this.modelEntity.setPosition(this.entity.getPosition());
    //this.entity.rigidbody.applyForce(0, -500, 0);
};




PlayerController.prototype.displayGamepadInfo = function (gamepad) {
    const pos = this.entity.getPosition();
    this.gamepadInfo.innerHTML =
        `<strong>Gamepad Info:</strong><br>` +
        gamepad.axes.map((val, i) => `Axis ${i}: ${val.toFixed(2)}<br>`).join('') +
        gamepad.buttons.map((btn, j) => `Button ${j}: ${btn.pressed ? 'Pressed' : 'Released'}<br>`).join('') +
        `<br><strong>Position:</strong> X: ${pos.x.toFixed(2)} Z: ${pos.z.toFixed(2)} Y: ${pos.y.toFixed(2)}<br>`;
};

PlayerController.prototype.setupUI = function () {
    this.gamepadInfo = document.createElement('div');
    Object.assign(this.gamepadInfo.style, {
        position: 'absolute',
        top: '50px',
        left: '10px',
        backgroundColor: 'rgba(0,0,0,0.5)',
        color: 'white',
        padding: '10px',
        fontFamily: 'Arial',
        fontSize: '12px'
    });
    document.body.appendChild(this.gamepadInfo);
};

In my own game applying a downward force works fine. You can try to decrease Linear Damping. If you do this you also need to decrease your movement force.