Get world location of mouse point

I eventually want to allow my game to pan (RTS style) over the world by holding right-click and moving the mouse.

I figured I would start by getting the world coordinates of where the mouse is pointing when I right-click - but this is not working. The console log shows “undefined” instead but there are no errors. This script is attached directly to my camera.

MoveCamera.prototype.onMouseDown = function (event) {
    // If the left mouse button is pressed, change the cube color to red
    if (event.button === pc.MOUSEBUTTON_LEFT) {
        
    }

    // If the left mouse button is pressed, change the cube color to green
    if (event.button === pc.MOUSEBUTTON_MIDDLE) {
        
    }

    // If the left mouse button is pressed, change the cube color to blue
    if (event.button === pc.MOUSEBUTTON_RIGHT) {
        var fromWorldPoint = MoveCamera.fromWorldPoint;
        var toWorldPoint = MoveCamera.toWorldPoint;
        var worldDiff = MoveCamera.worldDiff;
        console.log(fromWorldPoint);
    }
};

I found some orbit camera examples but I wasn’t able to make them work either. Could someone help me out by helping me first figure out how to find the current world coordinates of the mouse?

Thanks!

To get the world position of the mouse cursor you need to use the screenToWorld method of the camera component:

https://developer.playcanvas.com/en/api/pc.CameraComponent.html#screenToWorld

Here is an example on how to use it, from the Orbit Camera (found in the Model View starter kit) panning the camera:


MouseInput.prototype.pan = function(screenPoint) {
    var fromWorldPoint = MouseInput.fromWorldPoint;
    var toWorldPoint = MouseInput.toWorldPoint;
    var worldDiff = MouseInput.worldDiff;
    
    // For panning to work at any zoom level, we use screen point to world projection
    // to work out how far we need to pan the pivotEntity in world space 
    var camera = this.entity.camera;
    var distance = this.orbitCamera.distance;
    
    camera.screenToWorld(screenPoint.x, screenPoint.y, distance, fromWorldPoint);
    camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);

    worldDiff.sub2(toWorldPoint, fromWorldPoint);
       
    this.orbitCamera.pivotPoint.add(worldDiff);    
};

I see you got some lines from this method in your code, but that isn’t enough. You need to actually call the screenToWorld method with the correct arguements to get the world position.

Now if you aren’t using an orbit camera and you want to implement a traditional top-down RTS camera (fixed height), here is a very simple way to get you started:

MoveCamera.prototype.onMouseDown = function(event) {
  if (event.button === pc.MOUSEBUTTON_RIGHT) {
      var cameraSpeed = 0.05;
      this.entity.translate(event.dx * cameraSpeed, 0, event.dy * cameraSpeed);
  }
};

2 Likes

Thanks for your response!

I implemented your code by adding the line below to my initialize function:

    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);

And I added the following code below the update function:

MoveCamera.prototype.onMouseDown = function(event) {
  if (event.button === pc.MOUSEBUTTON_RIGHT) {
      var cameraSpeed = 0.05;
      this.entity.translate(event.dx * cameraSpeed, 0, event.dy * cameraSpeed);
      
      console.log("event.dx: " + event.dx + ", event.dz: " + event.dy);
  }
};

However, when I look at the console log event.dx and event.dy are 0 and the camera does not move. Any ideas what I could be missing here?

Thanks again!

Ah right, I think dx/dy is available only during mouse move, can you try doing something like this:

this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);

MoveCamera.prototype.onMouseMove = function (event) {    
    var mouse = this.app.mouse;
    if (mouse.isPressed(pc.MOUSEBUTTON_RIGHT)) {
      var cameraSpeed = 0.05;
      this.entity.translate(event.dx * cameraSpeed, 0, event.dy * cameraSpeed);
      
      console.log("event.dx: " + event.dx + ", event.dz: " + event.dy);
    }
};
1 Like

So cool!! That worked perfectly!! Thank you so much!

Through this process I also figured out how to include a line break in chrome so I could examine the variables. Very cool!

Thanks again!

1 Like

So I was looking into fromWorldPoint and I expected to be able to access it like this:

MoveCamera.prototype.onMouseDown = function (event) {
    console.log("fromWorldPoint: " + MoveCamera.fromWorldPoint);    
}

This also returns undefined. I tried changing the function (event) to function (screenPoint) but that didn’t seem to change anything. I got the same result for toWorldPoint as well… Not sure what’s going on here.

@Paul_Hill can you share again your script at the current state?

MoveCamera.fromWorldPoint is just a pc.Vec3() helper object used in the OrbitCamera scripts. If you aren’t using the same setup it is normal to be empty.

Also what would you like to do on MouseDown? If you would like to get the world pos under the mouse cursor, here is the simplest way to do it:

MoveCamera.prototype.onMouseDown = function (event) {
    // for the following code to work, this.worldPos should be added in the initialise method of the script like this:
   // this.worldPos = pc.Vec3();
    this.entity.camera.screenToWorld(event.x, event.y, 100.0, this.worldPos);
    console.log(this.worldPos);
}

It will return the worldPos under the mouse cursor 100.0 units forward. Change 100.0 to your camera’s fixed height to get accurate ground positions.

1 Like

Sure here you go: https://playcanvas.com/project/648278/settings

Taking a look at the code you posted. Thanks for your time!

EDIT: So this worked:

this.worldPos = pc.Vec3();
console.log(this.entity.camera.screenToWorld(event.x, event.y, 100.0, this.worldPos));

Good, you don’t have to use the MoveCamera.fromWorldPoint property, just try playing directly with the screenToWorld method.

Check my last code example, make sure to initialise the this.worldPos property and set the correct camera distance, which would be around 10.0 from what I see in your scene.

1 Like

Great! You are learning quickly :wink:

1 Like

I have a great Jedi teacher! Thanks again!

1 Like