top of page

Lightning!! (Week 6, Sprint 3)

  • Writer: Joses Kang
    Joses Kang
  • May 27, 2021
  • 4 min read

Hi everyone! Today I'd like to show you how I did the physics implementation for the Elemental Lord's lightning bolts.


While designing this ability's mechanics, a few issues came to mind:

  1. How can we ensure a perfect lightning grab every time?

  2. What happens if the player lets go of the lightning bolt?

  3. How will the lightning bolt look if it is thrown with its forward tip not facing the direction of motion?

I deliberated over this for a few weeks, but I've managed to come up with some solutions. Here's what I've got!


Lightning Cloud


Let's begin with the first issue, handling the location and spawning of dormant lightning bolts. I first created a script for a Lightning Cloud with these variables.


After that, I created a function to handle the perfect lightning grabs. This just means that the player will always be able to grab an available dormant lightning bolt from the cloud.


In order to achieve this, I tracked the highest hand (left or right) of the VR Player and forced the available lightning bolt to have the same x and z coordinates as that hand, whilst preserving the y-coords to maintain height.


As long as the VR Player's hand is in the cloud, they'll always grab an available dormant lightning bolt.


Here you can see that I'll only run the code every frame if there is a dormant lightning bolt and if its isDormant variable is true (more on that in a while).



Lightning Bolt


Now, let's look at the code for the lightning bolt.


Here you can see the variables that I declared and a function called IsHoldingFunc(). This function is a simple toggle that I added as a Select event for the Lightning Bolt's XR Grab Interactable component. It tells me if I'm holding the bolt or not. You can also see the DisableDormant() function here which sets the isDormant variable to false. This function is called via a Select event as well.


You can also see that I set my oldPos variable to my current bolt position and I ran DisableDormant. Let's see what these are used for below!



This function, ThrowLightning, handles how we throw the lightning. Now you see, I wanted to solve Issue 2 as stated above. It was quite simple really. If the lightning bolt is currently being held, has not been thrown and its current velocity is higher than the threshold stated, we'll mark it as ready to be thrown the next frame.


If in the next frame we see that the bolt is no longer being held, has not been thrown and we marked it in the previous frame, we start some code to let it fly via a coroutine called ForceRotation (more on that in a while)!


The rest of the function just handles returning the bolt to dormancy so that it returns to the cloud and saving the current position for comparison in the next frame.


Now, let's look at that ForceRotation() coroutine.


To solve Issue 3, we'll simply force the bolt to always face the direction in which it is thrown. We start off by tracking the position of the bolt at two points in time. After which, we set the angularVelocity of the bolt to Vector3.zero so that it won't spin incessantly.


We'll be rotating the bolt to face the right way in two parts. Starting with the y-axis rotation, we generate a direction to look at with no y-difference and force the lightning bolt to angle itself that way.


Let's address a small problem here. We want the VR Player to always hold the Lightning Bolt this way, with the big red tip facing downwards. This forces us to make this the upright position of the bolt.


In order to use Quaternion.LookRotation() to fit our needs, I simply set Vector3.up to be the local front-face (as represented by

the side with the red bar) and the

direction we determined earlier to be

the top-face.



All that's left to do is the incline along the x-axis. We can solve for the rotation via basic trigonometry. By comparing the heightDiff (opposite side) and the distTravelled (hypotenuse), we're able to solve for α via the inverse sin of heightDiff divided by distTravelled.


The other parts of that calculation are purely for converting the answer from Radians to Degrees and rounding it to 2 decimal places. As the trigonometry option is invalid in the (unlikely) event that there is no x or z-difference but only y-difference, we run an if/else statement to check if the y-difference is positive or negative and rotate the bolt accordingly.


Now, all that's left to do is send the bolt flying with a velocity change-type force in the new direction.


Of course, we've got to make sure that we actually run all of this. We'll call the ThrowLightning() function every FixedUpdate() so that we have accurate physics calculations.



Without further ado, let's take a look at what the end result looks like!

So I got all three of the issues down pat, I'd say I did a good job! Give yourself a pat on the back Joses! *pats self on back*


This issue was a major halter of progress so I'm expecting VR development to go a lot smoother now, here's to hoping!


Comments


logo_text.png

    ©2021  Golden Monkey Studios

    bottom of page