Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question 2D Top-down aiming not directly at cursor.

Discussion in '2D' started by AlphaLulz, Sep 16, 2022.

  1. AlphaLulz

    AlphaLulz

    Joined:
    Sep 2, 2019
    Posts:
    35
    Hey, I'm making a 2D top-down shooter. Unfortunately, I'm having a problem with aiming via mouse. As I intend to make this game multiplayer, all movement and aiming needs to look correct when done in FixedUpdate, since data is sent over the network in fixed intervals.

    My player controller is using Rigidbody2D as it will need to interact with physics. Movement works just fine, but when I put my aiming code into FixedUpdate, the player aims farther ahead while moving as they should. Instead of aiming directly at the cursor, the player rotates to aim slightly beyond the cursor, depending on the direction of movement.

    When in Update, the player aims perfectly at the mouse, but like I said before, I need it to work in FixedUpdate for it to look right on other clients. I've attached a video comparison of FixedUpdate vs Update. The instance on the left is FixedUpdate, and the instance on the right is Update. My goal is to have the rotation on the left look like the rotation on the right while keeping the rotation code in FixedUpdate.

    I'm not sure why this is happening. The only thing I can think of is that the aiming code is sampling the player's position slightly in the past, as that would make the angle farther ahead than it should be. Does anyone know how to make it so the player can aim directly at the mouse when having both movement and aiming in FixedUpdate.

    Here is a link to my player movement/aiming script: https://hastebin.com/kelezawava.cpp
    Here is a link to the video comparison:
     
  2. flasker

    flasker

    Joined:
    Aug 5, 2022
    Posts:
    97
    update runs code every frame

    fixed update doesnt run code every frame, and so, thats why there seems to be lag there are frames where your code to face the cursor isnt being ran
     
  3. AlphaLulz

    AlphaLulz

    Joined:
    Sep 2, 2019
    Posts:
    35
    Yeah, FixedUpdate may make it be sampling from the past. Is there any way for it to be in FixedUpdate and still work tho?
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    8,894
    The script you attached uses physics to change the linear velocity then bypasses physics by writing to the transform. This is seen all the time where rotation is perceived as something special. If you're using physics and want movement, the only way you should ever do that is by always using the Rigidbody2D API. It's role is to write to the Transform, you should not do that. Because FixedUpdate runs at the Time.fixedDeltaTime it might not be in-sync with the frame-rate which might be 60fps, 120fps, 500fps.

    When correctly using the Rigidbody2D API to cause movement, you can ask for interpolation to be on, in which case, inbetween fixedupdate, per-frame it interpolates from the old position to the current position. If the Rigidbody2D is purely Kinematic body-type then use MovePosition/MoveRotation; never touch the Transform.

    If you need physics to be constantly in-sync with rendering then you need to run physics per-frame and understand that the physics simulation would then be operating on a variable time-step which can result in an ever decreasing simulation quality if your frame-rate is low i.e. < 20 fps etc. For a lot of games, this isn't the case nor would it better because it might not have stacked objects and complex joint set-ups.

    You can run physics per-frame by going into the Project Settings > Physics 2D > Simulation Mode and selecting "Update". Physics runs per-update then rather than per fixed-update. Interpolation is turned off even if you ask for it too because it's not required.

    In per-frame mode, you can directly set the Rigidbody2D.position and Rigidbody2D.rotation. Again, don't modify the Transform. When querying the position, read the Rigidbody2D.position/.rotation and NOT the Transform. Leave the Transform for renderers.
     
  5. flasker

    flasker

    Joined:
    Aug 5, 2022
    Posts:
    97
    well if you want fixed update to run every frame like update, no theres not

    youll have to find a work around
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    8,894
    I'm not sure what you're referring to here TBH. "FixedUpdate running every frame" is a contradiction in terms. Maybe you mean the simulation running every frame.

    Interpolation is always historic, for everything not just physics because that's what it is. Extrapolation is futuristic predicition so that's the future. The "here and now" is its current position.

    I see this "discussed" all the time though when simply running the physics per-frame would be perfectly fine for a majority of projects. It's why we're considering it being the default, especially with the new sub-stepping support.
     
  7. AlphaLulz

    AlphaLulz

    Joined:
    Sep 2, 2019
    Posts:
    35
    I've tried using physics for rotation via rb.rotation but that just makes the rotation slightly ahead of the movement instead of behind, I believe. I'm not sure if rb.rotation is the correct thing to do here, but there aren't really any other rigidbody methods that let me aim at the mouse easily. Should I be using something else instead, and if so, how do I also just get to aim at the mouse?
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    8,894
    That just instantly changes the Rigidbody2D rotation. There's absolutely no way it can be "ahead". It's not like it's predictive and can see into the future. ;)

    I think perhaps you're getting confused by the fact that the simulation doesn't run per-frame unless you specify that it should do so.

    The Rigidbody2D pose (position/rotation) is detatched from the Transform position/rotation. When the simulation runs, it writes to the Transform.

    You're asking this question but the answer you need is to understand what stuff does and when it runs.