A quick (one evening) port of my old Duck Hunt VR game to the Oculus (a.k.a. Meta) Quest 2. Mainly to check what kind of performance I can expect from this device.
The build is still a little rough especially on the light and shading side. Also the mapping of the Zapper (gun) to the Quest 2 controllers needs some polishing, as the trigger is off-center on the physical controllers.
A BUG in SharpDX.XInput ci-ci217, resulting in issues with the left Thumb Stick, Left Trigger, and Right Trigger!Please stick to SharpDX.XInput v4.1.0-ci184 for now.
using System;
using Com.Okmer.GameController;
namespace XBoxSampleConsole
{
classProgram
{
staticvoid Main(string[] args)
{
XBoxController controller = newXBoxController();
Console.WriteLine("XBox 360 Controller (Press ENTER to exit...)");
//Connection
controller.Connection.ValueChanged += (s, e) => Console.WriteLine($"Connection state: {e.Value}");
//Battery
controller.Battery.ValueChanged += (s, e) => Console.WriteLine($"Battery level: {e.Value}");
//Buttons A, B, X, Y
controller.A.ValueChanged += (s, e) => Console.WriteLine($"A state: {e.Value}");
controller.B.ValueChanged += (s, e) => Console.WriteLine($"B state: {e.Value}");
controller.X.ValueChanged += (s, e) => Console.WriteLine($"X state: {e.Value}");
controller.Y.ValueChanged += (s, e) => Console.WriteLine($"Y state: {e.Value}");
//Buttons Start, Back
controller.Start.ValueChanged += (s, e) => Console.WriteLine($"Start state: {e.Value}");
controller.Back.ValueChanged += (s, e) => Console.WriteLine($"Back state: {e.Value}");
//Buttons D-Pad Up, Down, Left, Right
controller.Up.ValueChanged += (s, e) => Console.WriteLine($"Up state: {e.Value}");
controller.Down.ValueChanged += (s, e) => Console.WriteLine($"Down state: {e.Value}");
controller.Left.ValueChanged += (s, e) => Console.WriteLine($"Left state: {e.Value}");
controller.Right.ValueChanged += (s, e) => Console.WriteLine($"Right state: {e.Value}");
//Buttons Shoulder Left, Right
controller.LeftShoulder.ValueChanged += (s, e) => Console.WriteLine($"Left shoulder state: {e.Value}");
controller.RightShoulder.ValueChanged += (s, e) => Console.WriteLine($"Right shoulder state: {e.Value}");
//Buttons Thumb Left, Right
controller.LeftThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb state: {e.Value}");
controller.RightThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb state: {e.Value}");
//Trigger Position Left, Right
controller.LeftTrigger.ValueChanged += (s, e) => Console.WriteLine($"Left trigger position: {e.Value}");
controller.RightTrigger.ValueChanged += (s, e) => Console.WriteLine($"Right trigger position: {e.Value}");
//Thumb Positions Left, Right
controller.LeftThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb X: {e.Value.X}, Y: {e.Value.Y}");
controller.RightThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb X: {e.Value.X}, Y: {e.Value.Y}");
//Rumble Left, Right
controller.LeftRumble.ValueChanged += (s, e) => Console.WriteLine($"Left rumble speed: {e.Value}");
controller.RightRumble.ValueChanged += (s, e) => Console.WriteLine($"Right rumble speed: {e.Value}");
//Rumble 0.25f speed for 500 milliseconds when the A or B button is pushed
controller.A.ValueChanged += (s, e) => controller.LeftRumble.Rumble(0.25f, 500);
controller.B.ValueChanged += (s, e) => controller.RightRumble.Rumble(0.25f, 500);
//Rumble at 1.0f speed for 1000 milliseconds when the X or Y button is pushed
controller.X.ValueChanged += (s, e) => controller.LeftRumble.Rumble(1.0f, 1000);
controller.Y.ValueChanged += (s, e) => controller.RightRumble.Rumble(1.0f, 1000);
//Rumble at the speed of the trigger position
controller.LeftTrigger.ValueChanged += (s, e) => controller.LeftRumble.Rumble(e.Value);
controller.RightTrigger.ValueChanged += (s, e) => controller.RightRumble.Rumble(e.Value);
//Wait on ENTER to exit...Console.ReadLine();
}
}
}
This is a little playful MutableWhenAny and MutableWhenAll extension for the Task Parallel Library (TPL), using a ObservableCollection.
The extension makes it possible to add or removed tasks to/from an ObservableCollection<Task> while the MutableWhenAny or MutableWhenAll is used to wait on the tasks in this (mutable) collection.
It’s not super useful in practice, but a nice little exercise that combines two cool C# features into a fun asynchronous “magic” trick.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading;
using System.Threading.Tasks;
namespace Com.Okmer.Extensions.ObservableCollectionOfTask
{
publicstaticclassObservableCollectionOfTaskExtention
{
privateconstint INFINITE = -1;
publicstaticasyncTask MutableWhenAll(thisObservableCollection<Task> collection)
{
await MutableWhenSomething(collection, Task.WhenAll);
}
publicstaticasyncTask MutableWhenAny(thisObservableCollection<Task> collection)
{
await MutableWhenSomething(collection, Task.WhenAny);
}
privatestaticasyncTask MutableWhenSomething(thisObservableCollection<Task> collection, Func<IEnumerable<Task>, Task> whenSomething)
{
Task waitAllTask = null;
Task helperTask = null;
bool isCollectionChanged = false;
do
{
//Cancellation on collection changed eventvar cts = newCancellationTokenSource();
var cancelActionHandler = (sender, arg) => cts.Cancel(false);
collection.CollectionChanged += cancelActionHandler;
//Current collection
waitAllTask = whenSomething(collection);
//Wait on current collection or collection changed eventtry
{
helperTask = Task.Delay(INFINITE, cts.Token);
awaitTask.WhenAny(waitAllTask, helperTask);
}
finally
{
isCollectionChanged = cts.IsCancellationRequested;
cts.Cancel(false);
cts.Dispose();
collection.CollectionChanged -= cancelActionHandler;
}
}
while (isCollectionChanged);
//Return the WaitAll on collection resultsawait waitAllTask;
}
}
}
A simple example application that demonstrates the MutableWhenAll extension on an observable collection of tasks. The longest running task is added to the observable collection after MutableWhenAll is called, but the MutableWhenAll will complete only when all tasks (included this longest running task) are completed.