Skip to content

Normalization of direction vector on npcs and player #286

@ipinzi

Description

@ipinzi

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions