UniWii

From Unify Community Wiki
Jump to: navigation, search

Contents

Author info

Mac version created by Rob Terrell of Stinkbot LLC. You can contact him at robterrell@gmail.com.

Windows version courtesy of ByDesign Games in cooperation with Rob Terrell of Stinkbot LLC

What it does

The UniWii plugin uses the DarwinRemote framework to connect with up to 16 Wiimotes. It supports the primary and nunchuck accelerometer, IR sensors, rumble, and all of the buttons on the Wiimote and Nunchuck peripheral.

This plugin has been used with Unity's stock FPS Tutorial to implement a RedSteel-style method of control, where the Wiimote controls mouselook and weapon aiming, and the nunchuck joystick controls the player's movement through the scene; various buttons fire or switch weapons. Give it a try: FPS with Wiimote Demo FPS with Wiimote Demo Source Project

The plugin has been used to support head tracking. See the video here: http://robterrell.com/UnityHeadtracking01.mov

Windows version downloadable includes test scene with interactive Wii-mote model & test code.

Note: If the DLL does not seem to work (or your game seems to get stuck on the wiimote_start), you might need to install the Microsoft Visual C++ 2008 SP1 Redistributable Package (x86). This might instantly solve your problem. This situation might actually happen if you move your game to a machine which is not a development machine.

Limitations

DarwiinRemote supports an event-based model, whereas Unity offers no method for sending events into the engine, so your code will need to poll the Wiimote for events periodically. Not much of a limitation, in the end. DarwiinRemote seems to be a little slow to connect to Wiimotes initially.

Since it seems it's not that obvious for some people, this doesn't work for webbuilds since you can't use any native code plugins in a webbuild.

Copyright

The Mac plugin is Copyright 2007 Stinkbot LLC. Please check with us before including it in release builds of your projects.

The Windows plugin is Copyright 2009 ByDesign Games SARL and is free for non-commercial use. Commercial usage license is available; please check the Windows downloadable for full license details. We'd love to hear about which projects you're using it in, so if you use this on a project, drop us a quick email!


Download

You can download the current Mac version of the plugin from here.

Download the current Windows version of the plugin + test scene here.

How to Install

If you've never used a Unity plugin before, you may want to read the Unity manual's page on plugins.

plugins are copied into your project's "Assets" folder, inside a folder called "Plugins". Create the Plugins folder and copy the (unzipped, of course) plugin into it. Basically, you put the plugin bundle into a folder called "Plugins" in your project's Assets folder.

How to Use

You need to write a C# script that calls the plugin's functions. In general, your code will call wiimote_start(), check for a connected wiimote with wiimote_count(), and get the wiimote's values with the other functions.

Any code that uses the plugin needs to first declare the plugin's interface. Here I am using c# syntax. (You can probably use these functions from JavaScript and Boo, too, but I haven't yet found the correct syntax to declare the external interfaces. If anyone knows how to do this, please let me know.)

Here is a simple script you should try first. It just checks for Wiimotes and displays a message if they are found. Create a new C# script called "UniWiiCheck.cs" and copy the script below into it:

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
 
public class UniiWiiCheck : MonoBehaviour {
 
	[DllImport ("UniWii")]
	private static extern void wiimote_start();
 
	[DllImport ("UniWii")]
	private static extern void wiimote_stop();
 
	[DllImport ("UniWii")]
	private static extern int wiimote_count();
 
	private String display;
 
	void OnGUI() {
		int c = wiimote_count();
		if (c>0) {
			display = "";
			for (int i=0; i<=c-1; i++) {
				display += "Wiimote " + i + " found!\n";
			}
		}
		else display = "Press the '1' and '2' buttons on your Wii Remote.";
 
		GUI.Label( new Rect(10,Screen.height-100, 500, 100), display);
	}
 
	void Start ()
	{
		wiimote_start();
	}
 
	void OnApplicationQuit() {
		wiimote_stop();
	}
 
}

Plugin Interface

The interface declaration for the plugin is below. You only need to declare the functions you're going to use.

[DllImport ("UniWii")]
private static extern void wiimote_start();
[DllImport ("UniWii")]
private static extern void wiimote_stop();
 
[DllImport ("UniWii")]
private static extern int wiimote_count();
[DllImport ("UniWii")]
private static extern bool wiimote_available( int which );
[DllImport ("UniWii")]
private static extern bool wiimote_isIRenabled( int which );
[DllImport ("UniWii")]	
private static extern bool wiimote_enableIR( int which );
[DllImport ("UniWii")]
private static extern bool wiimote_isExpansionPortEnabled( int which );
[DllImport ("UniWii")]
private static extern void wiimote_rumble( int which, float duration);
[DllImport ("UniWii")]
private static extern double wiimote_getBatteryLevel( int which );
 
[DllImport ("UniWii")]
private static extern byte wiimote_getAccX(int which);
[DllImport ("UniWii")]
private static extern byte wiimote_getAccY(int which);
[DllImport ("UniWii")]
private static extern byte wiimote_getAccZ(int which);
 
