Currently I am working on a game for people with accessibility restrictions. I am having the issue of locking the player model in a sitting position. If the user does not center themselves in the room the player model will be pulled to a certain direction. I would like to lock the player model in a seat and only allow for arm movements and head rotations, no leaning or moving in the game using the HMD.
Since I am using the Final VR IK asset I have tried using their demo for sitting position in VR and cannot get the player to stay seated naturally. I am not sure how to program this or set restrictions to be able to do this.
Edit: To simplify my question. How do you lock the oculus rift HMD to only allow for rotation and not position tracking.
I figured it out how to lock the HMD into to only allow for rotation and not position tracking. To add a sitting position just use an body animation that's sitting. There are 2 things I did. First I added a line of code to the OVRCameraRig script:
trackingSpace.localPosition = -1 * centerEyeAnchor.localPosition;
This was done right before the RaiseUpdatedAnchorsEvent(); call around line 260 in the UpdateAnchors() method. What this does is it locks the head position and only allows for head rotation.
The second thing I did was write a head relocation script based on #derHugo answer to one of my other questions. What this does is when the space bar is pressed it will move the entire OVRCameraRig position. There must be a parent on OVRCameraRig for this to work In the screen shot below you can see the CameraParent object as the parent. I used a sphere as the relocation object that was placed in the middle of the head of my player model. The reason I had to add this was sometimes when you hit play the player would start at a weird position depending on where the headset was at the beginning. In the screen shot you can see use position tracking as not being checked in the inspector, that is an error. Please keep it selected to prevent screen tearing in the headset
Here is the code for the changing position of player when in game:
public class VRPositionChange : MonoBehaviour
{
public Transform resetPos;
private Transform parent;
private void Awake()
{
// create a new object and make it parent of this object
parent = gameObject.GetComponentInParent<Transform>();
}
// Update is called once per frame
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// reset parent objects position
parent.position = resetPos.position;
}
}
}
Related
I recently started having a look at game development with Unity and was trying to make a simple 2D character with basic movement abilities. This character is supposed to jump and move from side to side, but only if it is standing on something.
Now my question is: How do you check if a player is standing on something? / Get the distance to the next game object / collider beneath the player game object?
Would greatly apreciate any helpful answers and especially explanations on how exactly it works. Thanks!
To do this, you need to send a ray to detect the point of impact on the ground and then calculate the distance. The code below sends a ray from the center of your object down to the maximum height (3) and gives the size.
public LayerMask groundLayer;
public float maxRayLength = 3;
public void Update()
{
var hit = Physics2D.Raycast(transform.position, Vector3.down, maxRayLength, groundLayer.value);
if (hit) Debug.Log(hit.distance); // it will print current distance from pivot
}
If you want to calculate the height of the ray from the character's foot, there are two methods, one is subtracting half the height of the character from it.
Physics2D.Raycast(transform.position-transform.up*height, ....)
Next one is to use an empty object at the base of the character, which we refer to instead of the center.
public Transform pivot;
Then..
Physics2D.Raycast(pivot, ....)
There are a few ways of actually doing this.
The most usual although a bit complicated way of doing it for a beginner is using Raycasts. A Raycast is basically a small invisible line that starts and ends where you tell it to. If anything of a specific tag or layer is caught in it's crossfire you can basically pull that object from your code. Raycasts are used for a lot of things, most notably in Shooter games to shoot or in games like Skyrim to pickup objects and interact with them.
Another way to do this, which is a bit more popular in 2D games is to create a "feet" GameObject and make it the child of the player in the hierarchy. You can add a box collider on that GameObject and check the "IsTrigger". You can add a Tag to your ground objects and through your code using the OnTriggerEnter() and OnTriggerExit() Methods you can basically tell when your character is floating on air and when he is on ground.
Another popular method is to use the Physics.OverlapBox() Method which is pretty much the same as the Trigger Method but you are creating an invisible box (much like a raycast) and instead of only getting notified when Triggered (something enters or exits) you check if the invisible box is colliding with another object/tag/collider (which could be your ground).
There are also a few different things you can do with a Nav Mesh (mostly in 3D) but I think that for now these 3 should suffice!
I am building a 3d topdown shooter. The player controls the avatar with the keyboard and the reticule with the mouse.
I found a simple way to implement the reticule based on this article:
https://gamedevbeginner.com/how-to-convert-the-mouse-position-to-world-space-in-unity-2d-3d/
I defined an object which represents the reticule and attached this script:
public class Reticule : MonoBehaviour
{
Camera mainCamera;
Plane plane;
float distance;
Ray ray;
// Start is called before the first frame update
void Start()
{
mainCamera = Camera.main;
plane = new Plane(Vector3.up, 0);
// This would be turned off in the game. I set to on here, to allow me to see the cursor
Cursor.visible = true;
}
// Update is called once per frame
void Update()
{
ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (plane.Raycast(ray, out distance))
{
transform.position = ray.GetPoint(distance);
}
}
}
This works, but the issue is that the reticule is lagging behind the mouse cursor, and catches up when I stop moving the mouse.
Is this because this method is just slow. Is there another simple way to achieve the same result?
the issue is that the reticule is lagging behind the mouse cursor, and catches up when I stop moving the mouse
That's normal, your mouse cursor is drawn by the graphics driver (with the help of WDM) as fast as the mouse data information comes over the wire, while your game only renders at a fixed framerate (or slower). Your hardware mouse will always be ahead of where your game draws it or anything related to it.
Some things that can help with working around this:
Don't show the system cursor, instead show your own. That way the cursor you show will always be in the same place your game thinks it is (since it drew it) and you won't have this issue. Careful with this however, because if your game's frame rate starts dipping it will be VERY noticeable when your cursor movement isn't smooth anymore.
Don't tie objects to your cursor. The issue doesn't show with normal interactions, like clicking buttons. You will notice this in RTS games when drawing boxes around units, but I struggle to think of another example of this.
Like above, but less restrictive, you could lerp the objects tied to your cursor in place, so they're always and intentionally behind it. It makes it look more gamey, which isn't that bad for a, you know, game. Though I wouldn't do this for a twitchy shooter, of course.
I have a 3d model prefab in unity that I'm trying to add physics to. The issue is that the prefab was imported from auto desk and when that happened the pivot/center of gravity for all the child mesh objects was not where you would necessarily expect them. I've tried attaching a rigid body to the various child objects and setting the center of mass with a script but it doesn't seem to be working as I would expect. My method for setting the center of mass involved creating two child game objects at either end of the highlighted object and using the midpoint formula to a 'good enough' center of mass. Is there any way around this beyond rebuilding/re-importing the object?
Showing the off center pivot
Showing the weird center of mass
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CenterOfGravity : MonoBehaviour
{
// Start is called before the first frame update
public Transform[] centerPoints;
public Rigidbody rb;
void Start()
{
centerPoints = gameObject.GetComponentsInChildren<Transform>();
Transform center1 = Array.Find(centerPoints, elem => elem.name.Equals("Center1"));
Transform center2 = Array.Find(centerPoints, elem => elem.name.Equals("Center2"));
Vector3 center = (center1.localPosition + center2.localPosition)/2.0f;
rb = GetComponent<Rigidbody>();
rb.ResetCenterOfMass();
rb.centerOfMass = center;
}
// Update is called once per frame
void Update(){}
}
Every time I have to change the center off mass of an object, I create an empty child Game Object in the place where I want to be the center of mass.
After that, I set the center off mass of the object, to the local position of the new child object, something like that:
public GameObject childObj, myObj;
void Start()
{
myObj.GetComponent<Rigidbody>().centerOfMass = childObj.transform.localPosition;
}
Edit:
If you want to change the pivot of a GameObject, you need to do those things:
1-Create an empty game object and name it as "Pivot".
2-Place the pivot where you want the center of mass to be.
3-Asign your initial game object that you want to change the pivot as child of your new object called "Pivot".
Now the pivot of the initial game object should be the empty game object called pivot.
Some disclaimers first, AFAIK there's no way to do that in unity BUT! there is a workaround I came across when I had a similar issue. The thing is that I'm not quite sure what your work pipeline is, and this fix might be even worst than just modifying the meshes in auto desk and reimporting it.
The idea is to move your object temporarily to another game object, then modifying the broken pivot and bringing it back to the original object. The idea comes from this video. It may work for you too!
I am trying to make an AR game and am currently using Unity's high-level networking classes. I have set my player prefab to be spawned in one of the two network spawn locations, which are both childs of the Ground Plane Stage. When user has tapped to make their ground plane stage and has tapped to be the host, their player character appears. Unfortunately, if they press the fire button, the bullets appear above the stage and unscaled, meaning they aren't parented to the stage. This confuses me because I've checked many times and the bullet emitter is a child of the player, and in my code it references said emitter. Thus I'm rather confused why the bullets don't seem parented.
I've attempted to attach a script to make the bullet emitter a child of the player when it spawns. I've also tried making it a child of the stage when it spawns. I've tried making the player character not dependent on the Network manager spawning it when the player joins, but then that leads to other networking problems when it comes to controlling the character, but it can shoot then.
The only one that was relatively successful was making the bullet a child of the stage when it spawned, but it would only stay in one place. Attempting to make the bullet a child of the player did nothing
//This is the class I'm trying to use to make the object a child of
something
public class AddToBeetle : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
GameObject player =
GameObject.FindGameObjectWithTag("Player");
transform.SetParent(beetle.transform, false);
}
}
It rarely prints any error messages. I hope that I can eventually get the bullet to spawn in front of the player model when the button is pressed.
Oh gosh I was dumb, the one thing I didn't apply the script to was the player's bullet emitter. It was super late and that's probably why I missed trying it on that. Anyway I hope this helps someone else if they ever have to deal with AR and Unity.
I created a new empty gameobject in the hierarchy.
Attached to it a Box Collider:
And changed this settings on the Box Collider:
I set it's center property to 0,0,0
And set the size to x = 500 y = 600 z = 500
I also set the IsTrigger to be on( the checkbox is checked ).
And this is the Terrian details:
Width 500 Length 500 Height 600
When i'm looking at the scene window it seems like the box is around the terrain edges as it should be: ( Maybe in the right side there some space between the box and the terrain ? )
Scene Screenshot
This is the script attached to the empty gameobject ( InvisibleWalls ).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BoxCollider : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerExit(Collider c)
{
Destroy(c.gameObject);
}
}
This is just for the test.
I added a break point on the line:
Destroy(c.gameObject);
Just to check when the event trigger.
The player ( ThirdPersonController ) is walking at speed 10.
When it's getting to the terrain edge the event is not triggering. The player keep walking on the air for some more seconds and only then the event is trigger and stop on the break point but then the player is already out the terrain area.
Event Triggered
What i want to do is once the player is touching the wall trigger the event and do something for example keep the player walking on place so the wall is blocking him. But now the event is trigger when the player is out of the terrain area.
Well this looks like the result of starting the player inside the collider, and using OnTriggerExit. That method won't be called until all of the player's collider is outside the defined box.
You could make the box smaller, so that there is some "padding" terrain around the outside of it. This is probably the quickest, but I would recommend option 2 instead.
You could make 4 box colliders, one for each wall. Instead of having one gigantic collider and waiting for the player to step out, think of these as skinny walls placed one to each side of your terrain. Don't make them triggers, and use the OnCollisionEnter event instead. This will automatically stop the player if you are moving him via physics, and you get the event as well. You can still make them triggers and use OnTriggerEnter if you want, but why not use the physics system since its there!
I hope this helps, good luck with your project!
Edit: Found a video that explains method 2
1) You Can call OnTriggerEnter if you want the player to be detected before it crosses the Trigger.
2) Another way will be To make the triggers Colliders and they will automatically block the player to cross the terrain boundary