My angles seem to be skewed, yet the movement is still functioning in my 2D, top-down game. What's causing

I am currently developing a 2D birds-eye view game in JavaScript without using any engine or library, mainly for the learning experience. I have successfully implemented character movement using WASD keys, where the character moves forwards (W) or backwards (S) based on their current direction (A turns left, D turns right). However, I am encountering unexpected results when I output the angles (direction) during gameplay.

For instance, when the player is facing "up" and I press "W", the player moves up, and the output direction is 90° - which is expected. When facing "down" and I press "S", the player moves down, and the direction is 270° as expected.

But, when facing left and moving forward with "W", the character does move left but the output direction is . Similarly, when facing right and moving forward, the output direction is 180°, which is the opposite of my expectations.

The functions responsible for player movement are as follows:

// Turning
    _resetAngle(angle) {
        if (angle >= 360) { return 0 }
        if (angle < 0) { return 359 }
        return angle
    }

    updateDirection(player, keyboardInput) {
        let currentDirection = player.direction
        const turnedLeft = keyboardInput['a']
        const turnedRight = keyboardInput['d']

        if (turnedLeft) { currentDirection -= this.turnAngle }
        if (turnedRight) { currentDirection += this.turnAngle }

        player.setDirection(this._resetAngle(currentDirection))
    }

//Moving
    _calculateNewCoords(movingForward, entity) {
        let newX
        let newY

        // please ignore the code duplication, just testing for now
        if (movingForward) {
            newX = entity.getX() - entity.speed * Math.cos(entity.direction * (Math.PI / 180))
            newY = entity.getY() - entity.speed * Math.sin(entity.direction * (Math.PI / 180))
        }
        else {
            newX = entity.getX() + entity.speed * Math.cos(entity.direction * (Math.PI / 180))
            newY = entity.getY() + entity.speed * Math.sin(entity.direction * (Math.PI / 180))
        }
        return { newX, newY }
    }

    updateCoordinatesByKeyboard(entity, keyboardInput) {
        const movingForward = keyboardInput['w']
        const movingBackwards = keyboardInput['s']

        if ((movingForward && movingBackwards) || !(movingForward || movingBackwards)) { return }
        
        const { newX, newY } = this._calculateNewCoords(movingForward, entity)
        if (this._canMove(entity, newX, newY)) { return entity.setXY(newX, newY) }
    }

This is the section that renders the players:

drawCharacter(character, image) {
    const scale = this._getScale(character) // for a 'breathing' effect, makes character grow and shrink

    this.context.setTransform(scale, 0, 0, scale, this.windowDimensions.width / 2, this.windowDimensions.height / 2)
    this.context.rotate(character.direction * Math.PI / 180)
    this.context.drawImage(image, -image.width / 2, -image.height / 2)
}

When printing player.direction, here are the results:

Output: 90 (as expected)

https://i.sstatic.net/7ZCvV.png

Output: 180 (expect it to be 0)

https://i.sstatic.net/sO8g2.png

Output: 270 (as expected)

https://i.sstatic.net/ClVbr.png

Output: 0 (expect it to be 180)

https://i.sstatic.net/wzmeE.png

Output: 135 (expect it to be 45)

https://i.sstatic.net/YtndF.png

Output: 315 (expect it to be 225)

https://i.sstatic.net/1CPWC.png

To summarize, the player movements work correctly, but the output directions are not as expected. I would like to address this issue because I plan to set NPCs at specific angles in the future and anticipate them facing the correct direction without needing to calculate the 'mirror' direction.

Thank you in advance for any assistance!

Answer №1

The results you are seeing may seem illogical at first glance, but they actually align with what I would anticipate. It appears to be more of a superficial issue that affects all your game objects uniformly.

However, you can easily adjust the output to match your preferred values by:

output = Math.abs((input + 90) % 360 - 270)

With this formula:

90 -> 90

180 -> 0

270 -> 270

0 -> 180

135 -> 45

315 -> 225

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Currently, I am utilizing a Google script to import my emails into a spreadsheet. I am seeking help in identifying and fixing a duplication issue that

For the past few weeks, I have been running a script to gather task data for my company. The script has been running smoothly since 09/03/2023, but recently it started duplicating entries and causing confusion in identifying which tasks are necessary and w ...

Utilizing a npm module in a web browser following importing in Node.js

I recently installed an npm module, but I'm having trouble figuring out how to use it in the browser after importing it. First, I installed the npm module using the following command (using a dummy example module): npm install sample-module In my p ...

Add transparency to elements that are not currently being hovered over using d3's mouseover feature

