sarwin_
sarwin_

Reputation: 21

Using Camera.main.ScreenToWorldPoint while the camera is moving

want to make a game where there is a 2D ball which moves to the position of the cursor. To get the position of the cursor, I use this code:

Vector2 PixelPos = Input.mousePosition;

Then to convert the screen position to world position I use this code:

Vector2 Pos = Camera.main.ScreenToWorldPoint(PixelPos);

The problem is that the main camera move up so that if forces the player to move. But when it move I get some weird movement with the ball.(as the camera is moving up it is always moving the ball)

Is there an alternate way to make this work??

Or more simply can I replace this piece of code:

Vector2 Pos = Camera.main.ScreenToWorldPoint(PixelPos);

with some other things which does not require a camera to convert the screen positions to world position?

Thanks!

Upvotes: 1

Views: 1404

Answers (1)

Ruzihm
Ruzihm

Reputation: 20259

Since you want the cursor to be moved only by the player and to be updated relative to world space, not screen space, you need to implement a virtual cursor that exists in world space.

First, create your virtual cursor as a GameObject. On Update you can update its position with

float sensitivity = 1f;
transform.position += sensitivity * new Vector2( 
        Input.GetAxis("Mouse X"), 
        Input.GetAxis("Mouse Y")
);

Then, instead of using the camera to find the cursor position, you just check the `transform.position` of that virtual cursor `GameObject`.

Second, you'll need to lock the built-in cursor. You can do that with

Cursor.lockState = CursorLockMode.Locked;

If you need to undo that (for instance, if you bring up a menu, and need to use the regular cursor without moving the virual cursor around), then you can use:

Cursor.lockState = CursorLockMode.None; 

or, if you need the cursor to stay in the window:

Cursor.lockState = CursorLockMode.Confined;

If you only want to move the ball to the last position clicked/touched then here is an easier solution.

Keep track of the goal position for the ball, and if one has been set yet:

private Vector2 moveGoalPos;
private bool moveGoalSet= false;

Only change moveGoalPos on frames where the mouse is clicked/the screen is touched.:

bool isTouched;
if (isMouseEnable) {
    isTouched = Input.GetMouseButtonDown(0);
    PixelPos = Input.mousePosition;
} else {
    isTouched = Input.touchCount > 0;
    Touch touch = Input.GetTouch(0);
    PixelPos = touch.position;
}

if (isTouched) {
    moveGoalPos= Camera.main.ScreenToWorldPoint(PixelPos);
    moveGoalSet= true;
}

However, on every frame, you'll want to move the ball to the world space moveGoalPos (only if a goal has been set):

if (moveGoalSet) {
    Vector2 OffsetPos = moveGoalPos + CursorOffSet; 

    GCursor.transform.position = OffsetPos; 
    print(OffsetPos);   
    Vector2 LerpPos = Vector2.Lerp(rb.transform.position, OffsetPos, 0.05f);

    rb.MovePosition(LerpPos);
}

When you need to stop the ball from moving to the last touched/clicked position (for instance, if you change or reset a level), you'll need to reset moveGoalSet:

moveGoalSet = false;

Upvotes: 2

Related Questions