Multi thread for joystick input - c#

Hi there i am trying to make a question answer game. ( Whoever presses joystick button first answers the question first )
So far i ' ve used SharpDX , threading since i cant handle the button press event via SharpDX
My problem is i cant get it worked . I dont know the reason but let me explain my code.
On my page load i ' ve initialized 2 different threads ;
//Initializing the constants
private bool q = true;
private Thread th1;
private Thread th2;
private Guid joy1Guid = Guid.Empty;
private Guid joy2Guid = Guid.Empty;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var directInput = new DirectInput();
foreach (var deviceInstance in directInput.GetDevices())
{
if (deviceInstance.Subtype == 258)
{
//My joysticks connected to pc via usb.
if (joy1Guid == Guid.Empty)
joy1Guid = deviceInstance.InstanceGuid;
else if (joy2Guid == Guid.Empty)
joy2Guid = deviceInstance.InstanceGuid;
}
}
th1 = new Thread(Joy1Start);
th2 = new Thread(Joy2Start);
th1.IsBackground = true;
th2.IsBackground = true;
}
Below my Thread methods
private void Joy1Start()
{
var directInput = new DirectInput();
var joystick = new Joystick(directInput, joy1Guid);
joystick.Properties.BufferSize = 128;
joystick.Acquire();
while (q)
{
joystick.Poll();
var state = joystick.GetCurrentState();
var counter = 0;
foreach (bool isPressed in state.Buttons)
{
if (isPressed)
{
Action a1 = () => textBox1.Text = "JOY1";
textBox1.Invoke(a1);
th1.Abort();
th2.Abort();
q = false;
break;
}
counter++;
}
}
}
private void Joy2Start()
{
var directInput = new DirectInput();
var joystick = new Joystick(directInput, joy2Guid);
joystick.Properties.BufferSize = 128;
joystick.Acquire();
while (q)
{
joystick.Poll();
var state = joystick.GetCurrentState();
var counter = 0;
foreach (bool isPressed in state.Buttons)
{
if (isPressed)
{
Action a2 = () => textBox1.Text = "JOY2";
textBox1.Invoke(a2);
th1.Abort();
q = false;
break;
}
counter++;
}
}
}
I am firing thread starts with a button
private void button1_Click(object sender, EventArgs e)
{
th1.Start();
th2.Start();
}
So the problem is i can't get any response if i work with two threads.
When i only start th1 or th2 it works like a charm.
Can you please show me where is the wrong part of this algorithm ?

Related

Why doesn't the method work in the OnMessage event?

I use WebSocketSharp to write a client, in Start I add the ChangeColor method to the OnMessage event, and the method is executed but not to the end, it does not change the color of the object, although it should. I tried to call the method in Update on button click and it worked correctly. What is the problem?
The server sends correct data, I checked
WebSocket ws;
private Renderer objectRenderer;
private Color matColor;
private string reciveData;
private void Start()
{
objectRenderer = GetComponent<Renderer>();
ws = new WebSocket("ws://127.0.0.1:8080");
ws.Connect();
ws.OnMessage += (sender, e) =>
{
reciveData = e.Data;
ChangeColor(e.Data); // its dosent work!
};
}
void Update()
{
if (ws == null)
return;
// its work
// if (Input.GetKeyDown(KeyCode.Space))
// {
// ChangeColor(reciveData);
// objectRenderer.material.color = matColor;
// }
}
public void ChangeColor(string data)
{
string[] colors = data.Split(',');
matColor = new Color()
{
r = float.Parse(colors[0]) / 255.0f,
g = float.Parse(colors[1]) / 255.0f,
b = float.Parse(colors[2]) / 255.0f,
a = float.Parse(colors[3]) / 255.0f
};
objectRenderer.material.color = matColor;
}
It does not work, because the WebSocketSharp callbacks run on a worker thread. Unity does not allow to interact with your objectRenderer in any other thread than the main thread.
You can cache the data as you did and process it in update method (which is called in main thread).
Use a boolean to tell the Update method to call your ChangeColour method.
WebSocket ws;
private Renderer objectRenderer;
private Color matColor;
private string reciveData;
private bool newDataToBeProcessed;
private void Start()
{
objectRenderer = GetComponent<Renderer>();
ws = new WebSocket("ws://127.0.0.1:8080");
ws.Connect();
ws.OnMessage += (sender, e) =>
{
reciveData = e.Data;
newDataToBeProcessed = true;
};
}
void Update()
{
if (ws == null)
return;
if (newDataToBeProcessed == true)
{
newDataToBeProcessed = false;
ChangeColor(reciveData);
objectRenderer.material.color = matColor;
}
}
public void ChangeColor(string data)
{
string[] colors = data.Split(',');
matColor = new Color()
{
r = float.Parse(colors[0]) / 255.0f,
g = float.Parse(colors[1]) / 255.0f,
b = float.Parse(colors[2]) / 255.0f,
a = float.Parse(colors[3]) / 255.0f
};
objectRenderer.material.color = matColor;
}

