I'm making a simple c# game similar to snake, and I have two moving aspects. I have a method to move both of them, however I want them to both move at different speeds. Here's a cut down version of the method I have now.
private async void mover()
{
while (GlobalVar.Status == "alive")
{
if (GlobalVar.Direction == "up")
{
try { moveupp(GlobalVar.Row, GlobalVar.Column, "player"); }
catch (System.IndexOutOfRangeException) { died(); }
}
if (GlobalVar.OppDirection == "up")
{
try { moveupp(GlobalVar.Row, GlobalVar.Column, "opp1"); }
catch (System.IndexOutOfRangeException) { died(); }
}
await Task.Delay(500);
}
}
Here, in the first IF statement, my character (player) is moving up, and in the second IF statement, the opponent (opp1) is moving up. These are working in sync with a 500 millisecond delay in between with the delay "await Task.Delay(500);".
My question is, is there anyway they can both run together, with different delays in between? So the opp1 can move faster than the player?
Many thanks in advance!
I would use two different timers instead of delaying tasks. Also I would not use exceptions to control program flow:
private PlayerTimer_Tick(object sender, EventArgs e)
{
if (GlobalVar.Status != "alive")
return; // you can also stop timer in this case
if (GlobalVar.Direction == "up")
{
if (GlobalVar.Column == 0)
died();
else
moveupp(GlobalVar.Row, GlobalVar.Column, "player");
}
}
Also create timer for opp1 and set different intervals for these timers - 500 for player and another value for opp1.
Related
In the game I am trying to make. When I am holding my fire button and I pick up a power up SuperShot, it continues to fire my regular laser unless I release my fire button and press it again. The same thing happens again when the power up ends. I have researched and I cant seem to figure out a way to check on where the power up is active while holding the key down.
private void Fire()
{
if (Input.GetButtonDown("Fire1"))
{
if (SuperShotIsActive)
{
superShotFiringCoroutine = StartCoroutine(SuperShotFireContinuously());
}
else if (!SuperShotIsActive)
{
firingCoroutine = StartCoroutine(FireContinuously());
}
}
if (Input.GetButtonUp("Fire1"))
{
StopCoroutine(firingCoroutine);
StopCoroutine(superShotFiringCoroutine);
}
}
You might be able to fix this by looking away from the button itself and into the code of the actual firing of the weapon.
//psuedocode-ish example. Just for the concept
//not necessarily the best idea to use a for loop but maybe it works for you.
FireContinuously()
{
for(int foo = 0; foo < ammo; foo++)
{
if(!SuperShotIsActive)
{
//normal firing code you have goes here
}
else
{
//supershot code goes here
}
}
}
In FireContinuously() (which I assume is a loop of some sort) you can add a check before each shot to see if the player now has the powerup and the necessary logic to change to the appropriate SuperShotFireContinuously(). Do the opposite for SuperShotFireContinuously() to change to FireContinuously().
I'm making a system to balance calls inside of the OnGUI method of a EditorWindow.
I'm doing the following:
public void Update()
{
Repaint();
}
Inside of my OnGUI method I'm calling this Balancer. I have one list with the callbacks (List).
So the idea is simple, some callvaxc
I'm skipping some repaint frames for the callback that has the complete GUI, and calling on each repaint for other callbacks (for example, a marquee label or dispalying gifs).
By some reason, this error happens "Getting control 0's position in a group with only 0 controls when doing repaint"
private int m_repaintCounter;
public void Draw()
{
Event e = Event.current;
try
{
foreach (var action in m_actions)
{
try
{
// Test 1
// MainAction is a class that inherits from Action (class MainAction : Action)
if (action is MainAction)
{
bool isDesignedType = e.rawType == EventType.Repaint || e.rawType == EventType.Layout;
if (isDesignedType)
++m_repaintCounter;
if (!(m_repaintCounter == 20 && isDesignedType))
continue;
else
m_repaintCounter = 0;
}
// Test 2
action.Value();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
catch
{
// Due to recompile the collection will modified, so we need to avoid the exception
}
}
But if I comment the "Test 1" everythings works fine.
On the ctor of the class we need to specify a callback to a GUI method, for example:
public Balancer(Action drawAction)
{
m_actions = new List<Action>();
m_actions.Add(drawAction);
}
So we could do easily (inside the EditorWindow):
private Balancer m_balancer;
public void OnEnable()
{
m_balancer = new Balancer(Draw);
}
public void Draw()
{
// This block will be called every 20 repaints as specified on the if statment
GUILayout.BeginHorizontal("box");
{
GUILayout.Button("I'm the first button");
GUILayout.Button("I'm to the right");
// This marquee will be called on each repaint
m_balancer.AddAction(() => CustomClass.DisplayMarquee("example"));
}
GUILayout.EndHorizontal();
}
// Inside of the Balancer class we have
// We use System.Linq.Expressions to identify actions that were added already
private HashSet<string> m_alreadyAddedActions = new HashSet<string>();
public void AddAction(Expression<Action> callback)
{
if(!m_alreadyAddedActions.Add(callback.ToString()))
return;
m_actions.Add(callback.Compile());
}
I can't figure this out. I couldn't find any information on the internet. Can anyone help me?
Ok, so, OnGui (IMGui) is awful to work with. If you aren't using it for an editor script, use the new 4.6 UI (UGui) instead.
Now then. The problem.
OnGui is called at least twice every frame. One of those is to calculate layouts and the other is to actually draw stuff ("repaint").
If the number of things, size of things, or anything else changes between these two calls then Unity will error with "Getting control 0's position in a group with only 0 controls when doing repaint."
That is: you cannot change UI state in the IMGui system at any point after Layout and before Repaint.
Only, only, only change state (and thereby which objects are being drawn) during Event.current == EventType.Repaint and only, only, only change state for the next frame (alternatively, do the changes during Event.current == EventType.Layout, provided that this same, new state will result in the same code path during Repaint). Do not, under any circumstances, make changes during Repaint that were not present during the previous Layout.
I have an audio player that loads a configuration file with a list of files to be played at certain intervals. Like 5 files should be looped between 09:30 and 11:30 - it is an application for libraries where they need the background music.
When im outside of an interval, i loop through all my time intervals (there might be 2 hours before next interval starts) and then if i find that nothing is to be played right now - i sleep for a second and then try again.
I have a problem where i get a stack overflow after around 3-4 hours of checking for these time intervals (often at nights, because the clients are on, but no music should be playing at night).
private void PlayNextFile()
{
Application.DoEvents();
if (currentState == PlayerState.Started)
{
//if we find the next slide then play it
AudioSlide slideToPlay = FindNextSlide();
if(slideToPlay != null)
{
PlaySlide(slideToPlay);
}
else
{
MedianLog.Log.Instance.LogDebug("Did not find a slide to play now, will check again in a second");
System.Threading.Thread.Sleep(1000);
PlayNextFile();
}
}
}
Any idea on how to get around this exception?
You just filling up your stack with not controlled recursive calls.
A while loop would be a better solution.
Something like that should do it correctly:
private async void PlayNextFile()
{
while (true)
{
if (currentState == PlayerState.Started)
{
//if we find the next slide then play it
AudioSlide slideToPlay = FindNextSlide();
if (slideToPlay != null)
{
PlaySlide(slideToPlay);
return;
}
MedianLog.Log.Instance.LogDebug("Did not find a slide to play now, will check again in a second");
await Task.Delay(1000);
}
else
{
return;
}
}
}
First of all my question is quite complicated (for me) and I try to explain.
I have a WPF application which is working with NFC tags. Couple days ago this code was worked properly but now somethings messed up.
First I have a method which is reading data from NFC tag like this:
private void NFCCard_OnCardInserted()
{
CheckCard();
}
private bool CheckCard()
{
try
{
lock (_object)
{
NFCCard.Connect(CardReader, SHARE.Shared, PROTOCOL.T0orT1);
APDUPlayer player = new APDUPlayer(ApduListFile, NFCCard);
if (nfcFunction.NFCLogin(player))
{
string TempCompanyID = "";
//--Read data
}
DateTime cartOpenedDate = Convert.ToDateTime(OpenedDate);
if (CartNo == "" || CompanyID.ToString() == "" || Convert.ToInt32(limit) <= 0 || isactive == "False" || cartOpenedDate.ToShortDateString() != DateTime.Today.ToShortDateString() || CartType == "Staff")
{
Dispatcher.BeginInvoke(new Action(delegate
{
ShowCardNo(txtCardNo, "Geçersiz Kart!");
}));
}
else
{
//-- Some internal code
}
}
}
catch (Exception exc)
{
StationSession.WriteLog("write log bla bla", exc);
}
}
Now is the funny thing when I check the threads windows of VS two same thread try to run NFCCard_OnCardInserted() method at same time.
For this reason I put lock state but the problem is this method firing two times. And its make big trouble for me because the card transaction time is being double right now (almost 3 second for some transaction. I cannot explain to people you will wait with cart at cart reader like this :/ ). By the way I check whole page for this method reference, just this code should use this method.
NFCCard.OnCardInserted += new CardInsertedEventHandler(NFCCard_OnCardInserted);
So how can I fix this problem without workaround. Because I have several page and method which is using NFC cart thread. I need to find clear way for this problem. Thanks.
As the title suggests, I'm new to the concept of threading and I'm learning as I go. I'm working on a program as part of a research project involving a 3D printer. I have two pieces of hardware I need to interface with: a small stage that moves up and down, and a force sensor that can detect when an object on the stage makes contact with the sensor which acts as the signal to stop moving the stage. As I said, I'm new to the whole threading concept, so I'm not even sure if I'm designing this correctly, if I should use backgroundworker or the Thread class, how to ensure thread-safety, etc.
I"m writing the program in C# using Windows Forms and decided to use two background worker controls in Visual Studio/.NET Framework, one to monitor the force sensor reading and the other to control the stage moving up and down.
It has to be fast and accurate; the stage needs to stop moving the moment a pre-defined sensor value is detected. I have two static classes, a ZStageControl static class and a ForceSensorControl static class.
ForceSensorControl has a method called UpdateSensor() which returns the current value of the force sensor, and the ZStageControl has a private static bool variable, forceDetected (set to false by default), a public property ForceDetected that gets/sets this variable, and a method called GoodToMove. GoodToMove is defined as follows:
public static bool GoodToMove()
{
if (forceDetected == true ||
Position() < MinHeight ||
Position() > MaxHeight)
return false;
else
return true;
}
My sensor update backgroundworker dowork code is defined as follows:
private void sensorUpdateBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
double currentForceValue;
while (ForceSensorControl.IsConnected() == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
try
{
currentForceValue = Double.Parse(ForceSensorControl.UpdateSensor());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
disconnectForceSensor();
return;
}
if (currentForceValue >= forceSensorStopValue)
{
if (this.ForceDetected != null)
{
this.ForceDetected(this,
new ForceDetectedEventArgs(ZStageControl.Position(), currentForceValue));
}
}
else if (ZStageControl.ForceDetected == true)
ZStageControl.ForceDetected = false;
forceSensorValueLabel.Text = currentForceValue.ToString() + "g";
}
}
}
So as long as the sensor remains connected, continuously loop and update the force sensor vlaue. If it detects the proper force value, it fires the ForceDetected event. If it reads the value as less than the force sensor stop value, but ForceDetected is still set to true, it simply sets to false (since when the force is detected, it will stop the stage from moving and then return it to its default position, so it should reset the force detected variable).
The event code is defined as follows:
public void FormMain_ForceDetected(object sender, ForceDetectedEventArgs e)
{
if (ZStageControl.ForceDetected == true)
return;
ZStageControl.ForceDetected = true;
feedbackRichTextBox.Text += "\nForce Detected at position " +
e.ForceDetectedPosition.ToString() + " with a value of " +
e.ForceDetectedValue.ToString() + "\n";
ScrollToEndOfFeedbackBox(feedbackRichTextBox);
soundPlayer.Play();
}
The thread to move the Z-Stage up or down is defined as follows:
private void zStageMoveBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ZStageMoveDirections direction = (ZStageMoveDirections)e.Argument;
while (ZStageControl.IsConnected == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(zStageSpeed);
if (direction == ZStageMoveDirections.Down)
{
ZStageControl.MoveDown(true);
}
if (direction == ZStageMoveDirections.Up)
{
ZStageControl.MoveUp(true);
}
zStagePositionUpdateLabel.Text = ZStageControl.Position().ToString();
}
}
}
The code that calls the DoWork event for the Z-Stage move is controlled by an if statement that checks if ZStageControl.GoodToMove() is true. So while GoodToMove() returns true, the Z-Stage thread can fire.
The issue I'm having is that I'm not sure if I'm designing this right, if I'm using the backgroundworker properly, and I know my variables are not thread-safe because at certain points GoodToMove() returns true and other times it returns false, even though there is clearly no force being detected. It seems to have a mind of its own. I just know nothing about thread-safety. Should I simply use the THread class instead of the background worker, is there a certain way to ensure the forceDetected variable/GoodToMove() method operates properly across these threads?
I think your approach is inherently flawed.
You seem to be designing a system with a constantly looping monitor and then a check of that monitor when you want to execute a "move."
This is inherently problematic because you've created a race condition between your safety check operation and your move operation.
Consider this:
1 // check if move is ok -- PASS
(async) // move suddenly becomes not ok!
2 // move is executed
Instead you should think about this problem as entirely synchronous (as validation checks and executions should be entirely atomic). Whenever a move is requested you should check if it's permitted and then decide whether or not to execute.
1 // exclusive lock
2 // check if move is ok -- PASS
3 // execute move
4 // release lock