UniWii

From Unify Community Wiki
Revision as of 20:07, 1 October 2008 by NCarter (Talk | contribs)

Jump to: navigation, search

Contents

Author info

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


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

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


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.


How to use

First, about Unity 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.

If you've never used a Unity plugin before, you may want to read the Unity manual's page on plugins. Basically, you put the plugin bundle into a folder called "Plugins" in your project's Assets folder. Then, you need to write a C# script that calls the plugin's functions. n 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:


<csharp> 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(); }

} </csharp>


Plugin Interface

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

<csharp> [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); </csharp>


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":

<csharp> 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; }

} } } </csharp>

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.

<csharp> 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); } } } } </csharp>

Download

You can download the current version of the plugin from here. Currently, the plugin is a Mac-only universal binary.


Copyright

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


Version history

To be added.


To do

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