Pause and resume thread activity

I have a thread that adds points onto a zedgraph component on a certain time interval. I need to pause the adding of the points on pressing a check box and then resume adding them when the checkbox is pressed again. The following is what I have for thread:
public class myThread{
ManualResetEvent pauseResumeThread = new ManualResetEvent(true);
public void threadHeartrateGraph()
{
for (int k = 15; k < _hr.Length; k++)
{
pauseResumeThread.WaitOne();
if (HRDataSummary.threadPause == true)
{
break;
}
x = k;
y = _hr[k];
list1.Add(x, y);
_displayHRGraph.Invoke(list1, graph_HeartRate, _GraphName[0]);
graph_HeartRate.XAxis.Scale.Min = k-14;
graph_HeartRate.XAxis.Scale.Max = k+1;
Thread.Sleep(_interval * 1000);
}
}
catch (NullReferenceException)
{
}
}
public void play()
{
pauseResumeThread.Set();
}
public void pause()
{
pauseResumeThread.Reset();
}
}
And then, I have called for the play and pause thread from a checkbox.
private void checkBoxPause_CheckedChanged(object sender, EventArgs e)
{
if(checkBoxPause.Checked == true)
{
//HRDataSummary.threadPause = true;
checkBoxPause.Text = "Play >";
myThread mythread = new myThread();
Thread pause = new Thread(mythread.pause);
pause.Start();
}
if (checkBoxPause.Checked == false)
{
//HRDataSummary.threadPause = false;
checkBoxPause.Text = "Pause ||";
myThread mythread = new myThread();
Thread play = new Thread(mythread.play);
play.Start();
}
}
What am I missing? Or is it completely wrong use of ManualResetEvent?
First you declare your myThread Object globally (only one!).
myThread heartGraph = new myThread()
Then you want to start your Worker-Method in a new Thread.
Thread worker = new Thread(heartGraph.threadHeartrateGraph);
worker.Start();
Now you can use your ManualResetEvent to Pause/Resume the work.
if (checkBoxPause.Checked == true) {
//HRDataSummary.threadPause = true;
checkBoxPause.Text = "Play >";
heartGraph.pause();
} else {
//HRDataSummary.threadPause = false;
checkBoxPause.Text = "Pause ||";
heartGraph.play();
}

Play three sounds simultaneously c#

I want to play three sounds simultaneously, but second sound must play after one seconds, third sound after two seconds. I have this code:
private void Play()
{
AxWindowsMediaPlayer player1 = new AxWindowsMediaPlayer();
player1.CreateControl();
AxWindowsMediaPlayer player2 = new AxWindowsMediaPlayer();
player2.CreateControl();
AxWindowsMediaPlayer player3 = new AxWindowsMediaPlayer();
player3.CreateControl();
player1.URL = "sounds\\1.wav";
player1.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player2.URL = "sounds\\2.wav";
player2.Ctlcontrols.play();
System.Threading.Thread.Sleep(1000);
player3.URL = "sounds\\3.wav";
player3.Ctlcontrols.play();
Why all this sounds are playing in one time after two seconds?
I ended up using SharpDX (available via NuGet packages SharpDX
and SharpDX.XAudio2.
An example of its usage can be found in one of my GitHub projects: 2DAI
You can hear the various sounds overlapping in this screen recording as well.
Playing a sound:
var backgroundMusicSound = new AudioClip(#".\Assets\Sounds\Music\Background.wav" /*Sound path*/, 1.0 /* Volumne*/, true /*Loop Forever?*/)
backgroundMusicSound.Play();
The class that I pieced together:
public class AudioClip
{
private XAudio2 _xaudio = new XAudio2();
private WaveFormat _waveFormat;
private AudioBuffer _buffer;
private SoundStream _soundstream;
private SourceVoice _singleSourceVoice;
private bool _loopForever;
private bool _isPlaying = false; //Only applicable when _loopForever == false;
private bool _isFading;
private string _wavFilePath; //For debugging.
private float _initialVolumne;
public AudioClip(string wavFilePath, float initialVolumne = 1, bool loopForever = false)
{
_loopForever = loopForever;
_wavFilePath = wavFilePath;
_initialVolumne = initialVolumne;
var masteringsound = new MasteringVoice(_xaudio); //Yes, this is required.
var nativefilestream = new NativeFileStream(wavFilePath,
NativeFileMode.Open, NativeFileAccess.Read, NativeFileShare.Read);
_soundstream = new SoundStream(nativefilestream);
_waveFormat = _soundstream.Format;
_buffer = new AudioBuffer
{
Stream = _soundstream.ToDataStream(),
AudioBytes = (int)_soundstream.Length,
Flags = BufferFlags.EndOfStream
};
if (loopForever)
{
_buffer.LoopCount = 100;
}
}
public void Play()
{
lock (this)
{
if (_loopForever == true)
{
if (_isPlaying)
{
if (_isFading)
{
_isFading = false;
_singleSourceVoice.SetVolume(_initialVolumne);
}
return;
}
_singleSourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
_singleSourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
_singleSourceVoice.SetVolume(_initialVolumne);
_singleSourceVoice.Start();
_isPlaying = true;
return;
}
}
var sourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
sourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
sourceVoice.SetVolume(_initialVolumne);
sourceVoice.Start();
}
public void Fade()
{
if (_isPlaying && _isFading == false)
{
_isFading = true;
(new Thread(FadeThread)).Start();
}
}
private void FadeThread()
{
float volumne;
_singleSourceVoice.GetVolume(out volumne);
while (_isFading && volumne > 0)
{
volumne -= 0.25f;
volumne = volumne < 0 ? 0 : volumne;
_singleSourceVoice.SetVolume(volumne);
Thread.Sleep(100);
}
Stop();
}
public void Stop()
{
if (_loopForever == true)
{
if (_singleSourceVoice != null && _isPlaying)
{
_singleSourceVoice.Stop();
}
_isPlaying = false;
_isFading = false;
}
else
{
throw new Exception("Cannot stop overlapped audio.");
}
}
}
It should also be notes that loading the sounds can be a heavy process, so if you are doing it a lot then you might want to cache them as I did:
private Dictionary<string, AudioClip> _audioClips { get; set; } = new Dictionary<string, AudioClip>();
public AudioClip GetSoundCached(string wavFilePath, float initialVolumne, bool loopForever = false)
{
lock (_audioClips)
{
AudioClip result = null;
wavFilePath = wavFilePath.ToLower();
if (_audioClips.ContainsKey(wavFilePath))
{
result = _audioClips[wavFilePath];
}
else
{
result = new AudioClip(wavFilePath, initialVolumne, loopForever);
_audioClips.Add(wavFilePath, result);
}
return result;
}
}

Communication between objects in C# issue

I'm trying to provide communication between two objects that can be best described as turn - based. What I mean by that is that the first object(a Game class) has multiple goals which are specified in a database, and the second object represents a class that is used to play animations from sprite sheets. My goal currently is to show an introductory animation in the Game class(that I have done), show the player his first goal. Then the class expects user input in the form of animation parameters which are then passed as a list to be animated.
Once the animation is complete, I check if the goal is met. If it is met, and it is not the last one, I need to go back to the Game class, show the next goal, play a sort off explanation, then expect user input and this repeats until all goals are satisfied.
This is Windows Phone 8.1 Silverlight.
Here is the code of the Game class(most relevant snippets):
public Game(GamePage gp, int chapterNum)
{
currentClickedCommand = null;
currentClickedSlot = null;
gamePage = gp;
chapterNumber = chapterNum;
isAnimationComplete = false;
//chosenCommands = new string[5];
gamePage.characterRectangle.Visibility = System.Windows.Visibility.Collapsed;
Thread AnimationThread = new Thread(playIntroAnimation);
AnimationThread.Start();
Thread loadingThread = new Thread(loadControls);
loadingThread.Start();
}
These two threads are used to play the animation(animation thread), and the other one waits for a static variable to be set to true to load user input controls. The code:
private void loadControls()
{
while (!InformationObject.isSequenceComplete) { }
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// loadGoals();
showCurrentGoal();
gamePage.CommandGrid.Visibility = System.Windows.Visibility.Visible;
gamePage.SlotGrid.Visibility = System.Windows.Visibility.Visible;
gamePage.mainCanvas.Background = null;
gamePage.characterRectangle.Visibility = Visibility.Collapsed;
loadCommands();
loadSlots();
});
}
This is the method which plays the animation sequence that the user selected:
public void AnimateCurrentAnimationInSequence(Rectangle container) {
AnimationParams currentParams = sequenceToAnimate[currentAnimationInSequence];
DoubleAnimation fadeInAnimation = new DoubleAnimation();
fadeOutAnimation = new DoubleAnimation();
if (sequencePlayerInteractions.Count != 0 && sequencePlayerInteractions != null)
{
PlayerInteraction currentInteraction = sequencePlayerInteractions[CurrentInteraction];
TalkBubble interactionBubble = new TalkBubble(currentInteraction.Value);
interactionBubble.setWidthHeight((int)container.Width, (int)container.Height);
talkBubble = interactionBubble;
onCanvas.Children.Add(talkBubble);
Canvas.SetLeft(talkBubble, Canvas.GetLeft(container) + 30);
Canvas.SetTop(talkBubble, Canvas.GetTop(container) + 30);
}
// ovdje razdvojiti po tipu
if (!currentParams.IsMoveType)
{
ImageBrush imageBrush = new ImageBrush() { Stretch = Stretch.None, AlignmentX = AlignmentX.Left, AlignmentY = AlignmentY.Top };
imageBrush.Transform = new CompositeTransform();
imageBrush.ImageSource = currentParams.Sheet;
container = setRectangleProperties(container, currentParams.Width, currentParams.Height, imageBrush);
// Storyboard za animaciju
Storyboard sb = new Storyboard();
if (currentParams.Loop) sb.RepeatBehavior = RepeatBehavior.Forever; // odredjujem da li je na repeat
// Animacija za talk bubble
if (sequencePlayerInteractions.Count != 0 && sequencePlayerInteractions != null)
{
fadeInAnimation.From = 0.0;
fadeInAnimation.To = 1.0;
fadeInAnimation.Completed += new EventHandler(fadeIn_complete);
fadeInAnimation.FillBehavior = FillBehavior.HoldEnd;
Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(UIElement.OpacityProperty));
Storyboard.SetTarget(fadeInAnimation, talkBubble);
}
// Animacija sheeta preko frameova
int time = 0; // vrijeme kojim odredjujem trajanja frameova
ObjectAnimationUsingKeyFrames frm = createFrames(currentParams.Repetitions, time, currentParams.Width, currentParams.NumberOfFrames); // inicijaliziram frameove animacije sheeta
frm.BeginTime = new TimeSpan(0, 0, 0);
fadeInAnimation.Duration = TimeSpan.FromMilliseconds(400);
Storyboard.SetTarget(frm, container.Fill);
Storyboard.SetTargetProperty(frm, new PropertyPath("(ImageBrush.Transform).(CompositeTransform.TranslateX)"));
sb.Children.Add(frm);
if (sequencePlayerInteractions.Count != 0 && sequencePlayerInteractions != null) sb.Children.Add(fadeInAnimation);
sb.Completed += new EventHandler(animationInSequence_Complete);
sb.Begin();
}
else {
cameFromSequenceAnimate = true;
AnimateMove(container, currentParams.Direction, currentParams.Steps);
}
}
private void animationInSequence_Complete(object sender, EventArgs e)
{
if (!(currentAnimationInSequence + 1 == animationCount))
{
if (sequencePlayerInteractions.Count != 0 && sequencePlayerInteractions != null) { if (!(CurrentInteraction + 1 == interactionCount)) CurrentInteraction++; }
currentAnimationInSequence++;
AnimateCurrentAnimationInSequence(currentContainer);
}
else
{
// Goal satisfaction
if (CurrentCommandIDs != null && CurrentCommandIDs.Count != 0)
{
bool has = true;
List<string> sequenceID = new List<string>();
foreach (AnimationParams ap in sequenceToAnimate) sequenceID.Add(ap.AnimationID);
for (int i = 0; i < CurrentCommandIDs.Count; i++)
{
if (!sequenceID.Contains(CurrentCommandIDs[i])) has = false;
}
if (has) { InformationObject.isCriteriaMet = true;
InformationObject.setCurrentGoal(InformationObject.currentGoal + 1);
}
else InformationObject.isCriteriaMet = false;
}
KidCode.Game.isSequenceComplete = true;
InformationObject.isSequenceComplete = true;
currentAnimationInSequence = 0;
CurrentInteraction = 0;
}
}
Now, after the animation is done, I need to somehow return back to the game class to basically repeat this. I tried using a static class(InformationObject)
to store information about current goals but I wasn't able to utilize it
Thanks for any help!

