RPG-JS icon indicating copy to clipboard operation
RPG-JS copied to clipboard

Normalization of direction vector on npcs and player

Open ipinzi opened this issue 1 year ago • 1 comments

Firstly, love the work that is happening on this project

So I just cloned the project and took a look at the example project and there seems to be some oversight in the gameplay programming When moving diagonally the player moves faster than moving horizontally, usually this is because the input vector is not normalized.

I dug a bit deeper into the code and found where directions are being assigned but it looks like this would only deal with 4 directional movement from what I can see...

if (input == Control.Action) {
    await player.triggerCollisionWith(RpgCommonPlayer.ACTIONS.ACTION)
}
else if (
    input == Direction.Left ||
    input == Direction.Right ||
    input == Direction.Up ||
    input == Direction.Down
) {
    player.moving = true
    moving = true
    const isMove = await player.moveByDirection(+input, deltaTimeInt || 1)
    if (isMove) {
        routesMove.push(inputData)
    }
}

So it seems like the movement for x and y axis would be additional and therefore the length of the directional vector is wrong when moving diagonally. Anyway! The way that the direction is calculated is fine but the fact that is added together for x and y, FORGETABOUTIT you don't want to do that.


    private directionToAngle(direction: number): number {
        const angle = (direction < 2 ? +direction + 2 : direction - 2) * 90
        return toRadians(angle)
    }

    /** @internal */
    defineNextPosition(direction: number, deltaTimeInt: number): Vector2d {
        const angle = this.directionToAngle(direction)
        const computePosition = (prop: string) => {
            return this.position[prop] + this.speed * deltaTimeInt
                * (Math.round(Math[prop == 'x' ? 'cos' : 'sin'](angle) * 100) / 100)
        }
        // If it's greater than 1, round value to reduces bandwidth
        const x = this.speed < 1 ? computePosition('x') : round(computePosition('x'))
        const y = this.speed < 1 ? computePosition('y') : round(computePosition('y'))
        return new Vector2d(x, y, ~~this.position.z)
    }

What you want to do is get the player input as a vector2. If the player or npc is pressing up or wants to move up the vector2 is (0,-1) if up left its (-1,-1) if down right its (1,1) etc then you can normalize this vector with a function like this:


function normalize(vector: Vector2d): Vector2d {
    const magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    return {
        x: vector.x / magnitude,
        y: vector.y / magnitude
    };
}

That way the length of the vector will be normalized. Then you can multiply that vector by the speed and deltatime and bingo, you have correct diagonal movement consistent with the speed of horizontal movement.

ipinzi avatar May 17 '24 00:05 ipinzi

Hello,

Thanks for your feedback! Your help is very useful for the corrections on RPGJS :)

RSamaium avatar May 30 '24 05:05 RSamaium