So I'm completely new to Unity and VR but for a project I need to detect the positions of the base stations.
I tried googling, but since I don't know all the lingo I don't really know where and what to look for.
All I can find is how to detect the controllers.
Here's one way, all with Unity code:
var nodeStates = new List<XRNodeState>();
InputTracking.GetNodeStates(nodeStates);
foreach (var trackedNode in nodeStates.Where(n => n.nodeType == XRNode.TrackingReference))
{
bool hasPos = trackedNode.TryGetPosition(out var position);
bool hasRot = trackedNode.TryGetRotation(out var rotation);
}
In OpenVR, base stations are "tracked devices", just like the controllers and HMD. The standard SteamVR plugin for Unity already has a way to get the position of any tracked device, see for example how the controllers are implemented in the standard [CameraRig] prefab.
The only problem is that you need to provide the "index" of the device, which may change every time you reconnect your headset. SteamVR plugin handles this with the SteamVR_ControllerManager component, but as the name suggests - it handles only controllers. You should be able to implement something similar, or just edit the script and find the lines
if (deviceClass == ETrackedDeviceClass.Controller ||
deviceClass == ETrackedDeviceClass.GenericTracker)
and add ETrackedDeviceClass.TrackingReference to this list. You should then be able to copy the controller objects and attach them in the "additional objects" array in SteamVR_ControllerManager to have the base stations appear in your scene.
Related
I m building a car simulator game using Unity. For the input I m using Logitheck steering wheel G29. Now I need to use Hand Controller to accelerate or break.
This is my Hand Controller
Hand Controller HC1
Link
Now I can I interpect his input ? This device is recognize by my windows 10 system, but if I try to start the game with this device I cannot accelerate or break the car.
I configured this in my InputController of Unity:
And in my IRDSPlayerControls.cs file I write these lines of code:
if (Input.anyKey)
{
foreach (KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
{
Debug.Log("Joystick pressed " + kcode);
}
}
Debug.Log("Input debug acc: " + Input.GetAxis("Vertical3"));
Debug.Log("Input debug frenata: " + Input.GetAxis("Vertical4"));
In Console of Unity, I can display this:
Input debug acc: -1
Input debug frenata: -1
You can detect a specific button on a specific joystick joystick 1 button 0, joystick 1 button 1, joystick 2 button 0…
or a specific button on any joystick joystick button 0, joystick button 1, joystick button 2…
Check out Input Manager
I can explain this step by step here but it wont be as good as some tutorials online. I recommend this video as a good tutorial to do this.
UPDATE:
I think your hand controller give analog values and the acceleration/brake buttons are not actually buttons but they are analog joy sticks and have a range of values.
to check this use Input.GetJoystickNames :
using UnityEngine;
public class Example : MonoBehaviour
{
// Prints a joystick name if movement is detected.
void Update()
{
// requires you to set up axes "Joy0X" - "Joy3X" and "Joy0Y" - "Joy3Y" in the Input Manager
for (int i = 0; i < 4; i++)
{
if (Mathf.Abs(Input.GetAxis("Joy" + i + "X")) > 0.2 ||
Mathf.Abs(Input.GetAxis("Joy" + i + "Y")) > 0.2)
{
Debug.Log(Input.GetJoystickNames()[i] + " is moved");
}
}
}
}
I will suggest to first check if those inputs are being received with:
if (Input.anyKey)
{
foreach(KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
{
Debug.Log(kcode);
}
}
This way you can know if the game is recognizing the keycodes of your controller, and if it does, which names are assigned to them.
Once you got this, you only need to check keycodes as an usual keyboard!
Not every joystick, steer etc. is mapping it's inputs to the same axis.
There is a unity forum about that topic (and other related problems). And I found that there are some unity plugins, that could probably solve your problem:
https://github.com/speps/XInputDotNet
https://github.com/JISyed/Unity-XboxCtrlrInput
There are some programs that you can use to list all input axis and see which one you are currently affecting. I used one of them but don't remember the name of it. It might help you to see to which axis your break and throttle are mapped to.
Some of them also allow you to remap then, if this is what you want.
The most probable cause is Unity3D does not support this device.
Unity3D uses a mix of XInput, GameInput?, and USB HID processing for its input on Windows.
It is unclear(closed source), if GameInput is used on Windows, it is required on the modern XBOX's.
I cannot provide a definitive answer, since I do not have this controller to test, and the documentation on the controller is sparse.
The best I can do is point you in the right direction.
Does the device exist in Unity3D:
See if the Input System identifies the device when plugged in while running (make sure the game window has focus):
Adapted from https://docs.unity3d.com/Packages/com.unity.inputsystem#1.4/manual/HowDoI.html
InputSystem.onDeviceChange +=
(device, change) =>
{
switch (change)
{
case InputDeviceChange.Added:
// New Device.
Debug.Log("New device added.");
break;
case InputDeviceChange.Disconnected:
// Device got unplugged.
break;
case InputDeviceChange.Connected:
// Plugged back in.
break;
case InputDeviceChange.Removed:
// Remove from Input System entirely; by default, Devices stay in the system once discovered.
break;
default:
// See InputDeviceChange reference for other event types.
break;
}
}
A lack of log output, when plugged in means the device was not identified as a potential input device. Skip to "All else Fails" below.
Identification at this level does not imply support, as it may flag all HID devices.
Look at all low level input events while pressing the buttons:(Also adapted from 4)
var trace = new InputEventTrace(); // Can also give device ID to only
// trace events for a specific device.
trace.Enable();
//…run stuff
var current = new InputEventPtr();
while (trace.GetNextEvent(ref current))
{
Debug.Log("Got some event: " + current);
}
// Trace consumes unmanaged resources. Make sure to dispose.
trace.Dispose();
The chances of getting here with responses(given the edited output) are slim, but if it happens explore the output to find hints to the device associations and fix your mappings accordingly.
All else Fails
Request device support though Unity3D.com website. Highly recommended.
You can write your own support for the device using either the USB HID, may be flagged by virus scanners, and there is limited documentation or implement a custom GameInput interface. The inclusion in Windows Game Controllers makes this the most probable solution.
I am trying to load an animation from an fbx file and have it play on a GameObject:
TestObject.AddComponent<Animation>();
animation_handler = TestObject.GetComponent<Animation>();
walking_anim = Resources.Load("fbx_anims/walking_anim_test", typeof(AnimationClip)) as AnimationClip;
if(walking_anim == null)
{
Debug.Log("walking anim not found");
}
walking_anim.legacy = true;
animation_handler.AddClip(walking_anim, "walking");
animation_handler.wrapMode = WrapMode.Loop;
In the game loop, I tried using this:
if (Input.GetKeyDown(KeyCode.W))
{
if (!(animation_handler.IsPlaying("walking")))
{
animation_handler.clip = walking_anim;
animation_handler.Play("walking");
}
}
It doesnt give any errors, yet it doesn't work either. Anything I'm missing?
EDIT: For clarification: The model stays in the default T-Pose, after pressing 'W'. After inserting Debug.Logs at different points, I can confirm that the Play function is getting called only once, after which IsPlaying always returns true. Yet the "playing" animation causes no visual changes in the model (yes, the bone names are the same).
You don't want to use the Animation component, it is an old legacy component that has been replaced by the much improved Animator component. There are a lot of good posts on the Internet on how to use it - no need to repeat it here. The important steps are:
Add the Animator (not Animation) component to the model.
Create an "Animator Controller" in your project and add the clips (like the "walking_anim"). Here you can have a lot of different clips and tell Unity how to interpolate between them by using different parameters.
Add the "Animator Controller" to your "Animator" component.
Add an "avatar" of your model (usually created when the model is imported).
By code alter the parameters of the Animator Controller to tell it which animation clips to play.
It may look like a lot of steps, but it is not so hard and you will quickly have a walking, running, jumping creature on your screen. Good luck!
Working in Godot 3.2, I have a scene, Player.tscn. Near the top of Player.tscn, I have "class_name Player"
Now, when instantiating the Player, I have, as far as I see it, two options:
player = Player.new()
or
player = load("res://Player.tscn").instance() as Player
Now, the first version seems best to me...but it clearly isn't. If I use .new(), it claims that it has no children, and any method calls that attempt to get to its children (.get_texture() on a Sprite, e.g.), produces things like "Attempt to call function 'get_texture' in base 'null instance' on a null instance", because apparently Player has a no children.
Of course, doing it the second way, everything works fine. But why? Why can't I just use .new() if I've registered it as a class using class_name?
I'm new to Godot myself so I may be wrong, but I think it's because the .new() keyword is a language feature for loading single classes/nodes,
whereas .instance() is more of an engine feature that takes a packaged scene which is a combination of many classes/nodes, and restores their relative position in the tree, attaches scripts and resources, etc
So if your player is a tscn scene, you'd do something like:
var player = load("res://etc/Player.tscn").instance()
get_tree().root.add_child(player)
player.global_transform = etc ...
which would load the root node of Player.tscn and all of its children (rigidbodies, collidershapes etc) into the scene tree, set their relative positions, connect the scripts and what have you
Or if your Player is a class or a GDScript, you could do
var player = Player.new()
get_tree().root.add_child(player)
player.global_transform = etc ...
Which would add the single-node root player object only into the scene tree, but not any children
Once it's in the scene tree and _ready()'s triggered though, you can instantiate and attach the child component nodes (.new() > parent.add_child() > set transform) from the script itself
Hi how do we change motion in an AnimatorController using script in Unity Editor?
The red highlight is the one I'd like to change, but using script
My use case is to copy animations from one object, process the animation e.g. adding offset rotation, then add to another object. Since my object has many child objects, I need to create a script to automate this.
Changing the AnimatorController via editor scripts is always quite tricky!
First of all you need to have your AnimationClip from somewhere
// somewhere get the AnimationClip from
var clip = new AnimationClip();
Then you will have to cast the runtimeAnimatorController to an AnimatorController which is only available in the Editor! (put using UnityEditor; at the top of the script!)
var controller = (AnimatorController)animator.runtimeAnimatorController;
Now you can get all its information. In your case you can probably use the default layer (layers[0]) and its stateMachine and according to your image retrieve the defaultState:
var state = controller.layers[0].stateMachine.defaultState;
or find it using Linq FirstOrdefault (put using System.Linq; at the top of the script) like e.g.
var state = controller.layers[0].stateMachine.states.FirstOrDefault(s => s.state.name.Equals("SwimmingAnim")).state;
if (state == null)
{
Debug.LogError("Couldn't get the state!");
return;
}
Finally assign the AnimationClip to this state using SetStateEffectiveMotion
controller.SetStateEffectiveMotion(state, clip);
Note however that even though you can write individual animation curves for an animation clip using SetCurve unfortunately it is not possible to read them properly so it will be very difficult to do what you want
copy animations from one object, process the animation e.g. adding offset rotation, then add to another object.
You will have to go through AnimationUtility.GetCurveBindings which gets quite complex ;)
Good Luck!
I'm using the A* pathfinding algorithm for my 2D game (from my understanding, Unity Nav Meshes don't work in 2D). I would like to be able to pre-calculate navigation grids for all of my scenes, and save them in resource files that can be loaded whenever the player enters a new scene. Rather than having to remember to click "calculate" for every scene -- and remember to recalculate all of my scenes if I make a change to my navigation grids -- I want to be able to programatically have the Unity Editor iterate though each scene and calculate the grids.
Is there a way to create a command in the Unity editor that will iteratively open each scene in the editor and run a method on a MonoBehaviour that's in the scene? Alternatively, is there another way to accomplish what I'm trying to do?
Yes you can!
In editmode you can't use SceneManager but have to use the EditorSceneManager.
First of all you need the scenes you want to iterate.
Could be e.g. a public static field with a list of SceneAsset in the Inspector where you simply reference the scenes
public static List<SceneAsset> Scenes = new List<SceneAsset>();
or you could get them by script e.g. for only use the scenes added to the build settings using EditorBuildSettings.scenes
List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;
For both you can get a list of the scene paths e.g. using LinQ Select (this is basically a kind of shortcut for a foreach loop) and AssetDatabase.GetAssetPath like
List<string> scenePaths = Scenes.Select(scene => AssetDatabase.GetAssetPath(scene)).ToList();
for the EditorBuildSettingsScene from EditorBuildSettings.scenes you can also simply use
List<string> scenePaths = Scenes.Select(scene => scene.path).ToList();
Now you can iterate over them all and do your stuff by using EditorSceneManager.OpenScene, EditorSceneManager.SaveScene and EditorSceneManager.CloseScene (and if you need it AssetDatabase.SaveAssets)
foreach(string scenePath in scenePaths)
{
// Open a scene e.g. in single mode
var currentScene = EditorSceneManager.OpenScene(scenePath);
/* Do your calculation for currentScene */
// Don't know if it makes changes to your scenes .. if not you can probably skip this
EditorSceneManager.SaveScene(currentScene);
// Finally Close and remove the scene
EditorSceneManager.CloseScene(currentScene, true);
}
// you might be doing changes to an asset you want to save when done
AssetDatabase.SaveAssets();
Before starting you should probably ask to save the current open scene(s) using EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
// Saved => the foreach loop here
}
else
{
// aborted => do nothing
}
Than in order to finally start that method the simplest would be to add a [MenuItem]
public static class Calculation
{
[MenuItem("YourMenu/RunCalculation")]
public static void RunCalculation()
{
// all the before mentioned snippets here
// depending how exactly you want to do it
}
}
This will add a new menu YourMenu with one entry RunCalculation to the top menubar of the Unity Editor.
Note:
Since this uses a lot of types (EditorSceneManager etc) that only exist in the UnityEditor namespace you should either place the whole script in an Editor folder (so it is ignored in the final build) or use pre-processors like
#if UNITY_EDITOR
// ... code here
#endif
so in the build the code is also ignored.
Note that I'm assuming so far you also did your calculation in editmode. The thing is if this calculation relies somewhere aon any Start or Awake method you have to call it manually from that editorscript before running the calculation.