1
\$\begingroup\$

I have 2 Balls, 2 Nodes, and 1 Hand. I can pick up a ball, send it to a Node, grab it, put it on another Node, but I can't grab any other balls.

The problem is that the Ball is defined publicly in The Node Manager. The Node Manager is a script given to The Hand and Each Node, because these are the places The Ball needs to go. While each Holding Place can easily declare itself, there is only one spot for a Ball. I can't add two Balls. I could make a Ball1 and a Ball2, but that's not very scalable.

What I'd like to do is find a way to get the name of the Ball being looked at and use that to power the Ball Selection instead of using a public declaration.

What I want to do is something like a Raycast, but I feel like I'm already using a Raycast by using Pointer Enter and Pointer Exit. When you look at the Balls, they use the Pointers to activate certain scripts like changing the colors of the Balls, and actually triggering the code to grab things. If I can do all that with the Event Triggers, I should be able to specify a Ball. But I can't find out how to do that.

Part of me thinks the code for grabbing the Ball with your Hand actually needs to be on the Balls themselves, and not the Hand, but as much as I try, I can't seem to figure it out. I am officially giving in and asking for help.

I'm working off of this tutorial. I sent the author a message and he said that he's Working On It and would get back to me, but it's been like two weeks. It seems like it should be a really easy fix, but then again, the whole thing is spaghetti code, so who knows.

\$\endgroup\$
  • 2
    \$\begingroup\$ You're not dumb, you're just solving a complex problem that's new to you. To get better answers faster, it helps to clarify what you've done so we can spot ways we can help. "I RTFM'd and it didn't help" doesn't tell us anything about how to help you, because we don't know what parts of the manual you were reading, what you were looking for, and what you didn't find or didn't understand. Instead, try showing a simplified code example, or walking us through the sequence of events when you interact with a ball ("first I click and ScriptA fires a raycast in Update and if it hits a ball, then...") \$\endgroup\$ – DMGregory Aug 4 '18 at 13:41
2
\$\begingroup\$

Oh gosh... I would not recommend following this tutorial series. Apart from the brittle architecture that doesn't scale to multiple balls as you've discovered, I'm seeing errors in their transform code and asset setup already. Their naming conventions are certainly cute, but not as instructive as you'd want to use in production code that needs to make sense to your whole team months later.

I'd recommend starting from scratch. Since I don't currently have a VR development environment configured, I can't give you fully tested code to build from, but I can give a sketch of how we could architect this to scale better:

  • IGazeSelectable interface: defines a contract for anything we want to select with our gaze. It says all these interactions must expose:

    • bool IsSelectionAvailable() predicate: so we know to ignore stuff that's not currently selectable.

    • void OnSelectionComplete() action: a behaviour to fire after our gaze has lingered long enough to complete the selection.

  • Pickup component: represents an object that can be picked up. Holds a reference to the Holder that's currently holding it, if any. Implements IGazeSelectable:

    • IsSelectionAvailable(): check if the Inventory is not currently full.

    • OnSelectionComplete(): tell the Inventory to pick up this object. (Removing it from its current Holder, if any)

  • Holder component: represents a place where a pickup can be stored. Stores a reference to the Pickup it's currently holding, if any. Implements IGazeSelectable:

    • IsSelectionAvailable(): check if the holder is currently empty AND the Inventory has something that can be placed here.

    • OnSelectionComplete(): tell the Inventory to place its object in this holder.

    • also: void Store(Pickup pickup): takes the provided Pickup and handles transforming/parenting it as necessary to sit in the right place for this Holder.

  • Inventory component: a singleton that represents what the (local/VR) player is carrying. Has its own Holder (the hand) to store a carried pickup object. Other scripts can interact with it via...

    • bool CanPickUpObject(Pickup pickup): check if we have room in our hand to hold the item.

    • bool CanPlaceObject(Holder holder): check if we have an object that we can place into the given holder (you can build on this to make certain holders only accept certain objects, like locks & keys)

    • void Pickup(Pickup pickup): take the given pickup object and store it in our hand, and remove it from any previous Holder that held it.

    • void PlaceIn(Holder holder): place a carried object in the given holder, removing it from our hand/Inventory.

    Using this setup, we can later choose to expand our Inventory to a stack of objects, a set (from which we automatically select the best fit for a given interaction), or a menu the player can cycle through, without affecting any of the other scripts that communicate with the Inventory.

  • Gaze Selection component: handles checking when the gaze has entered a new object or left an old one (this script can implement some hysteresis so you have a little wiggle room and your selection doesn't flicker).

    The Gaze Selection component uses GetComponent<IGazeSelectable> to find any gaze-interactive scripts on the objects being looked at, and if IsSelectionAvailable() it can display the selection timer, firing the gazed-upon object's OnSelectionComplete() action when the timer finishes.

Now we have no concept of "The Ball" anywhere in the code. Each holder (including the Inventory's hand) knows what it's holding, the Gaze Selection component knows what it's looking at, and Pickup objects know when they're eligible for pickup.

\$\endgroup\$
  • \$\begingroup\$ This is really great stuff. I don't understand any of it, but I least I know now what to google! I really thought it would have been something a simple as just finding out the name of the object I was trying to pick up, but I realize that even if I did get it working, I'm still missing a lot of other stuff, like Inventory. As for those tutorials, the funny names actually help a lot to figure out what's syntax and what's not. Generics really confuse me. I will DM the author and forward this answer to him, maybe be can 'translate' it. Thanks again! \$\endgroup\$ – Haven Aug 5 '18 at 16:58
  • \$\begingroup\$ Haha, I wouldn't recommend doing that. Given my assessment of the tutorial series at the top, the author might find this unfriendly. If you have implementation questions, feel free to ask them here. For small stuff I can make clarifying edits, and for bigger stuff we can add more answers or you can post new questions. \$\endgroup\$ – DMGregory Aug 5 '18 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.