entity_picking.script 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. go.property("camera_url", msg.url("/camera#camera"))
  2. --- Performs a raycast from the camera through a screen position to find an entity.
  3. -- @param camera_url url The camera URL to use for screen-to-world conversion
  4. -- @param screen_x number The x-coordinate on the screen
  5. -- @param screen_y number The y-coordinate on the screen
  6. -- @param collision_groups table The collision groups to check against as array of hash values
  7. -- @return table|nil The first entity hit by the ray, or nil if nothing was hit
  8. local function pick_entity(camera_url, screen_x, screen_y, collision_groups)
  9. local from = camera.screen_to_world(vmath.vector3(screen_x, screen_y, 0), camera_url)
  10. local to = camera.screen_to_world(vmath.vector3(screen_x, screen_y, 100), camera_url)
  11. local results = physics.raycast(from, to, collision_groups, { all = false })
  12. if not results then
  13. return nil
  14. end
  15. return results[1]
  16. end
  17. function init(self)
  18. -- Use the projection provided by the camera
  19. msg.post("@render:", "use_camera_projection")
  20. -- Acquire input focus to receive input events
  21. msg.post(".", "acquire_input_focus")
  22. self.input_pressed = false -- Tracks if the input is currently pressed
  23. self.last_input = nil -- Stores the last input action received
  24. self.previous = nil -- Keeps track of the previously highlighted entity
  25. end
  26. function update(self, dt)
  27. if not self.last_input then
  28. -- No input received yet
  29. return
  30. end
  31. local result = pick_entity(self.camera_url, self.last_input.screen_x, self.last_input.screen_y, { hash("target") })
  32. if result then
  33. -- Store in the result table the model URL of the entity just for convenience
  34. result.model_url = msg.url(nil, result.id, "model")
  35. -- Set the tint of the entity to highlight it
  36. go.set(result.model_url, "tint.w", 1.5)
  37. -- If the input is currently pressed, move the camera to the entity
  38. if self.input_pressed then
  39. -- We want to move the camera to only the X,Y of the entity, so we get its position
  40. local move_to = go.get("/camera", "position")
  41. move_to.x = result.position.x
  42. move_to.y = result.position.y
  43. go.cancel_animations("/camera", "position")
  44. go.animate("/camera", "position", go.PLAYBACK_ONCE_FORWARD, move_to, go.EASING_INOUTQUAD, 0.5)
  45. end
  46. -- If the previously highlighted entity is different from the current entity, reset its tint
  47. if self.previous and self.previous.id ~= result.id then
  48. go.set(self.previous.model_url, "tint.w", 1)
  49. end
  50. self.previous = result
  51. else
  52. -- No entity was hit, so reset the tint of the previously highlighted entity
  53. if self.previous then
  54. go.set(self.previous.model_url, "tint.w", 1)
  55. self.previous = nil
  56. end
  57. end
  58. end
  59. function on_input(self, action_id, action)
  60. if action_id == hash("touch") then
  61. -- "touch" is a screen touch or mouse click. We only want to react to the press event.
  62. self.input_pressed = action.pressed
  63. elseif not action_id then
  64. -- If action_id is nil, it means that the action is a mouse move event.
  65. -- "action" contains the mouse move event data. We want to store it for later use.
  66. self.last_input = action
  67. end
  68. end