[DllImport ("UniWii")]
private static extern float wiimote_getIrX(int which);
[DllImport ("UniWii")]
private static extern float wiimote_getIrY(int which);
[DllImport ("UniWii")]
private static extern float wiimote_getRoll(int which);
[DllImport ("UniWii")]
private static extern float wiimote_getPitch(int which);
[DllImport ("UniWii")]
private static extern float wiimote_getYaw(int which);
 
[DllImport ("UniWii")]
private static extern byte wiimote_getNunchuckStickX(int which);
[DllImport ("UniWii")]
private static extern byte wiimote_getNunchuckStickY(int which);
 
[DllImport ("UniWii")]
private static extern byte wiimote_getNunchuckAccX(int which);
[DllImport ("UniWii")]
private static extern byte wiimote_getNunchuckAccZ(int which);
 
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonA(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonB(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonUp(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonLeft(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonRight(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonDown(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButton1(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButton2(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonNunchuckC(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonNunchuckZ(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonPlus(int which);
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonMinus(int which);
 
// Aquired through Dependency walker. 
 
[DllImport ("UniWii")]
private static extern bool wiimote_getButtonHome(int which);
 
 
// Not sure about return types.
[DllImport ("UniWii")]
private static extern float wiimote_getNunchuckPitch(int which);
 
[DllImport ("UniWii")]
private static extern float wiimote_getNunchuckRoll(int which);
 
[DllImport ("UniWii")]	
private static extern bool wiimote_setLed( int which );

Function Reference

Here's a brief guide to the functions the plugin makes available.

wiimote_start()

wiimote_stop()

Call these when you want the start or stop using the Wiimotes, i.e. Start() and OnApplicationQuit(). After you call wiimote_start(), you should present a message to the user telling them to press the 1 & 2 buttons on their Wiimote (or the red button in the battery compartment) to initiate the connection.

wiimote_count()

Returns the number of connected Wiimotes.

wiimote_available( int which )

Returns true if there is a connected Wiimote at the given index. Since Wiimotes can drop out (out of range, out of battery) it's a good idea to check.

wiimote_isIRenabled( int which )

wiimote_enableIR( int which )

If you are going to use the IR mode (i.e. use the Wiimote as a pointer, or for head-tracking), the Wiimote's IR mode needs to enabled. (I use the Nyko sensor bar, about $20, to provide an IR source on my Mac.)

wiimote_isExpansionPortEnabled( int which )

If this is true, something is plugged into the Expansion port. Hopefully the thing plugged in is the Nunchuck controller, because that the only thing UniWii supports at the moment.

wiimote_rumble( int which, float duration)

Tells a Wiimote to rumble for a certain duration (a floating point value, in seconds).

wiimote_getBatteryLevel( int which )

Returns the battery level of the given Wiimote.

wiimote_getAccX(int which)

wiimote_getAccY(int which)

wiimote_getAccZ(int which)

Returns the raw values for Wiimote accelerometer for each axis. The return value is a byte, so the rotation values can be from 0 to 255.

wiimote_getRoll(int which)

wiimote_getPitch(int which)

wiimote_getYaw(int which)

Returns values for roll, pitch, yaw. Here's how I used these values to rotate an object called "wiiparent":

private Vector3 oldVec;
void FixedUpdate () {
	int c = wiimote_count();
	if (c>0) {
		for (int i=0; i<=c-1; i++) {
			float roll = Mathf.Round(wiimote_getRoll(i));
			float p = Mathf.Round(wiimote_getPitch(i));
			float yaw = Mathf.Round(wiimote_getYaw(i));
			if (!float.IsNaN(roll) && !float.IsNaN(p) && (i==c-1)) {
				Vector3 vec = new Vector3(p, 0 , -1 * roll);
				vec = Vector3.Lerp(oldVec, vec, Time.deltaTime * 5);
				oldVec = vec;
				GameObject.Find("wiiparent").transform.eulerAngles = vec;
			}
 
		}
	}
}

wiimote_getIrX(int which)

wiimote_getIrY(int which)

Returns a float (from -1 to 1) of the value of the IR sensors. (-1,-1) is topleft, and (1,1) is bottom right. A value of -100 means the IR sensor could not be seen (i.e. the IR LED was occluded, or the wiimote was pointed away, etc.)

Sample Code

This sample will rotate a GameObject called "wiiparent", and if you have an IR sensor bar, place a crosshair texture called "crosshair" where the wiimote is pointing.

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
 
public class WiiMote : MonoBehaviour {
 
	[DllImport ("UniWii")]
	private static extern void wiimote_start();
 
	[DllImport ("UniWii")]
	private static extern void wiimote_stop();
 
	[DllImport ("UniWii")]
	private static extern int wiimote_count();
 
	[DllImport ("UniWii")]
	private static extern byte wiimote_getAccX(int which);
	[DllImport ("UniWii")]
	private static extern byte wiimote_getAccY(int which);
	[DllImport ("UniWii")]
	private static extern byte wiimote_getAccZ(int which);
 
	[DllImport ("UniWii")]
	private static extern float wiimote_getIrX(int which);
	[DllImport ("UniWii")]
	private static extern float wiimote_getIrY(int which);
	[DllImport ("UniWii")]
	private static extern float wiimote_getRoll(int which);
	[DllImport ("UniWii")]
	private static extern float wiimote_getPitch(int which);
	[DllImport ("UniWii")]
	private static extern float wiimote_getYaw(int which);
 
	private string display;
	private int cursor_x, cursor_y;
	private Texture2D cursor_tex;
	private Vector3 oldVec;
 
	// Use this for initialization
	void Start () {
		wiimote_start();
		cursor_tex = (Texture2D) Resources.Load("crosshair");
	}
 
	// Update is called once per frame
	void FixedUpdate () {
		int c = wiimote_count();
		if (c>0) {
			display = "";
			for (int i=0; i<=c-1; i++) {
				int x = wiimote_getAccX(i);
				int y = wiimote_getAccY(i);
				int z = wiimote_getAccZ(i);
				float roll = Mathf.Round(wiimote_getRoll(i));
				float p = Mathf.Round(wiimote_getPitch(i));
				float yaw = Mathf.Round(wiimote_getYaw(i));
				float ir_x = wiimote_getIrX(i);
				float ir_y = wiimote_getIrY(i);
				display += "Wiimote " + i + " accX: " + x + " accY: " + y + " accZ: " + z + " roll: " + roll + " pitch: " + p + " yaw: " + yaw + " IR X: " + ir_x + " IR Y: " + ir_y + "\n";
				if (!float.IsNaN(roll) && !float.IsNaN(p) && (i==c-1)) {
				    Vector3 vec = new Vector3(p, 0 , -1 * roll);
				    vec = Vector3.Lerp(oldVec, vec, Time.deltaTime * 5);
				    oldVec = vec;
				    GameObject.Find("wiiparent").transform.eulerAngles = vec;
				}
			    if ( (i==c-1) && (ir_x != -100) && (ir_y != -100) ) {
				    	//float temp_x = ((ir_x + (float) 1.0)/ (float)2.0) * (float) Screen.width;
				    	//float temp_y = (float) Screen.height - (((ir_y + (float) 1.0)/ (float)2.0) * (float) Screen.height);
				    	float temp_x = ( Screen.width / 2) + ir_x * (float) Screen.width / (float)2.0;
				    	float temp_y = Screen.height - (ir_y * (float) Screen.height / (float)2.0);
				    	cursor_x = Mathf.RoundToInt(temp_x);
				    	cursor_y = Mathf.RoundToInt(temp_y);
				}
			}
		}
		else display = "Press the '1' and '2' buttons on your Wii Remote.";
	}
 
	void OnApplicationQuit() {
		wiimote_stop();
	}
 
	void OnGUI() {
		GUI.Label( new Rect(10,10, 500, 100), display);
		if ((cursor_x != 0) || (cursor_y != 0)) GUI.Box ( new Rect (cursor_x, cursor_y, 50, 50), cursor_tex); //"Pointing\nHere");
		int c = wiimote_count();
		for (int i=0; i<=c-1; i++) {
			float ir_x = wiimote_getIrX(i);
			float ir_y = wiimote_getIrY(i);
		    if ( (ir_x != -100) && (ir_y != -100) ) {
			    float temp_x = ((ir_x + (float) 1.0)/ (float)2.0) * (float) Screen.width;
			    float temp_y = (float) Screen.height - (((ir_y + (float) 1.0)/ (float)2.0) * (float) Screen.height);
			    temp_x = Mathf.RoundToInt(temp_x);
			    temp_y = Mathf.RoundToInt(temp_y);
				//if ((cursor_x != 0) || (cursor_y != 0))
				GUI.Box ( new Rect (temp_x, temp_y, 64, 64), "Pointer " + i);
		    }
		}
	}
}


Resolving Issues with Building Projects in Unity 3+ Windows

If you are receiving a message like the following:

ArgumentException: The Assembly Microsoft.VisualC is referenced by UniWii. But the dll is not allowed to be included or could not be found.
UnityEditor.AssemblyHelper.AddReferencedAssembliesRecurse (System.String assemblyPath, System.Collections.Generic.List`1 alreadyFoundAssemblies, System.String[] allAssemblyPaths, System.String[] foldersToSearch, System.Collections.Generic.Dictionary`2 cache) (at C:/BuildAgent/work/f724c1acfee760b6/Editor/Mono/AssemblyHelper.cs:52)
UnityEditor.AssemblyHelper.FindAssembliesReferencedBy (System.String[] paths, System.String[] foldersToSearch) (at C:/BuildAgent/work/f724c1acfee760b6/Editor/Mono/AssemblyHelper.cs:86)

Resolve this issue by going into Edit -> Project Settings -> Player and then opening up the "Other Settings" section and setting Api Compatibility Level to .NET 2.0 then try to build again.

Version history

To be added.


For More Information

http://forum.unity3d.com/viewtopic.php?t=7284


To Do / Feature Requests

Requested by Flash: wiimote_getRawIR() to support finger tracking.

Requested by Predster: A code snippet that shows how to get nunchuck data/broadcast to a script.

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox