Grappling

For the grappling, I have two ideas as to how it can work, the player can either manually shoot the grapple where they would like onto different grappleable objects, or the game will target grappleable objects for the player which would make aiming the grapple much easier.


I would like the grapple to feature a pull which launches the player towards the target or slowly pulls them towards it as well as a swing which lets the player swing around the target.


To begin the grappling, I will attempt to create the automatic targeting to test which grappling targeting mechanic work the best.


I quickly found that there were no video tutorials on YouTube covering this automatic targeting so i had to rely on my own knowledge without any assistance to create this mechanic which led to me creating this code which produced these results:

This code is attached to the camera which is essential for the raycast to work as it relies on where the player is looking. If the raycast hits an object with the appropriate layer mask within the distance range, then the angle float is determined which will track how far the player can look away from the object before it should disappear. In the ShowUI function, the grappleUI is a prefabed game object that shows a recticle which indicates a target. This game object is then instantiated on the canvas relative to the in game position using WorldToScreenPoint. Once the player looks away from the target object, HideUI is called which sets the grappleUI to false and so it disappears. Below is the script in action.

Targeting 1 showcase.mp4

Pros:

Cons:

The targeting works exactly as intended but could be improved as its very simple. Setting the mechanic up properly would take too much time in making empty game objects all across the map for the grapple points. To fix both of these issues I would have to improve the system so the UI can slide across edges of an object. This would save time placing objects as I would have to place much less objects and the targeting would feel even smoother. This would be a great improvement as the player will be able to target the grappling points more specifically.

Reflection

Overall I think this system has a lot of potential and I am happy with the work I have done so far on it. Next time however, I think I would make sure to research some mechanics more in depth as I developed this mechanic with my own knowledge. I could possibly have found some more information that would've helped me understand the mechanic a little more and would have helped me develop it faster. Not researching impacted my time management as it took me a little longer than expected, this means that I need to speed up a little further on to get back on track.

Here is where I ran into a major issue, I looked in multiple sources but found no assistance or tutorials around how to build more advanced targeting and this is where just my knowledge ran out. I could not advance this system any further with my own knowledge and so I decided to try out a different system that doesn't use any automatic targeting to compare which is more fun and easy to use.


I have worked on grappling without targeting before and found a YouTube tutorial by "Dave / GameDevelopment" to help create a effective grappling system. Below is a variety of screenshots and annotations that explain how the code works and what each part of the code does:

Firstly I created the variables that can be changed in the inspector. 

The start function just accesses the Movement script for referencing functions contained in that script.


The Update function checks if the player has pressed the grappling button and then calls the StartGrapple function as well as checks if the current cool down timer is greater than 0. If so then the timer will decrease using Time.deltaTime.

In the LateUpdate function, the script checks if the player is currently grappling. If the player is grappling then the line renderer creates a line at the gun tip position and where the player shot the grapple and then connects these 2 points to create a line. LateUpdate is called just after update. This line renderer is constantly updated so even when the player is moving with a grapple, the line renderer is kept on both positions in order to look better.

This is the StartGrapple function which is called everytime the player presses the grapple button. If the grapple timer is not ready to grapple then return is used which cancels the function as the player cannot grapple if the timer isn't 0 or less. If the player is able to grapple then the grappling bool is set to true on both this script and the movement script. activeGrapple on the movement script controls a few movement functions which calls a return, this stops the player from moving and jumping while a grapple is active.


A RaycastHit is then used to shoot the grapple which is called hit. If the raycast hits an object with the correct layer and is within the appropriate distance then the position of the raycast is set to the grapplePoint vector3. The player is then frozen until ExecuteGrapple function is called which uses Invoke which calls a function after a certain amount of time which in this case is the grappleDelayTime variable. If the raycast fails to hit an object or the object isn't the correct layer, the grapplePoint is set to the maximum distance and draws a line there so it looks as though a grapple is still shot. The StopGrapple function is then called so the player is never launched towards the grapplePoint as the grapple has technically failed.


Finally the line renderer is enabled and position 1 is set to the grapple point. Position 0 is always set to the gunTip in the LateUpdate function so that does not need to change.

This is the ExecuteGrapple function which is called when the raycast from StartGrapple hits an object successfully. Firstly the player is now unfrozen and the script now calculates how much force the player needs to reach the end of the grapple.


