JamesTKhan/Mundus

GameObject finder/picker method in gdx-runtime module

Closed this issue · 4 comments

Dgzt commented

Is your feature request related to a problem? Please describe.
I think a game object finder/picker method by screen x and y coordinates in the gdx-runtime module would be useful.

Describe the solution you'd like
A GameObject findBy(int screenX, int screenY) method in SceneGraph class.

Additional context
The editor uses a finder method in GameObjectPicker class but it uses opengl hack what is not really recommended ( http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-an-opengl-hack/ ).

An other way that use libgdx's Intersector.intersectRayTriangle(...) method to check for every model's meshes.
(Examples: libgdx/libgdx#1256 , https://stackoverflow.com/questions/56837626/libgdx-intersect-ray-with-mesh-from-modelinstance ). But I think it is cause huge CPU usage if there are lot of game objects on the map.

Dgzt commented

A possible solution:

        private GameObject getObject(final int screenX, final int screenY) {
		final Vector3 position = new Vector3();

		Ray ray = scene.cam.getPickRay(screenX, screenY);
		GameObject selectedGO = null;
		float distance = -1;
		for (int i = 0; i < scene.sceneGraph.getRoot().getChildren().size; ++i) {
			final GameObject gameObject = scene.sceneGraph.getRoot().getChildren().get(i);

			final ModelComponent modelComponent = (ModelComponent) gameObject.findComponentByType(Component.Type.MODEL);

			if (modelComponent != null) {
				gameObject.getPosition(position);
				position.add(modelComponent.getCenter());

				if (!ModelUtils.isVisible(scene.cam, modelComponent.getModelInstance(), modelComponent.getCenter(), modelComponent.getDimensions())) {
					continue;
				}
				final float len = ray.direction.dot(position.x - ray.origin.x, position.y - ray.origin.y, position.z - ray.origin.z);
				if (len < 0f) {
					continue;
				}
				float dist2 = position.dst2(ray.origin.x + ray.direction.x * len, ray.origin.y + ray.direction.y * len, ray.origin.z + ray.direction.z * len);
				if (distance >= 0f && dist2 > distance) {
					continue;
				}
				if (Intersector.intersectRayBoundsFast(ray, position, modelComponent.getDimensions())) {
					selectedGO = gameObject;
					distance = dist2;
				}
			}
		}
		return selectedGO;
	}

This uses the model component's dimension to detect model game object.

@JamesTKhan Is this accurate enough?

This is not intended to replace the Editor picking right? Just a new method to add to the runtime for raypicking GameObjects in runtime applications?

Dgzt commented

This is not intended to replace the Editor picking right? Just a new method to add to the runtime for raypicking GameObjects in runtime applications?

Yes, just a new method in runtime. Maybe we could put this method into runtime and if someone needs a more accurate method then she/he can use bullet or ode4j for picking, like in your video.

Dgzt commented

I was thinking about this issue and I will close it. If anyone need a picker method can use bullet or ode4j like in previous comment.