With the Internet Channel on Wii, a Web page is able to monitor the cursor and Wii Remote buttons using traditional JavaScript event detection (described in the article "Making Wii-friendly pages"). In addition, it is able to to access motion sensitivity information about the Wii Remote that is being used to browse the Web page. This is exposed through the Wii Remote API.
The Wii Remote API also allows the Web page to detect all Wii Remotes that are connected to the Wii; up to four at a time. This makes it possible to make Web pages interact with up to four users at the same time, a concept not normally possible with traditional JavaScript event detection. The API is available to JavaScript running on the Web page.
The API gives information about the current status of the Wii Remotes. This includes their roll, cursor position, distance from the screen, and what buttons are pressed. It does not give access to acceleration information.
Even when it appears perfectly still, resting on a flat surface, the Wii Remote is constantly sensing motion. In fact, it never stops sensing motion. As a result, it is not possible to use events to detect when it moves, because the events would never stop firing, and it would not be possible for a script to keep up. As a result, the API offers a method to update the data on demand, to obtain the instantaneous values. Typical use would involve polling for this data at required intervals.
The Wii Remote data is accessed through the opera.wiiremote object. This object offers a single method opera.wiiremote.update(n) which is used to obtain the status of an individual Wii Remote. The method expects a single parameter; the Wii Remote number. The number is zero-based, so it starts at 0 for the first remote, and ends at 3 for the fourth remote. The method returns a KpadStatus object, which has several properties that give information about the remote.
This update method can be called as often as is needed to obtain a fluid response, but note that the Wii is not as powerful as most desktop computers, so it is important to make sure that it is polled only as often as the script that uses that data can process it. For example, if a script uses the Wii Remote status to update the display of a canvas element, and that update will take perhaps 50 ms to update in Opera on a desktop computer, it may take over 100 ms on a Wii. Attempting to use a polling interval of less than 100 ms will cause the response to appear very sluggish.
Note that the opera.wiiremote object only exists in Opera on Wii, so it is important to check for its existence, as well as the existence of the opera object, before attempting to use it.
The KpadStatus object gives data for Wii Remotes and Nunchuk buttons only. It does not give information for Classic Controllers.
It is important to note that Wii Remotes can be switched off, be disconnected, or can be out of range. If they remain inactive for too long, they will automatically switch off, even if they are connected. This means that even if a Wii may have 4 remotes connected to it, it is possible that only remote 3 is currently active. It is also possible that none are active. For this reason, it is important to check that the remote is enabled before attempting to use its data values. It is also important not to assume that if a remote is disabled, that no further remotes will be enabled.
If a Wii Remote is enabled, the KpadStatus.isEnabled property for that remote will be 1 for that remote. If the remote is not enabled, the KpadStatus.isEnabled property will be 0 for that remote, and none of the other properties will be defined at all. To check if a remote is enabled, simply use the following:
if( theKpadStatusObject.isEnabled ) { ... }
Another important point is that the data is only valid if the remote is able to see the Sensor Bar. In other words, it must be pointing approximately towards the screen. The actual area that it can see is approximately 1.75 times the width of the screen, and 1.15 times the height, though these will vary significantly depending on how close the user is to the screen. The Wii Remote must also be within the detectable distance from the sensor bar, between approximately 0.55 and 3 metres away. If the remote is not within this detectable distance, and pointing within this visible area, then all relevant properties retain the last value they had, and will no longer update. Properties like hold will still continue to update, as they do not relate to motion sensitivity. The KpadStatus.dpdValidity property can help identify when the remote cannot see the Sensor Bar.
| Button | Bitmask |
|---|---|
| Left | 1 |
| Right | 2 |
| Down | 4 |
| Up | 8 |
| + | 16 |
| 2 | 256 |
| 1 | 512 |
| B | 1024 |
| A | 2048 |
| - | 4096 |
| Z (Nunchuk) | 8192 |
| C (Nunchuk) | 16384 |
Since the remote status can be read while the cursor is over any frame, including frames not belonging to the current page, this property is always 0 for the primary remote (see KpadStatus.isBrowsing). To detect button presses for the primary remote, normal JavaScript key events must be used. Note that the Z and C buttons cannot be detected at all for the primary remote, even when using normal JavaScript key events. Also note that if a script is using the Z and C buttons on the second Wii Remote, and the primary remote disconnects, then the second remote will automatically become the primary remote, and the Z and C buttons will suddenly become completely unavailable.
Math.atan2(KpadStatus.dpdRollY,KpadStatus.dpdRollX)Math.atan2(KpadStatus.dpdRollY,KpadStatus.dpdRollX)
var remote, roll = 0;
//check if the browser provides access to the Wii Remote data
if( window.opera && opera.wiiremote ) {
//get the KpadStatus object for the third Wii Remote
remote = opera.wiiremote.update(2);
//check that the remote is enabled
if( remote.isEnabled ) {
//get the roll angle in radians
roll = Math.atan2( remote.dpdRollY, remote.dpdRollX );
//convert the roll to degrees
roll = roll * ( 180 / Math.PI );
}
}
var remote, buttons = {};
//check if the browser provides access to the Wii Remote data
if( window.opera && opera.wiiremote ) {
//get the KpadStatus object for the third second Wii Remote
remote = opera.wiiremote.update(1);
//check that the remote is enabled
if( remote.isEnabled ) {
//use the bitwise AND operator to compare against the bitmasks
buttons.pressedLeft = remote.hold & 1;
buttons.pressedRight = remote.hold & 2;
buttons.pressedDown = remote.hold & 4;
buttons.pressedUp = remote.hold & 8;
buttons.pressedPlus = remote.hold & 16;
buttons.pressed2 = remote.hold & 256;
buttons.pressed1 = remote.hold & 512;
buttons.pressedB = remote.hold & 1024;
buttons.pressedA = remote.hold & 2048;
buttons.pressedMinus = remote.hold & 4096;
buttons.pressedZ = remote.hold & 8192;
buttons.pressedC = remote.hold & 16384;
}
}
Try the demonstration.
The more complex demonstration shows how to combine this with normal JavaScript event detection to simulate the hold property on the primary remote.
This simple demonstration steps through each Wii Remote, and lists the values of all properties provided for that remote.
A script will often need to find Wii Remotes that are enabled, instead of always assuming that the first remotes will be. The following script steps through all remotes, until it locates the requested number of enabled remotes. If not enough enabled remotes can be found, it can optionally add on enough of the disabled remotes to produce the requested number. The assumption is that these remotes may be enabled later. The findRemotes function returns an array containing the indexes of the remotes, or an empty array if the Wii Remote API is not supported.
function findRemotes(n,padlength) {
var offRemotes = [], foundRemotes = [], i;
if( !window.opera || !opera.wiiremote ) { return foundRemotes; }
//check through the list of remotes for enabled ones
for( i = 0; i < 4 && foundRemotes.length < n; i++ ) {
if( opera.wiiremote.update(i).isEnabled ) {
//if a remote is enabled, put it in the enabled list
foundRemotes[foundRemotes.length] = i;
} else {
//otherwise, put it in the disabled list
offRemotes[offRemotes.length] = i;
}
}
//if remotes must be enabled, or enough were found, return immediately
if( !padlength || foundRemotes.length == n ) { return foundRemotes; }
//otherwise pad to the desired length from the disabled list
for( i = 0; i < offRemotes.length && foundRemotes.length < n; i++ ) {
foundRemotes[foundRemotes.length] = offRemotes[i];
}
return foundRemotes;
}
//find 3 remotes, but do not pad if not enough can be found
var players = findRemotes(3,false);
This demonstration game allows two players to compete against each other, where each player must use rotation of their Wii Remote to keep a ball balanced on a surface, while causing their opponent's ball to roll off their surface. It is also possible to compete without a second player, but where one is good, two is better. The game also demonstrates how to use keys if no Wii Remotes are available.
Since Opera on Wii supports about the same level of JavaScript as Opera 9.10 on desktop, it would be possible to use several different scripted techniques to produce the interactive appearance of the game. An example would be DOM or traditional DHTML. However, since a rotating surface is best represented with vector graphics, it makes sense to use one of the two interactive vector graphics formats supported by Opera on Wii: SVG or canvas. Either of these could be used here, and it is very much a matter of choosing what suits your needs best.
In this case, the game is very simple, and as an example it must have minimal source code. SVG is too overly-capable for this need, and carries more overhead and complexity with it, so the demonstration uses the more simple and less demanding canvas. This also helps to keep the speed high, so the remote can be polled often enough to maintain a fluid effect. Try the demonstration game. View the source code to see an explanation of how it works, and why various choices are made.
Hosted by Chris Ruppel