Im working on a game in which I have a canon that fires at difrent amounts of time. Instead of writing a long if statement like this:
If (time == 1) {
"Do something "
} else If (time == 2) {
"Do something else "
} else If (time == 3) {
" You probaly get the point"
} else {
" My real problem is much longer than this. This is just.
an.
example"
}
So if there is an easier and prettier way to do this in c# that would be great. If not let me know also. Thanks in advance
As mentioned in the comments
Using a Switch Statement is probably what you're looking for.
private static void FireCanons(int time)
{
switch (time)
{
case 1:
// "do something";
break;
case 2:
// do something else
break;
case 3:
// you probably get the point"
break;
default:
// My real problem is much longer than this. This is just. an. example"
break;
}
}
Update:
Just looking at your comments, a Dictionary may be better suited.Here is a quick example I have made.
private static void FireCanons(int time)
{
// A Dictionary That Will Hold Our Results.
var myList = new Dictionary<int, string>
{
{ 1, "do something" },
{ 2, "do something else" },
{ 3, "you probably get the point" },
{ 4, "My real problem is much longer than this. This is just. an. example" }
};
// Attempt To Get The Value.
if (myList.TryGetValue(time, out string result))
{
// Display Results.
Console.WriteLine(result);
}
}
Dictionary is another approach. Create Dictionary where you can register different actions for every value of time
void DoSomething()
{
// Do something
}
void DoSomethingElse()
{
// Do else
}
void YouProbalGetThePoint()
{
// You probaly get the point
}
Register actions
var actions = new Dictionary<int, Action>
{
{ 1, DoSomething },
{ 2, DoSomethingElse },
{ 3, YouProbalGetThePoint },
{ 4, DoSomething },
}
Then usage can be one liner:ish
var action = actions.GetValueOrDefault(time, () => {});
action();
Such approach provide possibility to change behaviour of your code without changing the code in the function - Open-Close Principle ;)
The current answers are fine ... to answer your question if time actually is an int value.
This is just a guess but usually when you spak about time you have a float value as e.g. from Time.time.
For this your approach using ==, a switch and a dictionary as well would be completely useless since the odds that an exact time of e.g. 2.0 is matched in a certain frame is very close to 0. (not even speaking about the single floating point precision here...)
For this you rather might want to have a look at Coroutines and WaitForSeconds
You can create an Extension method
public static class MonoBehaviourExtensions
{
public static void Invoke(this MonoBehaviour me, Action theDelegate, float time)
{
me.StartCoroutine(ExecuteAfterTime(theDelegate, time));
}
private static IEnumerator ExecuteAfterTime(Action theDelegate, float delay)
{
yield return new WaitForSeconds(delay);
theDelegate?.Invoke();
}
}
and than simply use e.g.
private void Start()
{
this.Invoke(DoSomething, 1);
this.Invoke(DoSomethingElse, 2);
this.Invoke(YouGetThePoint, 3);
}
// will be executed 1 second after start
private void DoSomething()
{ ... }
// will be executed 2 seconds after start
private void DoSomethingElse()
{ ... }
// will be executed 3 seconds after start
private void YouGetThePoint()
{ ... }
If you than want those to be executed again after a ceratin delay you could simply add a new call at the end like e.g.
private void DoSomething()
{
...
this.Invoke(DoSomething, 1);
}
or alternatively add another extension method to do so:
public static class MonoBehaviourExtensions
{
public static void Invoke(this MonoBehaviour me, Action theDelegate, float time)
{ ... }
private static IEnumerator ExecuteAfterTime(Action theDelegate, float delay)
{ ... }
public static void InvokeRepeated(this MonoBehaviour me, Action theDelegate, float timeInterval)
{
StartCoroutine(ExecuteInIntervals(theDelegate, interval));
}
private static IEnumerator ExecuteInIntervals(Action theDelegate, float interval)
{
while(true)
{
yield return new WaitForSeconds(interval);
theDelegate?.Invoke();
}
}
}
and than use instead
private void Start()
{
this.InvokeRepeated(DoSomething, 1);
this.InvokeRepeated(DoSomethingElse, 2);
this.InvokeRepeated(YouGetThePoint, 3);
}
so DoSomething is called every second, DoSomethingElse is called every 2 seconds and YouGetThePoint is called every 3 seconds.
Related
I have an EventSystem for managing my turn-based game in Unity.
public class EventSystem : MonoBehaviour
{
private static List<Action> _commandsQueue = new List<Action>();
private bool _canExecuteCommand = true;
public void AddToQueue(Action command)
{
_commandsQueue.Add(command);
}
private void StartCommandExecution()
{
_commandsQueue[0]();
_canExecuteCommand = false;
}
public void CommandExecutionComplete()
{
_canExecuteCommand = true;
}
public void PlayFirstCommandFromQueue()
{
if (_commandsQueue.Any() && _canExecuteCommand)
{
StartCommandExecution();
}
else
{
Debug.LogError("No Command In Queue");
}
}
}
How do I put a method in Update() until _canExecuteCommand is true again but only for some methods?
It is quite broad what you are trying to do but in general you would use an endless loop within a Coroutine.
You can create a generic routine which invokes any Action you pass in as parameter once a frame like e.g.
private IEnumerator InvokeEveryFrame(Action action)
{
// This looks strange but is okey in a Coroutine as long as you yield somewhere within
while(true)
{
action?.Invoke();
// This tells Unity to "pause" this routine here
// render the current frame and continue from here in the next frame
yield return null;
}
}
So all that's left is starting the routine using MonoBehaviour.StartCoroutine like e.g.
Coroutine routine = StartCoroutine(SomeParameterlessMethod);
or if you need parameters
Coroutine routine = StartCoroutine(() => SomeMethod(x, y, z));
and then at some point later stop it using MonoBehaviour.StopCoroutine and the stored Coroutine reference like e.g.
StopCoroutine(routine);
how exactly you store that reference is up to you of course up to you.
I want to do something like this:
function void DoSomething(string path){
try {
DownloadDataFromWebSite(path)
}catch(OtherUserLoggedInUsingSameAcountException ex){
If (I am the first thread that get here){
Login();
}else{
Wait for the first thread to finish Login();
}
DownloadDataFromWebSite(path);
}
}
I have a collection that I will call like this:
APathCollection.AsParallel().ForAll(DoSomething)
Please help me, How can I implement this pattern? Is it possible?
PS: I have omitted the error counter, please assume it will not get into an infinite recurring.
Update: I have updated the code to reflect what I am really doing on #IPValverde request.
OK, you gave more information on your scenario. I think you can create a second lock indicating if one of your threads are logging-in.
Here is a snippet:
public class Program
{
public static void Main()
{
new Program().Execute();
}
public void Execute()
{
// lock objects
this.fixErrorLock = new object();
this.isLoggingInLock = new object();
var objectsToIterate = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
objectsToIterate.AsParallel().ForAll(this.DoWork);
}
private object isLoggingInLock;
private object fixErrorLock;
private bool isLoggingIn;
public bool IsThereAnyThreadLoggingIn()
{
lock (this.isLoggingInLock)
{
// If no thread is logging-in, the one who asked is going to log-in
if (!this.isLoggingIn)
this.isLoggingIn = true;
return this.isLoggingIn;
}
}
public void DoWork(int myParam)
{
try
{
if (myParam % 4 == 0)
throw new Exception();
}
catch (Exception ex)
{
// Is the equivalent of 'is the first thread to hit here?'
bool canLogIn = this.IsThereAnyThreadLoggingIn();
// Every thread with error will stop here
lock (fixErrorLock)
{
// But only the first one will do the login process again
if (canLogIn)
{
// Inside the login method the variable responsible for the 'isFirstThread' is restored to false
this.LogIn();
}
}
this.DoWork(myParam-1);
}
}
public void LogIn()
{
Thread.Sleep(100);
lock (this.isLoggingInLock)
{
// The login is done
this.isLoggingIn = false;
}
}
}
You can see this example running here: https://dotnetfiddle.net/SOXxO9
When you are talking about thread safety, it's the resources that are important.
So first read about lock, especially the parts referring to critical sections.
Then, create a lock for each "logical" resource in the FixparticularException method and you should be fine. If you give some particulars I could write the code for you more explicitly, bit here is the gist:
private bool _IsFixed;
public void DoSomething(int x)
{
try
{
DoWork(x)
}
catch (ParticularException pex)
{
FixParticularException(pex);
}
DoSomething(x);
}
private void FixParticularException (ParticularException pex)
{
lock (_resource1Lock)
{
if (_IsFixed)
return;
// fix it
_IsFixed = true;
}
}
I want a Character class, inheriting from MonoBehavior and exposing handfuls methods : Walk, Attack, ...
However, assuming that two components use these methods at the same time, I would like to queue the actions and have some way to notify the components that their actions have been executed.
In Javascript standard, I would have done something like this :
var Character = function ( ) {
this._deferred = new Deferred( );
};
Character.prototype.walk = function ( ) {
return this._deferred = this._deferred.then( function ( ) {
// Do the actual walk
} );
};
Character.prototype.attack = function ( ) {
return this._deferred = this._deferred.then( function ( ) {
// Do the actual attack
} );
};
var character = new Character( );
// Component A
character.walk( ).then( function ( ) {
// Executes when the walk is done
} );
// Component B
character.attack( ).then( function ( ) {
// Executes when the walk AND attack is done
} );
What is the right way to do so with Unity / C# ?
Preamble
For the answer I will use this "I would like to queue the actions" as a description of your problem.
There are lot of ways to solve this problem. And I don't pretend to be comprehensive.
Even in JS I would consider using Promises for queuing character commands as wrong choice.
I haven't ever compiled, run or tested the code that i present here :D
Promises in C#
There is some C# port of Promises on github. I haven't ever used it, but the code doesn't seem to contain anything that stops it from being used in Unity. Anyway, you can give it a try.
Using Queue<>
I would definitely use Queue<TCommand> of some TCommand for this problem. The only question is what to use as TCommand. I will give you 2 examples here. But, as usual, there are more options.
Some class
Something like this:
public enum CommandUpdateResult
{
Ongoing,
Finished
}
public interface ICommand
{
CommandUpdateResult Update();
}
public class RunCommand: ICommand
{
// Bla-bla-bla
}
public class AttackCommand: ICommand
{
// Bla-bla-bla
}
public class Character: MonoBehaviour
{
private Queue<ICommand> commandQueue;
public void Awake()
{
commandQueue = new Queue<ICommand>();
}
public void Update()
{
if (commandQueue.Count > 0 && commandQueue.Peek().Update() == CommandUpdateResult.Finished)
commandQueue.Dequeue();
}
public void EnqueueCommand(ICommand command)
{
commandQueue.Enqueue(command);
}
}
public class SomeClassThatUsesCharacter
{
private Character character;
public void SomeMethodThatUsesCharacter()
{
character.EnqueueCommand(new RunCommand(bla-bla-bla));
character.EnqueueCommand(new AttackCommand(bla-bla-bla));
}
}
IEnumerator
The simplest (but not very elegant) way to use IEnumerator is to use it with some infinite coroutine.
public class Character: MonoBehaviour
{
private Queue<IEnumerator> commandQueue;
private IEnumerator CommandQueueCoroutine()
{
while (true)
{
if (commandQueue.Count > 0)
yield return StartCoroutine(commandQueue.Peek());
else
yield return new WaitForFixedUpdate();
}
}
public void Awake()
{
commandQueue = new Queue<ICommand>();
StartCoroutine(CommandQueueCoroutine());
}
public void Update()
{
if (commandQueue.Count > 0 && commandQueue.Peek().Update() == CommandUpdateResult.Finished)
commandQueue.Dequeue();
}
public void Enqueue(IEnumerator command)
{
commandQueue.Enqueue(command);
}
IEnumerator RunCommand()
{
while (Jenny.Tells("Run"))
{
transform.position.x += 1;
yield return new WaitForFixedUpdate();
}
}
IEnumerator AttackCommand(BadGuy badGuy)
{
badGuy.Die();
yield break;
}
}
public class SomeClassThatUsesCharacter
{
private Character character;
public void SomeMethodThatUsesCharacter()
{
character.Enqueue(character.RunCommand());
character.Enqueue(character.AttackCommand(someBadGuy));
}
}
A very good Unity Promise library: https://github.com/Real-Serious-Games/C-Sharp-Promise and see related blog http://www.what-could-possibly-go-wrong.com/promises-for-game-development/
Alternatively I think you can also go down an RX approach with Observers that react to Walk and Attack events. See https://github.com/neuecc/UniRx
Well, at the moment Unity already allows you to use:
TaskCompletionSource as a promise;
Task as a future;
but if Promise itself is more suitable for your project give it a try by using: C-Sharp-Cancellable-Promise library
This is a fork of Real-Serious-Games Promise lib updated to the latest .NET and with Promises cancellation support.
I have an assignment to make a thread safe logging class that writes to a file. Every ten frames I am supposed to push some information of my choice to the logging class from a separate script. I was wondering how to do that. Here is my code so far.
public class Threading
{
public bool Execute = true;
public Vector3 player;
public Vector3 WriteTime;
System.Collections.Generic.Queue<float> values;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
public void execute()
{
while (Execute)
{
System.Threading.Thread.Sleep(500);
values.Enqueue(player.x);
UnityEngine.Debug.Log("value");
}
System.IO.StreamWriter write = new System.IO.StreamWriter("values.txt"); // writes to file every 5 seconds
while (values.Count > 0)
{
WriteTime = write.WriteLine(values.Dequeue().ToString());
}
write.Close();
}
public void Lock() // applied Lock threading
{
while(true)
{
lock (this)
{
// dont have anything here yet. Trying to figure out locks
}
}
}
Thank you.
I would like to run code alternatively, so I could stop execution at any moment. Is this code safe?
static class Program
{
static void Main()
{
var foo = new Foo();
//wait for interaction (this will be GUI app, so eg. btnNext_click)
foo.Continue();
//wait again etc.
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
}
}
class Foo
{
public Foo()
{
new Thread(Run).Start();
}
private void Run()
{
Break();
OnRun();
}
protected virtual void OnRun()
{
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
//do something else and break;
}
private void Break()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
public void Continue()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
}
Of course I know, that now the application will never ends, but that's not the point.
I need this, because I would like to present steps in some kind of an algorithm and describe what is going on in particular moment, and making everything in one thread would lead to many complications even when using small amount of loops in the code. For example those lines:
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
should be then replaced with:
if (this.i < 5)
{
Console.WriteLine(i++);
}
And that is just a small example of what I want to present. The code will be more complicated than a dummy for loop.
I recommend you check out this blog post about implementing fibers.
Code (In case the site goes down.)
public class Fiber
{
private readonly Stack<IEnumerator> stackFrame = new Stack<IEnumerator>();
private IEnumerator currentRoutine;
public Fiber(IEnumerator entryPoint)
{
this.currentRoutine = entryPoint;
}
public bool Step()
{
if (currentRoutine.MoveNext())
{
var subRoutine = currentRoutine.Current
as IEnumerator;
if (subRoutine != null)
{
stackFrame.Push(currentRoutine);
currentRoutine = subRoutine;
}
}
else if (stackFrame.Count > 0)
{
currentRoutine = stackFrame.Pop();
}
else
{
OnFiberTerminated(
new FiberTerminatedEventArgs(
currentRoutine.Current
)
);
return false;
}
return true;
}
public event EventHandler<FiberTerminatedEventArgs> FiberTerminated;
private void OnFiberTerminated(FiberTerminatedEventArgs e)
{
var handler = FiberTerminated;
if (handler != null)
{
handler(this, e);
}
}
}
public class FiberTerminatedEventArgs : EventArgs
{
private readonly object result;
public FiberTerminatedEventArgs(object result)
{
this.result = result;
}
public object Result
{
get { return this.result; }
}
}
class FiberTest
{
private static IEnumerator Recurse(int n)
{
Console.WriteLine(n);
yield return n;
if (n > 0)
{
yield return Recurse(n - 1);
}
}
static void Main(string[] args)
{
var fiber = new Fiber(Recurse(5));
while (fiber.Step()) ;
}
}
"...this will be GUI app..."
Then you probably do not want and will not have sequential code like above in Main().
I.e. the main GUI thread will not execute a serial code like above, but generally be idle, repainting, etc. or handling the Continue button click.
In that event handler you may better use an Auto|ManualResetEvent to signal the worker to proceed.
In the worker, just wait for the event.
I would suggest that any time one considers using Monitor.Wait(), one should write code so that it would work correctly if the Wait sometimes spontaneously acted as though it received a pulse. Typically, this means one should use the pattern:
lock(monitorObj)
{
while(notYetReady)
Monitor.Wait(monitorObj);
}
For your scenario, I'd suggest doing something like:
lock(monitorObj)
{
turn = [[identifier for this "thread"]];
Monitor.PulseAll(monitorObj);
while(turn != [[identifier for this "thread"]])
Monitor.Wait(monitorObj);
}
It is not possible for turn to change between its being checked whether it's the current thread's turn to proceed and the Monitor.Wait. Thus, if the Wait isn't skipped, the PulseAll is guaranteed to awaken it. Note that the code would work just fine if Wait spontaneously acted as though it received a pulse--it would simply spin around, observe turn wasn't set for the current thread, and go back to waiting.