lowestPoint takes the current position of the player minus 1 on the Y axis. This means if a grapple point is any lower than the Y axis, then the grapple will fail. GrapplePointRelativeYPos takes the grapplePoint.Y position and minuses the lowestPoint.Y position. HighestPointOnArc then takes the relative position and adds the overshootYAxis which determines how high the player will be launched. Then the JumpToPosition function is called in the movement scripts which puts the grapplePoint and HighestPointOnArc values in the function which is essential information for the grapple to work. 


After this, StopGrapple is called after 1 second and ResetRestrictions on the movement script is called after 0.2 seconds. This is so the player is free to move in the air after they have been launched.

This is the StopGrapple function which sets alot of variables back to what they should be before a grapple. The player is unfrozen again, this is there if ther player's grapple has failed. ActiveGrapple and grapple bools is set to false since the player is no longer grappling. The grapplingCdTimer is set back to its maximum time. The line renderer is now disabled and the position count is set to 0.

Here is the JumpToPosition and CalculateJumpVelocity functions which are the backbone of the grappling mechanic. These are located in the movement script.


 Firstly for the JumpToPosition to work, it requires a Vector3 and a float input which is received from the ExecuteGrapple function which is the grapplePoint and highestPointOfArc variables. In this script these are now called targetPosition and trajectoryHeight. Active grapple is now set to true which will restrict the players movements. Then VelocityToSet (a Vector3) is the result of calling CalculateJumpVelocity which requires a Vector3 which is called startPoint, another Vector3 called endpoint and another trajectoryHeight float. StartPoint refers to the players position before being launched and EndPoint refers the the grapplePoint/targetPosition. 


CalculateJumpVelocity workds by accessing Unity's current gravity. Then the script creates a new float called displacementY which is the result of endPoint.Y minused by StartPoint.Y. Then a new vector3 called dispacementXZ is created which is the result of endpoint.x - startPoint.x and the same for the z axis. 


Then a new Vector3 called VelocityY is created which is the result of Vector3.up multiplied by the square root of gravity and trajectory height. This actually calculates how much force is needed to reach the Y value of the target. The same calculation is made for the X and Z axis which gives a value for velocityXZ. The final calculation adds velocity Y and velocityXZ together and returns the final value.

The SetVelocity function is the final piece of the puzzle for grappling. The velocity of the rigidbody component on the player is set to the velocityToSet function which was recently set by the JumpToPosition and CalculateJumpVelocity functions. This velocity launches the player towards the target point. The trajectory of the launch can be changed via overshootYAxis and grappleSpeed. If grappleSpeed is higher than 1 then the player will go past the target due to higher speed. If OverShootYAxis is high then the player will be launched more upwards and gain a bigger height. These variables can be changed to preference or situations with more development.


Below are a few videos of me setting up the grappling as well as a few bug fixes and tweaking:

SettingUpGrappling.mp4
BugFixingGrappling.mp4

Overall this grappling works tremendously, all of the mechanics comes together nicely. The player is able to successfully pull towards any object as of now as every object is under the "grappleable" layer. This is a fix I will need to do as it is a restriction that is needed for balancing. The swing works pretty well, I think that it can be exploited as of now and could need some bug fixing. Right now, the distance to swing and pull is unlimited, this was for testing purposes and will need adjusting. The exploit is when the player uses the swing in the air, they can immediately let go and double jump straight after. This can be used infinitely and needs to be fixed as this is a major exploit that is almost game breaking as with this, the player can stay in the air as long as they like or start ascending.


Some issues I came across while developing this was issues with the grappling either launching the player extremely high or not launching the player at all. These issues were caused by multiple variables attached to the player such as the players mass, the grappling speed and the overshootY value. I managed to fix this after some time wondering why it was happening by tweaking these values. At first it was something I didn't notice was off and wasted a bit of time looking throughout my code for the issue. The fix was actually an easy fix but was something I didn't notice at first which costed time. This fix was good as the grappling is now much more consistent, the player sometimes doesn't quite make it to the target byt the double jumping can resolve this issue. If the grappling goes further though, the player will likely overshoot the grapple more often and this wouldn't be great gameplay wise. This also impacted my time plan as I didn't expect to spend such a large amount of time looking for a small issue. To improve in the future, I will double check the variables when I have a similar issue and be sure to allocate time to tweaking and bug fixing so my time isn't lost if I get stuck on an issue.