3D Top Down aiming system

Hi,
this is my very first game project ever so I have no previous experience besides java programming.

For a learning project, I decided to create a top-down 3D voxel spaceship meteor shooter (keyboard, gamepad, eventually local multiplayer) to learn most basics fast.

Now, I got my character down and found some very helpful YT videos for the movement and when it came to aiming the spaceship I first decided to simply face the player to the mouse location on the screen by ray casting (movement and rotation independent from another). This works perfectly fine, but I want to implement a different system and don’t know how (and can’t find articles or videos that help).

Instead of always facing the player towards the mouse, I want it to rotate only when moving the mouse accordingly and save its rotation when the mouse is still. Currently, I can leave my mouse and orbit around it with my spaceship (like the rotation is locked on if you get what I mean).
Comparable to how top-down rotations with gamepads work; the player rotates as long as you rotate the joystick but it keeps its rotation if you let go of the stick.

How can I change my current script so it works clean?
Or do you have a YT tutorial I missed that explains all that?

EDIT:
This is what I try to replicate.
And this is what my movement currently looks like.
EDIT2:
I found out that Getting Over It has the exact controls I was looking for (despite the different camera angle), so I asked Bennett Foddy how he did it. This was his reply: translating the cursor’s local position to world space to make it interact with game objects in the scene.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class MovementBehaviour : MonoBehaviour
{
    private Rigidbody sphereRigbod;
    private PlayerInput playerInput;
    private PlayerInputActions playerInputActions;

    private Camera mainCamera;

    public WeaponBehaviour weapon;

    [SerializeField] private float speed = 70f;

    private void Awake()
    {
        sphereRigbod = GetComponent<Rigidbody>();
        playerInput = GetComponent<PlayerInput>();

        playerInputActions = new PlayerInputActions();
        playerInputActions.PlayerMovement.Enable();         //Enables EVERY Action map set up!

        mainCamera = FindObjectOfType<Camera>();

    }

    private void FixedUpdate()
    {
        faceMouse();

        //X Z Movement WASD
        Vector2 inputVector = playerInputActions.PlayerMovement.Movement.ReadValue<Vector2>();
        sphereRigbod.AddForce(new Vector3(inputVector.x, 0, inputVector.y) * speed, ForceMode.Force);

    }

    /* Faces the player character to the mouse on screen
     */
    private void faceMouse()
    {
        Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
        Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
        float rayLength;

        if(groundPlane.Raycast(cameraRay, out rayLength))
        {
            Vector3 pointToLook = cameraRay.GetPoint(rayLength);
            Debug.DrawLine(cameraRay.origin, pointToLook, Color.red);

            transform.LookAt(new Vector3(pointToLook.x, transform.position.y, pointToLook.z));
        }
    }
}

EDIT: Replace the green “applied force” with “movement direction”

I appreciate your effort to draw a diagram but I don’t understand the green.

You mark the green as “applied force”… why would the applied force of an asteroids ship ever be different than the way it is facing?

Do you mean that the green is actually velocity? Velocity is your movement, force is what might be applied by a thrusting engine, which in every asteroids game I’ve played is ALWAYS in line with the ship.

When force is on, it can adjust the velocity vector accordingly.

Now this question:

This will be problematic. What is “moving” or “still?” The mouse freezes every frame it doesn’t move… and then every frame there is an update it would move… is that what you want to base your spaceship rotation on, this sort of stop-and-start of a typical mouse?

Usually the spaceship always turns to face the mouse, but you only thrust when the thrust button is down.

You’re right, that was my mistake. The green arrows indicate the movement direction of the spaceship, so “direction” would fit better than “velocity” (I think? Sorry, English is not my first language).
The movement along the X and Z axis is independent of the ship’s rotation. That means I’m able to face the front of the ship left while moving right.

I just remembered where I’ve seen this movement before, in “Enter The Gungeon”.
I made a preview clip here.
And this is what my movement currently looks like.

I really don’t know why I didn’t come up with this earlier.
Really sorry for the confusion.

Your visual communication skills are EXCELLENT however.

Compare those two video clips:

in Gungeon, the player never moves onscreen (camera tracks him exactly). He is always in exactly the same place all the time. That means the mouse also stays the same relative to him, so when the mouse is stationary, it works.

In your clip, your player moves around the screen while the camera does not … this means the relative player-to-mouse movement changes.

Try this: in LateUpdate(), copy the player position X,Y to the camera X,Y.

I think it will work.

Oh, I didn’t even consider the static/dynamic camera!
Well, the problem is: I need the camera to be static, since it’s supposed to be arena-like (much like Bit Blaster XL, on Steam).

I just thought; maybe I need an empty object “focalPoint” that the character always faces. Now the focalPoint obj inherits the X and Z movement of the character, but when the mouse is moved, the mouse vector is added (or multiplied) on top.
So if I WASD the character, the exact values are applied to the focalPoint - so the character doesn’t turn since the focalPoint is in the same spot in relation to the character - but when I move the mouse the focalPoint = playerCharacter * mousePosition and the character rotates in relation to the relative position.

Does that sound like something I can work from?

Perhaps… it might feel weird that the player moving moves the mouse.

But yes, the key takeaway difference is that you may need to remove the system mouse and have your own mouse cursor, as trying to change the system mouse position is often problematic.

But give it a whirl. I always try to stay away from ANY operations with the system mouse, as it is usually just a disaster waiting to happen: works fullscreen, doesn’t work windowed, or vice versa, or fails as soon as you have two monitors, etc.

And with your own mouse you would not be reading mouse position: you would be reading mouse deltas and adding it to your own notion of position.

Seems like I have a bumpy road ahead of me…
But thanks for your help! Really appreciate it.
If I make any sort of progress I’ll post here if anyone is in the same situation.

1 Like

Update: what I was looking for was a way to translate the cursor’s local position to world space so it can interact with objects in the scene itself. I wasn’t able to implement anything working yet, but I’ll keep updating.

Relevant things for this might include this (for raycasting):

https://docs.unity3d.com/ScriptReference/Camera.ScreenPointToRay.html

or perhaps this:

https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html