In the previous tutorial, I covered how to make a VR Bow that we could grab and also pull back on with the String. Now that we have the Bow working, we need to get it to launch some arrows.
If you haven’t gone over part 1, you can find it here.
SPAWNING ARROWS
Jumping back into our project, let’s kick things off by adding an arrow spawner to our bow.
While still having the Bow selected, let’s add a new script to it and call it Arrow Spawner. Below is a picture of the code I’ve come up with.
First we’re importing the XR Interaction Toolkit at the top. We then use two public Game Objects to store the Arrow prefab and the Notch on our bow, which is where we want our arrows to spawn. We’re going to also store the XR Grab Interactable for the bow to see when it’s selected, a bool to check if there is currently an arrow notched and another Game Object to store the current arrow that is notched.
Start – We grab the XRGrabInteractable reference as well as subscribe to an event from a Script we’ll be using later. For the ArrowSpawner script, we only need to know that we’re subscribing to the Pull Interaction script releasing. This is essentially us releasing the bow after pulling back the string.
OnDestroy – Just unsubscribes from the event, which will prevent unwanted bugs.
Update – We check if the bow is selected and if there isn’t a current arrow notched. If those are both true, then it will call the DelayedSpawn function. If the bow isn’t selected, then it will destroy the current arrow that is notched.
NotchEmpty – Will be called one the PullActionReleased even is triggered and simply sets the _arrowNotched bool to false.
DelayedSpawn – This will spawn a arrow after waiting a second.
Now that we’re spawning Arrows, we should probably make sure that our Arrow will actually function correctly.
To finish connecting this script, we need to go to the editor and make sure we fill in empty variables associated with it. That would be dragging our Arrow Prefab and Notch in to their respective slots on the script.
MAKING AN ARROW
To make the arrow, we need to hop over to our prefabs folder found in the Bow and Arrow tutorial folder. There we should be able to find a Arrow prefab that will need a script before it starts working properly.
With the Arrow prefab selected, we’re going to add a script to it and call it Arrow.
Let’s run through this code, line by line.
- The beginning imports all the standard libraries that we’ll need for this script. It also inherits from Unity’s base class, MonoBehaviour.
- The two public variables both store the speed and location of the tip of the arrow to be used in later calculations.
- The private variables store the rigidbody, a bool to determine if the arrow is in the air and the last position, which will be used to store the last position of the tip.
- Awake() – The method retrieves the rigidbody of the arrow, it subscribes to the PullActionReleased event and also calls the Stop method, which will prevent our arrow from flying off and having physics interactions.
- OnDestroy() – This method unsubscribes from the PullActionReleased method to prevent bugs and unwanted behavior.
- Release() – This method will be called once the PullActionReleased event has triggered. It begins to unsubscribe from the PullActionReleased event to prevent it from being called again in the future. It will also decouple from the Notch as its parent. It then activates all the components necessary for flight by setting _inAir to true, physics to true, and the rotate RotateWithVelocity method. It will also apply an initial force based on the value passed in by the PullActionReleased event.
- RotateWithVelocity() – This coroutine will constantly check for the velocity of the arrow in order to update its rotation. It begins by waiting for the next FixedUpdate, which will give the arrow a more accurate physics based rotation by synchronizing it to the physics engine’s update interval. It will then use LookRotation to align the forward vector with the velocity vector and the up vector with the transform’s up direction. It will then Update this every frame.
- FixedUpdate() – This is used for our physics calculations and is where all physics calculations should take place. If the arrow is in the air, it will check for collisions and update the last position of the arrow’s tip.
- CheckCollision() – This method will check for collisions with our arrow and will stop all physics once it has run into something. It starts by checking for a collision between the last position of the tip with the current position of the tip using Linecast. If a collision is detected, it will make sure it isn’t with something from Layer 8, which is our Body. If it isn’t on Layer 8, it will then turn off the interpolation of the arrow, set the parent of the arrow to what it collided with and apply an impulse force to the object it collided with. Finally, it calls the Stop() function, which will stop all physics interactions.
- Stop() – This will stop physics interactions and set _inAir to false.
- SetPhysics() – This set Physics to on or off based on what bool is passed in. It will do this by setting gravity to whatever is passed in and isKinematic to the opposite.
UPDATE TO CODE
I’ve removed FixedUpdate and CheckCollision. Since OnCollisionEnter is already called when the arrow collides with objects, we can just use this instead of manually checking for collisions using line cast.
Finally, we just need to go into the editor and set the Tip gameobject to the empty slot on the Script.
That’s it for our Arrow! Now we need to set some things in the editor before we can test it out.
Layering Our Arrow
To prevent unwanted behaviors’, we need to set our arrow to it’s own layer and then adjust the physics settings.
- Select the Arrow Prefab
- Add Layer and call it ‘Arrow’
- Set the Arrow Prefab to the Arrow Layer
- Edit -> Project Settings -> Physics
- Uncheck the Arrow boxes for Arrow and Body
Testing out The Arrow
Booting things up, we should now be able to grab the bow, pull back the string and fire an arrow!
On the next tutorial, we’ll be wrapping up the bow and arrow with some optimizations and polish ideas to make the VR bow and arrow even better.