[SOLVED] Entity picking with engine-only

I very much hope that someone has a working example of picking entities in an engine-only scenario. I have done my best to adapt the examples that I’ve seen, but I have a problem in the PickerRaycast.prototype.onSelect function. Basically it complains that “this.camera.screenToWorld() is not a function”. I am adding the camera that gets created earlier in the code as the camera property of the cube. I can see that the camera component is on this (the cube) in the console. And sure enough, in the console, I don’t see that method listed. What’s going on?

https://jsfiddle.net/michaelmccrickard/afrp69de/8/

are you using physics raycast?
http://playcanvas.github.io/#physics/raycast.html

Yes – this is the part from the fiddle above:

var PickerRaycast = pc.createScript('pickerRaycast');
  
  PickerRaycast.prototype.initialize = function() {
     app.mouse.on(pc.EVENT_MOUSEDOWN, this.onSelect, cube);
	}

  PickerRaycast.prototype.onSelect = function (e) {

    var from = this.camera.screenToWorld(e.x, e.y, this.camera.nearClip);
    var to = this.camera.screenToWorld(e.x, e.y, this.camera.farClip);

    var result = this.app.systems.rigidbody.raycastFirst(from, to);
    if (result) {
      var pickedEntity = result.entity;
      console.log(pickedEntity);
      //pickedEntity.script.pulse.pulse();
    }
  };

    cube.addComponent('script');
  cube.script.create("pickerRaycast");

To use rigidbodies, you will need to load the Ammo module for physics.

See here: https://github.com/playcanvas/playcanvas.github.io/blob/master/examples/physics/raycast.html#L25

Looking at the code:

 PickerRaycast.prototype.onSelect = function (e) {

    var from = this.camera.screenToWorld(e.x, e.y, this.camera.nearClip);
    var to = this.camera.screenToWorld(e.x, e.y, this.camera.farClip);

Using the script that I think you have grabbed this from, there’s the assumption that the PickerRaycast script would be attached to the entity that has the camera component and therefore, this.entity.camera would be valid as it would be referencing the camera component on the entity.

Thanks. I did figure out the camera part and those lines work now. But I can’t figure out how to load the ammo.js file. I’m using Vue and whenever I try to include the script with a script tag, I get a syntax error. That’s the same way I’m including the base playcanvas scripts. I think it must have something to do with closures. Unfortunately the WASM loader is not working either – I installed the NPM package but it’s not working.

Is there another way to include ammo.js?

I’ve got an updated fiddle here that nabs the ammo files from playcanvas.github.io

https://jsfiddle.net/L3rg8zsc/5/

Edit: Ah, you are using Vue.js. @Leonidas or @LeXXik, are you able to help here please?

1 Like

I’ll take a look tomorrow, mentioning @iso74 he worked a lot with vue.js and PlayCanvas in case he knows something.

3 Likes

Thanks @Leonidas for mentioning. Did not have the time to exactly figure out what’s the problem here, but @Michael_McCrickard can take a look at my Vue.js project, I am using also Ammo here, just for inspiration - hope that helps:

https://playcanvas-vue.netlify.app/#/

3 Likes

This is all extremely helpful. Just having the URL to the ammo.js is VERY helpful. This example clears up a number of issues for me. And I look forward to checking out https://playcanvas-vue.netlify.app/#/. Thanks so much to all three of you. I am amazed at the support on this forum!

1 Like

Sidenote: I wouldn’t use the links to Ammo I posted as ‘permalinks’ as they could be changed at any time :sweat_smile: Download a copy and host it with your project :slight_smile:

OK, now that I’ve downloaded the file, I’m able to import it without problem.

import Ammo from '../methods/ammo.js';

It imports fine and I get no errors, but again when I try to do raycastFirst(), I get an error here:

_proto.raycastFirst = function raycastFirst(start, end) {
			var result = null;
			ammoRayStart.setValue(start.x, start.y, start.z);
			ammoRayEnd.setValue(end.x, end.y, end.z);

ammoRayStart is undefined, so the setValue() call fails. Is there something I need to do beyond just importing Ammo?

Have the modules been loaded before the pc.app is created?

I moved the import and put in a test to make sure it was done before creating pc.app but still getting undefined on ammoRayStart … Obviously it works when you do the loadScriptAsync(). But I can’t figure out why it would be different with a regular import. I will continue poking around, thanks for your help.

1 Like

I decided to inline the script, the same way I do the others:

<script src='https://cdnjs.cloudflare.com/ajax/libs/playcanvas/1.39.1/playcanvas.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/playcanvas/1.39.1/playcanvas-extras.js'></script>
<script src='https://playcanvas.github.io/examples/lib/ammo/ammo.js'></script>

Now I get a different error, one that happens when I call app.start:

		var _proto = RigidBodyComponentSystem.prototype;

		_proto.onLibraryLoaded = function onLibraryLoaded() {
			if (typeof Ammo !== 'undefined') {
				this.collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();

It says: Ammo.btDefaultCollisionConfiguration() is not a constructor. It’s like this script can’t see the Ammo object? But this error didn’t happen until I inlined the script. ???

If you are importing Ammo manually, then you should instantiate it before accessing the instance methods. For example:

With bundler:

import Ammo from './ammo.js';
Ammo().then(Ammo => {
    // do your routines
    var vector = new Ammo.btVector3();
});

Or your second option:

<html>
    <body>
        <script src="ammo.js"></script>
        <script>
            Ammo().then(Ammo => {
                // do your routines
                var vector = new Ammo.btVector3();
            });
        </script>
    </body>
</html> 

Also, I would recommend to use Wasm version of Ammo as primary, and fallback to JS only if assembly files are not supported on the target. You can see an example of loading Wasm here:
https://playcanvas.github.io/#physics/falling-shapes.html

2 Likes

Well, that’s the ticket, right there! Thanks so much. Now I can rayCastFirst without errors. All that remained was to figure out how to add the rigidbody component, which I located on another forum thread.

[Angular 2 and entity script]

Thanks again to all the people who stepped up to help this PC beginner out!!

1 Like