Iterating through an array and play notes

I have an array which is populated by MusicNotes. Each MusicNote is an object with it's properties, e.g. pitch and duration. Duration is created using a timer in the MusicNote class.
The problem is that when I iterate through the array and play all the sounds the duration of each MusicNote is lost and it will play the whole wav file (for each note).
I know that the problem is related to the timer and I know that it maybe related to the Play() method in the MusicNote but I don't have any ideas on how to fix it. I have posted my the code related to this problem.
public class MusicNote : PictureBox
{
Timer tmr1 = new Timer();
int tmr1duration;
public SoundPlayer sp = new SoundPlayer();
public Timer tmr = new Timer();
public int pitch; //The no. of the music key (e.g. the sound freuency).
public int noteDuration; //Shape of note.
public string noteShape;
static int xLoc = 0;
int yLoc = 100;
public MusicNote(int iPitch, int iNoteDuration)
: base()
{
pitch = iPitch;
noteDuration = iNoteDuration;
Size = new Size(40, 40);
this.BackColor = Color.Transparent;
this.MouseClick += new MouseEventHandler(MusicNote_MouseClick);
this.MouseDown += new MouseEventHandler(MusicNote_MouseDown);
this.MouseUp += new MouseEventHandler(MusicNote_MouseUp);
tmr1.Tick += new EventHandler(tmr1_Tick);
tmr.Tick += new EventHandler(ClockTick);
}
public void ShowNote()
{
if (this.noteDuration == 1) noteShape = "Quaver.png";
if (this.noteDuration == 4) noteShape = "Crotchet.png";
if (this.noteDuration == 7) noteShape = "minim.png";
if (this.noteDuration == 10) noteShape = "DotMin.png";
if (this.noteDuration == 12) noteShape = "SemiBreve.png";
this.BackgroundImage = Image.FromFile(noteShape);
this.BackColor = Color.Transparent;
Location = new Point(xLoc, yLoc);
xLoc = xLoc + 40;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
public void Play()
{
sp.SoundLocation = this.pitch + ".wav";
sp.Play();
//Timer to play the duration
this.tmr.Interval = 100 * this.noteDuration;
this.tmr.Start();
}
void ClockTick(object sender, EventArgs e)
{
sp.Stop();
tmr.Stop();
}
private void MusicNote_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Play();
}
}
}
}
And this is the class were I have the array...
public class MusicStaff: Panel
{
public ArrayList musicNotes = new ArrayList(); //Array to store the Music Notes.
SoundPlayer sp = new SoundPlayer();
public void AddNote(MusicNote newNote) //Method to add the notes.
{
musicNotes.Add(newNote);
}
public int ListSize()
{
return musicNotes.Count; //Returns the size of the list.
}
public void PlayAll()
{
foreach (MusicNote m in musicNotes)
{
m.Play();
}
I have removed some code from the classes which is not replated to the problem so that question is not too long. Any help how can I solve this would be greatly appreciated. Tks.
Try something like this:
public void PlayAll()
{
foreach (MusicNote m in musicNotes)
{
m.sp.Stop();
m.sp.PlaySync();
Thread.Sleep(m.noteDuration); //duration should be in milliseconds
}
}
Should this work you can remove your timer completely.
I suggest you look into the use of Properties in C# to not let fields be public.
By the way I did this assignment two years ago :)

Categories

Resources