In this article we explore the design choices for different weapons in Tribocalypse VR. We discuss the relation of weapons in regular PC games to weapons in VR games. Again we use immersion and clarity to analyze the different design choices.
Items that the player can pick up in TVR are spears, bombs, the bow and the shield. First three are offensive items, while the shield is the only defensive item in the game. To pick up any of the items, the player has to place their character’s hand (using the Vive controller) on the item and press the trigger button on the Vive controller.
Item handling system was designed to be ambidextrous. This means that players can pick up items with either hand. Another way to solve this, as some other games do, is to let the players choose their dominant hand. They can do it when the game starts and when needed, change it later in the settings menu. This often results in two handed weapons (such as the bow) being placed in the player’s dominant hand, regardless which controller (left or right) the player uses to pick up the item. This kind of solution however reduces immersion. It feels more natural to be able to pick up the weapon with the hand the player has currently placed on the weapon. If the player feels like the weapon is in the wrong hand, the player can simply drop the weapon and pick it up with the other hand. A better solution for switching the weapon, would be to make the player able to simply take the weapon from the other hand, without having to drop it first. This solution should increase both the immersiveness and clarity. It is more natural, in real world, to pick the item from the other hand, without having to drop the item first.
All of the items have an attached rigidbody component. A rigidbody component makes any object in the game to be able to be subject to the physical forces acting in the environment such as gravity and collisions with other items. If an object in TVR is picked up, its own collider is disabled and each frame, the object sets its position to be equal to the weapon specific animation bone, located in the hand’s hierarchy. Also, an invisible “follower” object is created. This invisible object has a collider and a rigidbody and also smoothly lerps to the picked up item’s position. The purpose of the follower object is to make the held item interact physically with other smaller items when they collide. For example, this gives the player an ability to swipe items that are laying on the ground, such as bows and shields. This small detail adds immersion the game.
The reason to not simply use the picked up item’s collider is because collisions between rigidbodies in Unity works best if these rigidbodies are moved through physical functions. If the transform of a rigidbody is directly modified, then the collision calculations do not give expected results. This is because when manipulating the rigidbody’s position only directly through the transform component, the rigidbody’s internal velocity variable is a zero vector. If the collision happens however and the velocity is a zero vector, then the collision would be handled as if the collision happened with a static object. The problem however is that the player swings the object. To the player the object looks as if it is in motion. To the physics engine, since only the transform is modified, the object remains static. Through direct modification of the transform component the physics engine sees as if the object is simply placed or teleported to a different location. Now, when the player swings at object P, two outcomes are possible:
1) The player swings too fast and at frame n, the swingable object has not yet collided with P. If the player is very fast and the object that the player tries to hit is small, then at frame n+1 it is possible that the position of the swingable object has already gone past object P. No collision happens and it looks as if the swingable object simply went through object P.
2) At frame n, object P-s collision box and the swingable object’s collisions boxes overlap. Collision happens. However, to the physics engine in Unity, it seems as if the swingable object’s collider simply appeared in the object P’s collider. To solve this collision, the physics engine tries to push both items away from each other, often resulting in undesired force vectors. For example, the object P could fly in the opposite direction of the swing motion, due to physics engine detecting collision too late.
To fix this problem, a solution using the follower object was used. The follower object has a collider identical to that of the picked up item’s collider. The following function uses physics to smoothly follow the object. This means that collisions work correctly because the follower object’s rigidbody has a velocity greater than zero when moving, resulting in correctly handled collisions. The only downside to this is that the collision is slightly delayed compared to the visuals of the picked up object. Thus, for a very short amount of time, the swinged object could be seen overlapping with an object it should collide with. However, this amount of time is negligible to have any impact on immersion and clarity of the game.
Another option to solve the collision problem would be not to use the follower object and use the picked up object’s own collider. And instead of directly modifying its transform the object could be made to lerp to the player’s hand using the same function as the follower object does for lerping. This solution proved to break immersion as the following of the object was too slow and it felt more like that object “swam” to the player’s hand, rather than being a static object, held by the player. The faster the players moved their hands, the more evident the problem became.
If this solution was to be used, then the following improvement could be made to the technique: Add the weight of the carried item to the lerping formula. For example, items with heavier weight, follow the hands slower than items with smaller weight.
Another solution for adding artificial weight to the objects is to make the player lift up heavier items slower, and lighter items faster. This means if the player tries to pick up an item, a link is created between the player’s hand and the pickable item. This link makes the item move towards the hand. The heavier the item, the slower it moves. If the distance between the item and hand becomes too large, the link is broken and the item falls to the ground.
All items that can be picked up by the player, can also be thrown. This can be achieved by first picking up the item with the trigger button and then releasing the trigger button to throw the item. The faster the player moves an arm in real life (the faster the Vive controller moves), the further the item in the game is thrown. It was necessary to get the throwing mechanic feel right. It had to feel as close to throwing items in real world as possible. Throwing an item in real world consists of these elements:
- feeling the item in one’s hand
- feeling the weight of the item
- motion/trajectory and the speed of the hand
- the act of throwing the item (releasing).
The feel of having something in one’s hand is already accomplished by having the player hold the remote. Luckily, the shape of the Vive controllers is good enough to give an expression to the player that whatever they are holding in TVR, is also held in real life. It also does not seem to matter whether it is an item with a handle, such as the spear or shield or a round object such as the bomb.
Unfortunately, the weight that the player feels, is limited to the weight of the controller plus anything else attached to the controller. It is possible to tell the player to attach something to the controller in order to make the weight of a certain item in game feel more realistic. However, if this has to be done very often, adding and removing weight from the controllers breaks the immersion heavily, as it brings the player out of the game too often. This kind of approach might work if an extra weight has to be added only when starting the game. Some people have even suggested to add weights in the form of bracelets and hand gloves. By not being able to modify the weight of the controller automatically through the game somehow, it was necessary to use other techniques to make the throwing feel as natural as possible.
When throwing an item in TVR, the velocity of the controller is multiplied by a force multiplier (hard coded float value). This velocity is then added to the throwable item’s rigidbody. Modifying the force multiplier gave us the ability to fine-tune the throwing mechanic to feel as real as possible. All of the items in TVR used the same formula. This means, their in-game weight was not included in the calculations:
𝑖𝑡𝑒𝑚𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦 = 𝑓𝑜𝑟𝑐𝑒𝑀𝑢𝑙𝑡𝑖𝑝𝑙𝑖𝑒𝑟 ∙ 𝑐𝑜𝑛𝑡𝑟𝑜𝑙𝑙𝑒𝑟𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦 𝑖𝑡𝑒𝑚𝐴𝑛𝑔𝑢𝑙𝑎𝑟𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦 = 𝑓𝑜𝑟𝑐𝑒𝑀𝑢𝑙𝑡𝑖𝑝𝑙𝑖𝑒𝑟 ∙ 𝑐𝑜𝑛𝑡𝑟𝑜𝑙𝑙𝑒𝑟𝐴𝑛𝑔𝑢𝑙𝑎𝑟𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦
However, the used solution has a drawback. Regardless how big the item in the game is or how heavy it looks, the throwing force is only affected by the motion and speed of the Vive controller. For example, throwing the small bomb with force N and throwing the big shield with force N, without any obstacles in the way, both of these objects would land at the same location. This is clearly immersion breaking, since the lightweight bomb should fly much further than the heavier and more air resistant shield. In order to overcome this problem, the weight of the throwable items could be added to the formula. This means that items with different weights when thrown, in a same way (using the same motion and speed of the hand), would land at different locations. An improved formula would be:
𝑖𝑡𝑒𝑚𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦 = 𝑓𝑜𝑟𝑐𝑒𝑀𝑢𝑙𝑡𝑖𝑝𝑙𝑖𝑒𝑟 ∙ 𝒊𝒕𝒆𝒎𝑴𝒂𝒔𝒔 ∙ 𝑐𝑜𝑛𝑡𝑟𝑜𝑙𝑙𝑒𝑟𝑉𝑒𝑙𝑜𝑐𝑖𝑡𝑦
In TVR the main goal was to design the weapons in a way that each weapon would be more efficient in certain situations than other weapons. This means that the players have to use weapons strategically. That would add more variety to player’s actions and thus more content to the game.
An improvement of this would be to add weapons, which are effective in the same situation and only that situation. For an example: Weapons A and B are effective in situation 1, weapons C and D are effective in situation 2. Whenever the player encounters situation 2, he will most likely choose between weapons C and D. This gives the player 2 options for each of the situations. However, if the player only had weapon A for situation 1 and C for situation 2, then the variety of weapons would only come into play when the situations change. However, having 2 weapons for each situation, the variety of weapons could be maintained even if the situations do not change.
In VR this design thought could be improved even further. While in PC games only a mouse button is used for firing a weapon, in VR the whole hand movement could be considered. This is especially useful for weapons, which do not have a trigger in real life, e.g. melee weapons, throwable weapons, bows etc. Those can be immersively emulated in a VR environment requiring the user to mimic the real life actions for use of the weapons.
This also gives the VR developer a chance to produce a small amount of situations but many different weapons, which are effective for those situations and still make the player feel as if there is a lot of variety in weapon strategies. It should be noted that if many weapons are used for only a single situation, then these weapons should have no clear advantage over one another. The bow and spear in TVR are a good example of this design choice. They both do the same amount of damage, have a very similar attack rate and when used against enemies, are both very accurate. However, the hand movements for using them are completely different. While the spear requires the player to make a throwing motion, the bow requires the player to make a pulling motion with their hands. The variety has to come from using these weapons differently, rather than just having different weapon visuals.
Single Target versus Area of Effect Damage
Even after making the action of throwing feel as natural as possible, there was still the problem of throwing items accurately. This is not a problem when throwing items, which have no effect on the enemies, such as the bow and the shield. These kind of items are not meant to be thrown at specific targets. It becomes a problem when designing a weapon that is meant to kill the enemy by throwing the weapon at him. The first throwable weapon designed was an axe. The idea was to create a weapon that could be thrown very fast in a rapid succession with each hand. It was very difficult to throw the axe accurately even after we made the “weight” of the axe feel right. Even after a lot of practice, the thrown axes would fly a little bit to the left, right or over the opponent’s head. This problem was also amplified by the fact that the axe was very small and the enemies were always quite a distance away from the player. However, since we still wanted to implement a throwable weapon, we came up with the idea of creating an area of effect damage weapon.
The bomb is an explosive item that could be thrown. On impact the bomb detonates, dealing damage to every enemy within its explosion radius of 7 in-game units (7 meters). This way, the bomb does not have to directly hit the enemy, giving the player room for mistake. This reduces irritation caused by inaccurate throws not hitting a single enemy.
The idea was to make the bomb extremely efficient against groups of enemies while being useless against flying enemies. Due to the long usage cooldown of 30 seconds, the bombs have to be used sparingly. It is wise, in most cases, to bombard groups of enemies. Similarly it would be unwise to use a single bomb or even more on a few number of enemies. We tried reducing their cool down time to nearly 0 seconds to make them usable the whole time, however they simply became too powerful and reduced the challenge of the game.
Later in the design process, we came back to the idea of having a single target throwable weapon. Thanks to our earlier experience we were already aware of the inaccuracy problems, present in the virtual reality environment when throwing items.
When designing the spear (see image on the right), we had two goals in mind. Firstly, we wanted to create a single target throwable weapon, similar to the axe described earlier. Secondly, we wanted to give the player an alternative main weapon (like the bow). This means that the player could either use the hold and pull mechanic to kill most of the enemies (the bow) or use throwing as the main mechanic. Since bombs have a usage cool down and are not usable through the whole match, they cannot be the main weapon. The main problem with designing the spear was making it accurate.
First, we tried the same method as with throwing the axe: adding no aim assist and hoping that since the spear was bigger than the axe, the aiming would become a simpler task. To try this design, we rotated the spear in different ways on the hand, trying to get the best orientation. Orienting the spear in a way that it was perpendicular to the controller, resulted in most of the spears being thrown to the ground. Since the hand motion of the player starts from the back of the head and ends near the waist, the spears were often released too late in the motion of throwing. This resulted in the spears being driven straight to the ground. After that we tried to rotate the spear parallel to the controller. This meant that the player was forced to throw the spear as they would in real life. Bringing their hand to the back of their head and quickly leaning forward when throwing the spear. While this solution was better than the previous one, it still lacked accuracy on the horizontal axis and was also too demanding on endurance and stamina. Since we wanted to appeal not only to sporty players, this was not a suitable solution.
Third option was to make the player aim with their head. This means that the spear always flew where the player was looking at. This way, the spear inherits only its speed from the controller but not the direction. While this solution was accurate when correctly used, it did not feel natural. Players would often tilt their head towards the ground when throwing the spear, making the spear fly straight to the ground, similarly to the first solution. Often they would also look in a completely different direction compared to the direction of their hand movement. Since this solution had very little clarity it was also discarded.
Rotating The Spear in Player’s Hand
We decided to implement automatic rotation of the spear in the player’s hand. The spear’s orientation was perpendicular to the controller, pointing away from the player. When the spear is below the player’s head, the tip of the spear is pointed in the same direction as the Vive controller. When the spear is above the player’s head, it is turned around 180 degrees.
The purpose is to rotate the tip of the spear in the direction where it will be thrown. Usually in real life, this kind of 180-degree rotation is done manually by the person holding the spear. In VR the designer should not expect the player to rotate their controller in real life, to get the correct orientation for the spear. Given solution reduces immersion because an item, which is in the player’s hand is moved independent of the movement of player’s hand. However, it adds clarity, by making the act of holding and rotating the spear as effortless as possible.
After adding automated rotation to the spear when held, the act of holding and aiming the spear was easier for the player. This means that throwing the spear in the direction of the enemies was not a problem anymore. It was still difficult to hit the enemies. The players quickly discarded the spear as a weapon because similarly to the axe, it was still too inefficient due to the lack of accuracy.
To make the spear accurate, we decided to implement aim assist. It was designed to work in a way that allows for greater aiming error. In that sense, the spear would work similar to the bomb, giving room for mistakes. The aim assist system consists of two parts: detecting the enemy and flying towards the enemy.
For detection, a capsule cast is used: a collider with the shape of a capsule is placed at the tip of the spear. This capsule has a length of 300 and a radius of 2 in-game units. If any enemies collide with the capsule collider, then the spear starts moving towards the closest enemy. The spear even detects enemies behind obstacles, such as walls or the terrain. In order to avoid this and detect enemies only visible to the spear, an additional ray cast could be made from the tip of the spear to the enemy. If nothing obstructs the ray, then an enemy is visible to the spear.
If the enemy is detected, then he will be set as the target of the spear. From this point onward the spear’s velocity remains a constant (equal to velocity at the moment of detection). This will remain true as long as the spear either hits something or the target enemy is killed. In each following frame the spear is given a new rotation so that it would reach its target. If new rotation cannot be calculated, then the spear retains its rotation.
In this context
rb references the rigidbody component of the spear. First, a direction vector from the spear to the target is found.
Vector3 dir = target.transform.position - rb.transform.position;
If the magnitude of vector dir is greater than 2 and if the absolute angle between the dir and
rb.velocity vectors is less than 90 degrees (the dot product between these vectors is greater than 0) then the calculation continues. Otherwise, if the spear is closer than 2 units, no further calculation is required because the spear will most likely reach the target. If the dot product is equal to or less than 0 then the target is considered to be located behind the spear and thus ignored.
In order to rotate the spear, the necessary Euler angles of the new orientation must be calculated. The found Euler angles will be
z representing the rotation in the corresponding axes. Since Unity uses a left-handed coordinate system, the
x represents the pitch axis (tilting forward and backward), the
y represents the yaw axis (turning left and right), and the
z represents the roll axis (tilting side to side). The
z angles can be calculated by converting the
dir vector to a quaternion and then extracting the Euler angles from that quaternion.
Vector3 euler = Quaternion.LookRotation(dir).eulerAngles;
float y = euler.y; float z = euler.z;
This is sufficient to rotate the spear in the target’s direction on a 𝑦𝑧-plane (see the diagram below).
Next step is to calculate the x angle that is required to launch the spear at from its current position. The following formula will result in the necessary angle:
Where 𝑣 is initial launch speed, 𝑔 is the gravitational constant, 𝑥 is target’s distance (height is not taken into consideration) and 𝑦 is height difference between two points. In TVR’s case 𝑣 is spear’s rigidbody’s velocity (constant), 𝑔 is -9.8 units per second squared (default in Unity), 𝑥 is the distance between the target and the spear (without calculating the height) and 𝑦 is the height difference between the target and the spear.
float distance = (new Vector3(targetPos.x, 0, targetPos.z) – new Vector3(rbPos.x, 0, rbPos.z)).magnitude;
float height = targetPos.y – rbPos.Y;
In the calculation of 𝜃 only the root prefixed by the minus sign is used. If the root is imaginary, then no such angle can be found that the spear would reach its destination. Increasing the velocity of the spear enough would fix this problem. However, in TVR a constant speed was preferred. If the angle 𝜃 exists, then all necessary Euler angles for rotating the spear are can be found and a new rotation quaternion can be created. Angle x will be equal to 𝜃.
Quaternion newRot = Quaternion.Euler(x, y, z);
However, the spear’s rotation is not immediately set to be equal to this quaternion. Instead, spherical linear interpolation (slerp) is used to smoothly rotate the spear towards the new rotation. A coefficient (float from 0 to 1), which is dependent on the
dir vector’s magnitude, is calculated. This is used to set the speed of slerp. The closer the spear is to its target, the faster the orientation is changed.
float coef = Mathf.Clamp(Time.deltaTime * (4.0f - 4.0f / dir.magnitude), 0.0f, 1.0f);
Finally, the spear’s rotation is set based on previous calculations,
rb.transform.rotation = Quaternion.Slerp(rb.transform.rotation, Quaternion.Euler(-x, y, euler.z), coef);
and the spear rigidbody velocity’s direction is changed to make the spear fly forward in the new orientation.
rb.velocity = rb.velocity.magnitude * rb.transform.forward;
The aim assist, described above, greatly increased the accuracy of throwing the spears. Thanks to this, the spear can now be considered to be on par with the bow. It has same damage, similar fire rate and most importantly, very similar accuracy statistics. This means that the spear and the bow could be used in similar situations, while neither necessarily overpowers the other by being more effective. The property that differentiates these weapons is the way they are used. Thus adding more variety to the game. The player has an option to either use the hold and pull mechanic or the throwing mechanic, as their primary mechanic to deal with the enemies.
The bow is the only weapon in TVR that requires 2 hands to use. It is a very accurate weapon in the game that launches arrows as projectiles. The player has to hold the wooden part of the bow with one hand and pull the bowstring with the other one.
Beside the spear, the bow is the second main weapon in the game. It is accurate, has quite a high fire rate and moderate damage. Initially it was considered to be the main weapon of the game. However, after implementing spear’s aim assist, the bow is now on par with the spear. Though testing shows that players still prefer using the bow instead of the spear. This might be due to the reason that it is much easier to hit the menu buttons on the tree, as the bow is much more accurate when trying to hit a certain point. The spear only becomes as accurate as the bow when the targets are actual enemies.
The bow is a feature that was the longest in development during the whole development cycle of TVR. The development of the bow started at the beginning of the project and was not totally finished even at the end of the project. The bow became functional in a month, however continuous testing, modification and bug fixing was required. The main problem was the inaccuracy of the bow. Many testers pointed out the same problem: “The bow doesn’t feel very accurate. The arrow does not fly to where I point the tip of the arrow at”. There were exceptions, of course, however the majority had problems with aiming.
When the bow is held but the bowstring is not pulled then the bow works as if any other picked up object: its position and rotation are equal to that of the holding hand and it has an invisible follower item. However, if the bowstring is pulled with the other hand, the bow’s orientation will be dependent on both hands. The bow’s forward vector is set to be equal to the following subtraction: the position of the hand holding the bow minus the pulling hand’s position.
Vector3 start = pullingHandPosition;
Vector3 end = bow.hand.position;
Vector3 direction = end – start;
Vector3 axisToRotateAround = bow.hand.forward;
bow.transform.rotation = Quaternion.LookRotation(dir, axisToRotateAround);
The position of the bowstring’s middle part will thus be at the fingertips of the visual hand seen in the game. This kind of rotation means that the player could easily rotate the bow in any direction with only the pulling hand. For example, if from the player’s view, the pulling hand is placed in front of the bow holding hand, the player would be aiming at himself.
This solution causes problems with accurate aiming. If in real life a person were to hold the bow in front of him and tried to rotate the bow with only the pulling hand (using the string) then the bow would not rotate freely in the holding hand. Rotating by the string in real life would also cause the holding hand to rotate. In TVR the holding hand rotates, however the real hand remains stationary.
This can be problematic when the player in TVR tries to aim with the bow. If in real life a person correctly brings the middle part of the bowstring near the chin, the bow itself is rotated in the same direction as the person’s bow holding hand.
This results in accurate aiming in real life, but is not represented in that way in TVR. In addition, since in VR the tip of the controller (representing the middle part of the bowstring’s location) cannot be brought next to the chin without struggle (due to obstruction of the headset), another problem is encountered. The small distance between the tip of the controller and the person’s chin adds a small angle on the horizontal axis of the bow, causing arrows to fly in a wrong direction. The arrows fly correctly where they are aimed at in relation to the bow. However, the players do not seem to notice the origin of that error.
We tried to solve this by offsetting the pulling hand’s position in the code in a way that if the player pulls the controller near the headset (usually to the side of it), then in the game the pulling hand would be moved a bit closer to player’s head position (near the middle of the headset).
This means that the controller’s position and rotation no longer match the exact position and rotation of the in-game hand (see the image below). This was not a problem since the majority of the time when the string was pulled, players did not look at their hand. The mismatch was not visible for them, thus not reducing immersion of the game. If the players did look at the hand out of curiosity, then they would see their hand rotated and positioned incorrectly.
This kind of solution worked only for a small number of players. The majority still had problems with aiming the arrow. This was due to the fact that each person does draw the string a little bit differently than others do. Some bring the controller to the side of the mask, some bring it in front of the mask. Some a little bit below and so on. This kind of action was caused due to the fact that people simply cannot aim with the bow due to lack of experience in real life. They concentrate their view on the tip of the arrow and predict that the arrow will fly in the pointed direction. However, since time became a problem for us, this problem was not solved completely.
There are alternative ways to let the player aim the bow slightly. One of them, used in the VR bow game QuiVr, is to let the player adjust the hand’s offset in the game’s menu settings. The benefit of this is that each player can set up the bow’s rotation in a way that is suitable for them and thus allowing them to be accurate with the bow. The downside to this is that the player has to do manual adjustment, which can be time consuming due to trial and error method of testing the offset.
Another solution would be to launch the arrow from the tip of the drawn arrow with the rotation equal to player’s camera’s forward direction. This should ensure that the arrow always flies to where the player is aiming the arrow, at least on the horizontal axis. The downside to this is that it requires extra checks for situations where the player is not aiming down the sights. It should be decided then if the arrow should fly where the drawn arrow is aiming at or should its rotation still be equal to the forward vector of player camera’s rotation. This solution was not tested, but it would seem that the solution would sacrifice immersion for clarity.
Player Fatigue Reduction
Over long periods of time, both the bow and spear/bombs seem to be equally tiring to the player in terms of stamina. However, because the hand motions required for using these weapons are different (eg javelin throw and archery), players can easily switch from the spear/bombs to the bow if the act of throwing starts to become too cumbersome. The muscles that were used to perform the act of throwing are not used as heavily when holding the bow and pulling the string. This means that these muscles which are used for holding and pulling are not as tired as the ones used for throwing. This opportunity of having the player to switch between weapons and relax certain muscles, increases the overall play duration, which would be otherwise shortened by fatigue.
Another technique used in TVR that reduces fatigue of the player is that the players can rest as long as they like between each match. The player could even save their progress, return to the game after a week and continue where they left. The downside to this is that some challenge is taken away from the experience. The player is given time to rest, thus making the next wave less challenging compared to having no rest or very little rest between the waves.
This concludes the design choices about different items and weapons in the Tribocalypse VR game. Now we have covered main areas of VR game development. We started with environment and level design, continued with graphical user interface design and now discussed the items and their mechanics. See also the last part of this article series: The Conclusion.