I'm attempting to implement a mouseover effect that increases the opacity of elements that are not being hovered on. My SVG map consists of various regions, with the current function applying an opacity of 0.8 to the selected region. My goal is to r ...

Is the JSON response in the AJAX request accurate, even though the content is not being refreshed?

I have a function that is triggered in the following manner: success: function(json) { if(json.valid == 1) { // Another show/hide operation that functions properly $("#div-response-" + id).html(json.message); } ...

To retrieve the first td element by clicking a button within the corresponding row using JQuery

This may seem like a straightforward inquiry, but despite my best efforts, I have been unable to find a solution. I am looking to create a function that will allow me to click a button located in the 3rd td element and display the text from the first td e ...

What is the process for obtaining the source code for children in React?

Can React extract the source code from children props? Imagine having a component with the following structure... <SomeComp> <Heading>I want to access this code inside the Heading tag</Heading> </SomeComp> How can I retrieve t ...

How can I update the chartjs instance?

I am currently working on creating a reactive graph that updates based on certain values. However, I am running into issues where my computed ChartData() function is not updating the component as expected. I have tried using the update() function, but I am ...

Datagrid in AngularJS does not update filters upon refresh

Currently, I am attempting to implement name filtering with Angular JS using the following library: https://github.com/angular-data-grid/angular-data-grid.github.io. However, an issue arises when searching as the results do not refresh immediately; only up ...

What is the best way to retrieve a specific number of documents from MongoDB?

I am currently facing an issue with my code that is returning all news related to a company. However, I only want the first 15 elements. Is there a way to achieve this? The following code snippet retrieves all news for a company using the google-news-jso ...

Getting the IDs of selected nodes all the way up to the root node in jsTree

How can I retrieve the IDs of all parent nodes from a selected node to the root node in jsTree? If node C is selected, how can I obtain the IDs of all its parent nodes? Tree Structure: B C +C1 +c2 The following code snippet only returns the imme ...

Why am I consistently obtaining NaN as the output for the majority of my calculations?

Looking to calculate the average of cities in each state using the Reduce Function in mongoDB, but encountering an issue where only one correct result is obtained while rest return as 'nan'. Below is the map function: function map(){ key = {sta ...

Addressing Performance Challenges in Urban Rendering with ThreeJS

Issue: I am facing significant performance problems while rendering a scene using Three JS. The main issue arises from rendering a large number of simple geometries (11,107). (edit) Each building has a unique height based on elevation data, a distin ...

Adding additional functionalities to ng-blur within the controller: A step-by-step guide

I am seeking to enhance the functionality of ng-blur for all input and textarea fields by adding a new function. These elements already have an existing ng-blur defined in the HTML, and my goal is to incorporate a new function into this existing setup from ...

Is there a way to hide an image once my scrollable div has reached a specific height?

I'm currently working on a project that involves a scrollable div with arrows above and below. My goal is to have the arrow above only appear after the div has reached a certain height. Below is the code I've been using... $("#scrolldivup").hid ...

Learn the simple steps to duplicate events using ctrl, drag, and drop feature in FullCalendar v5 with just pure JavaScript

My goal is to incorporate CTRL + Drag & Drop functionality in FullCalendar v5 using nothing but pure JavaScript. I delved into the topic and discovered that this feature has been discussed as a new UI feature request on the FC GitHub repository. There ...

Tips on modifying anchor tag attributes in cross-domain iframe source URLs to open in a new tab

Is there a way to change the target attribute of an iframe child anchor tag from "_blank" to "_parent" or completely remove it? I'm looking for a script that can help me achieve this. How can I modify or delete properties of an anchor tag within an i ...

Animated div positioned on top of an image map

My current project can be found at: (please note that the sounds will not autoplay in the future). I am attempting to incorporate the sun effect from this codepen: https://codepen.io/Hackroro/pen/ByrKLZ I have realized that in order for the sun to appea ...

Responsive Design: Concealing a Sidebar with CSS

Seeking assistance with optimizing the layout of my app, . It currently displays a menu on the left and a login form in the center, with a graph shown to users upon logging in. Is there a way to configure it so that when accessed on iOS: 1) the left menu ...

Sending both an array and an image via Ajax in a single request

I need to send both JSON and file data to my PHP backend using an ajax call. Here is my current ajax call: $.ajax({ type: 'POST', dataType: 'json', data: jsonData, url: 'xxx.php', cache: false, suc ...

How to set a default option in a dropdown menu using Angular 4

Many questions have been raised about this particular issue, with varying answers that do not fully address the question at hand. So here we go again: In my case, setting the default value of a dropdown select by its value is not working. Why is that so? ...