I'm creating a calculator in Unity and faced with a problem.So I need to change bool value to write second number of my calculator.
My script attached to all the buttons(GameObjects) in the scene.
I need to change this value to true to write second number of calculator.
private bool input_second_num;
public void Input(){
if (calculate_label.text.Length < 15 && !input_second_num)
{
calculate_label.text += btnNumber;
first_num = long.Parse(calculate_label.text);
}
esle if (calculate_label.text.Length < 15 && input_second_num)
{
calculate_label.text += btnNumber;
second_num = long.Parse(calculate_label.text);
}
}
//Calls when clicking on action button
public void Action()
{
input_second_num = true;
calculate_label.text = " ";
}
At first input_second_num is false to write first number at first.When I'm changing input_second_num to true in another function clicking on action button and then trying to input second num, input_second_num is anyways false and I'm typing number for first_number.
Why is it so happening?
It's difficult to answer with the code posted and my initial observations require more than will fit into a comment.
You have posted two functions with the same signature public void Input(). I can't see how this code builds without issues; I must therefore assume that they are declared in different class types.
This function is incorrect:
public void Input()
{
else if (calculate_label.text.Length < 15 && input_second_num)
{
calculate_label.text += btnNumber;
second_num = long.Parse(calculate_label.text);
print("Second: " + second_num);
}
}
You're starting an if block statement with an else - is there code missing?
You state that you declared input_second_num as
private static input_second_num;
There is no data type assigned again I can't see how your code builds without issues.
Please revisit your question and show us more of your class code.
let me know if i'm on the right track of this-- i want to trigger certain events at a certain time in the game. For instance say at 10AM each morning I will have event a, b, and c happen.
My current code is something like:
public static Action<int> morningEvents = delegate { };
so I declare an action and then some methods to check time and trigger the action; for example
void CheckTime()
{
check if current time is 10AM then call morningEvents()
}
and I will register the the events a b c to the action
morningEvents += event a;
morningEvents +=event b;
morningEvents +=event c;
Is it possible to achieve my goals with the logic above? Also I don't know what parameters I need to pass in Action< >. I know the default is int but have no idea why.
You could use events as in code below, but this is certainly not the best example how to do it. In such "simple example", I wouldn't create events - just for the reason that it is so simple.
public class MySampleClass : MonoBehaviour
{
public delegate void CertainTimeReachedHandler();
public event CertainTimeReachedHandler tenAmTimeReached;
private bool wasReachedToday = false;
void Start()
{
tenAmTimeReached += ShowClock();
tenAmTimeReached += b();
tenAmTimeReached += c();
}
void Update()
{
var now = DateTime.Now;
var tenAm = DateTime.Today.AddHours(10);
if( (!wasReachedToday) && (now > tenAm) && (now < tenAm.AddSeconds(1)) )
{
wasReachedToday = true;
tenAmTimeReached?.Invoke();
}
}
private void ShowClock() { }
private void b() { }
private void c() { }
}
If I would want to create it for "production level", I would create:
Class that represents relation between condition & time - when it should be fired (DT from, DT to, how many times per day it can be fired, etc.) ~ TaskDTCondition
Class that stores all conditions + stores events for them + invokes those events on condition validity (DT reach) ~ TaskScheduler
In my classes where I want to have such checks, I would call TaskScheduler, ask for an event at specific date and register my private method to be invoked on that event.
For the above, there is likely to be existing some library already, try look around a little. Maybe even in Unity framework (that I'm not aware of). Anyway, this is really broad and if you would like to have more details, you would want to put on different SE site.
I'm modifying existing C# code in order to pilote a piston. Every 30ms, I have a direct feedback of the position of this piston, through an event. The value is stored in a global variable I use to get the current position of the piston.
What I'm trying to achieve: for a given distance input (A->C), I want the piston to travel at full speed for 95% of the distance (A->B), and then slower for the remaining 5% (B->C).
I have access to a command that defines the speed and the destination of the piston : pos(velocity, destination).
However, if I write that code:
pos(fullSpeed,B);
pos(reducedSpeed, C);
the piston directly goes from fullSpeed to reducedSpeed
I tried to use a while loop to compare the current position of the piston with the goal destination, however, upon entering the while loop, the variable storing the piston position does not update anymore.
However, I noticed that by throwing a MessageBox in between, the position value keeps on getting updated, and I can simply click "ok" to launch the second command.
pos(fullSpeed,B);
MessageBox.show("Wait");
pos(reducedSpeed, C);
I would like to know why the "while" loop stops the update of the position variable but the MessageBox does not. I mean, as long as I don't click the "ok" button, the box is here preventing me from doing anything, which for me ressembles a while loop behaviour. Is there another way for me to do this instead of the MessageBox ?
I have little to no knowledge when it comes to C# and no support. I have tried to look in the documentation, but I did not find an answer (I have probably missed it). Any lead is more than welcome.
EDIT: I have no documentation for that code, and it is barely commented. Here is what I gathered (really hope it helps):
To move the piston, taht function is called:
MyEdc.Move.Pos(control, speed, destination, ref MyTan);
control simply define what we pilote (a distance or a load, it is an enum), and I have no idea what MyTan does. Only thing I know is that the MyEdc.Move.Pos returns an error code.
If I look at the definition of "pos", I am redirected to class
public DoPEmove Move;
containing among other things:
public DoPE.ERR Pos(DoPE.CTRL MoveCtrl, double Speed, double Destination, ref short Tan);
DoPE.ERR is also an type enum. However, I cannot reach the definition of a function named "Pos". Coud it be within the .dll included ?
The following is the code that allows me to access the position of the piston (without the global variables):
private int OnData(ref DoPE.OnData Data, object Parameter)
{
if (Data.DoPError == DoPE.ERR.NOERROR)
{
DoPE.Data Sample = Data.Data;
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 300 /*ms*/)
{
LastTime = Time;
string text;
text = String.Format("{0}", Sample.Time.ToString("0.000"));
guiTime.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S].ToString("0.000"));
guiPosition.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F].ToString("0.000"));
guiLoad.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E].ToString("0.000"));
guiExtension.Text = text;
}
}
return 0;
}
Which is called using
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData);
I realise how little I know on how the soft operates, and how frustrating this is for you. If you think this is a lost cause, no problem, I'll try Timothy Jannace solution, and if it does not help me, I'll stick with the MessageBox solution. I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
I tried to use a while loop to compare the current position of the
piston with the goal destination, however, upon entering the while
loop, the variable storing the piston position does not update
anymore.
While you are in the while loop, your app can no longer receive and process the feedback event.
One possible solution would be to use async/await like this:
private const int fullSpeed = 1;
private const int reducedSpeed = 2;
private int currentPistonPositon = 0; // global var updated by event as you described
private async void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
pos(fullSpeed, B);
await Task.Run(() =>
{ // pick one below?
// assumes that "B" and "currentPistonPosition" can actually be EXACTLY the same value
while (currentPistonPositon != B)
{
System.Threading.Thread.Sleep(25);
}
// if this isn't the case, then perhaps when it reaches a certain threshold distance?
while (Math.Abs(currentPistonPositon - B) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
pos(reducedSpeed, C);
}
Note the button1_Click method signature has been marked with async. The code will wait for the while loop inside the task to complete while still processing event messages because of the await. Only then will it move on to the second pos() call.
Thank you for your answer ! It works like a charm ! (good catch on the
EXACT value). I learnt a lot, and I am sure the async/await combo is
going to be very usefull in the future ! – MaximeS
If that worked well, then you might want to consider refactoring the code and making your own "goto position" method like this:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
GotoPosition(fullSpeed, B);
GotoPosition(reducedSpeed, C);
}
private async void GotoPosition(int speed, int position)
{
pos(speed, position);
await Task.Run(() =>
{
while (Math.Abs(currentPistonPositon - position) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
}
Readability would be greatly improved.
You could even get fancier and introduce a timeout concept into the while loop. Now your code could do something like below:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
if (GotoPosition(fullSpeed, B, TimeSpan.FromMilliseconds(750)).Result)
{
if (GotoPosition(reducedSpeed, C, TimeSpan.FromMilliseconds(1500)).Result)
{
// ... we successfully went to B at fullSpeed, then to C at reducedSpeed ...
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
private async Task<bool> GotoPosition(int speed, int position, TimeSpan timeOut)
{
pos(speed, position); // call the async API
// wait for the position to be reached, or the timeout to occur
bool success = true; // assume we have succeeded until proven otherwise
DateTime dt = DateTime.Now.Add(timeOut); // set our timeout DateTime in the future
await Task.Run(() =>
{
System.Threading.Thread.Sleep(50); // give the piston a chance to update maybe once before checking?
while (Math.Abs(currentPistonPositon - position) > 0.10) // see if the piston has reached our target position
{
if (DateTime.Now > dt) // did we move past our timeout DateTime?
{
success = false;
break;
}
System.Threading.Thread.Sleep(25); // very small sleep to reduce CPU usage
}
});
return success;
}
If you're using events you are probably having concurrency issues. Especially with events being raised every 30ms!
A very simple way to handle concurrency is to use a lock object to prevent different threads from using contested resources simultaneously:
class MyEventHandler
{
private object _lockObject;
MyEventHandler()
{
_lockObject = new object();
}
public int MyContestedResource { get; }
public void HandleEvent( object sender, MyEvent event )
{
lock ( _lockObject )
{
// do stuff with event here
MyContestedResource++;
}
}
}
Keep in mind that is very simple and by no means perfect in every scenario. If you provide more information about how the events are raised and what you're doing with them people will be able to provide more help.
EDIT:
Using that signature you posted for the Pos method I was able to find documentation on the library you are using: https://www.academia.edu/24938060/Do_PE
The reason you only see the method signature when you goto definition is because the library has been compiled into a dll. Actually, it probably wouldn't be that useful to see the code anyway because it looks like the library is a C# wrapper around native (c or c++) code.
Anyways, I hope the documentation is helpful to you. If you look at page 20 there are some pointers on doing movement. This is going to be a challenge for a new programmer but you can do it. I would suggest you avoid using the event handler to drive your logic and instead stick with using the synchronous versions of commands. Using the synchronous commands your code should operate the same way it reads.
I believe what you'll want to do is add a call to:
Application.DoEvents();
This will allow your application to process posted messages (events), which will allow that global variable to be updated.
I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
The reason that works is because you're giving the WndProc a chance to process events which have been sent to the application. It's not an intended feature of that call to MessageBox.Show();, but it is a consequence. You can do the same thing with a call to Application.DoEvents(); without the interruption of the message box.
I had been playing around with an idea for a game, and implementation was going fairly well, but I have hit a stumbling block.
Basically, I have a form, which will show talent trees. I am just going to use labels to display the relevant details, and I want to create them programmatically. The display part is working fine, the part I am having trouble with is adding an event handler to the labels.
I want to be able to pass data during the event handling, so that I can identify which specific label was clicked, but I am hitting a brick wall. So when a particular label is clicked, the name of its associated skill (just passing a string) will be sent to the event handler. Any help would be appreciated. Here is the relevant code that I have:
public void DisplayTree()
{
int i=0;
startPoint.X = 40;
startPoint.Y = 125;
foreach(SkillNode s in tree.tier1)
{
for (i=0; i < s.labels.Count;i++ )
{
//Displays a label for each available rank for a skill
s.labels.ElementAt(i).Text = (i+1).ToString()+"/"+s.maxRank.ToString();
s.labels.ElementAt(i).Location = startPoint;
startPoint.Y += s.labels.ElementAt(i).Height + 2;
s.labels.ElementAt(i).Name = "lbl"+s.name+i.ToString();
//Only enable it to be clicked if the user is at the correct rank
if (s.rank == i)
{
s.labels.ElementAt(i).Enabled = true;
}
else
{
s.labels.ElementAt(i).Enabled = false;
}
//Add Event here
//I want to pass the name of the skill with the event
this.Controls.Add(s.labels.ElementAt(i));
}
startPoint.X += s.title.Width + 5;
startPoint.Y = 125;
}
}
public void LabelClick()
{
//Code here to pick out the name of the label
}
Try this:
public void LabelClick()
{
Console.WriteLine(((Control)sender).Name);
}
When you create an event and want to follow the official C# styleguide, you follow the following pattern:
public delegate void {YourName}EventHandler(object sender, {YourName}EventArgs args);
public event {YourName}EventHandler EventName;
Every information about what happened in the event or can be manipulated by the subscriber is stored in a class that inherits EventArgs. The delegate also contains a reference to the sender, which is the object that fires the event.
When you fire an event you do the following, regularly in a protected method that has the same name as the Event with an "On" as prefix:
EventName?.Invoke(this, new {YourName}EventArgs() { Initialize Stuff });
As you can see, you can work with the sender and identify the object. In your case you could also change object sender to UIElement sender (or similar) to make it easier to identify stuff without a cast.
I am pretty new to c# and only scratching the surface. Since my skills are rather limited, I've just reached the limit of what I can do. I would like to populate a list with methods to call (including parameters) and call these methods each second or over any other period of time.
How should I start? I heard about delegates, but I am not sure if they are what I need or if they are suitable for my purposes anyway.
Sorry if this is common-sense.
As DeeMac has already said, this doesn't seem like a thing a beginner or C# would likely need and you are best off explaining why you think you need to do this. However, to do what you were saying you could do something like this:
// Here we have the list of actions (things to be done later)
List<Action> ActionsToPerform;
// And this will store how far we are through the list
List<Action>.Enumerator ActionEnumerator;
// This will allow us to execute a new action after a certain period of time
Timer ActionTimer;
public ActionsManager()
{
ActionsToPerform = new List<Action>();
// We can describe actions in this lambda format,
// () means the action has no parameters of its own
// then we put => { //some standard c# code goes here }
// to describe the action
// CAUTION: See below
ActionsToPerform.Add(() => { Function1("Some string"); });
ActionsToPerform.Add(() => { Function2(3); });
// Here we create a timer so that every thousand miliseconds we trigger the
// Elapsed event
ActionTimer = new Timer(1000.0f);
ActionTimer.Elapsed += new ElapsedEventHandler(ActionTimer_Elapsed);
// An enumerator starts at the begining of the list and we can work through
// the list sequentially
ActionEnumerator = ActionsToPerform.GetEnumerator();
// Move to the start of the list
ActionEnumerator.MoveNext();
}
// This will be triggered when the elpased event happens in out timer
void ActionTimer_Elapsed(object sender, ElapsedEventArgs e)
{
// First we execute the current action by calling it just like a function
ActionEnumerator.Current();
// Then we move the enumerator on to the next list
bool result = ActionEnumerator.MoveNext();
// if we got false moving to the next,
// we have completed all the actions in the list
if (!result)
{
ActionTimer.Stop();
}
}
// Some dummy functions...
public void Function1(string s)
{
Console.WriteLine(s);
}
public void Function2(int x)
{
Console.WriteLine("Printing hello {0} times", x);
for (int i = 0; i < x; ++i)
{
Console.WriteLine("hello");
}
}
Caution:
Here this works as expected as we just pass in some constant values. However, things get tricky if you are not doing something so trivial. For example consider this:
for (int i = 0; i < 10; ++i)
{
ActionsToPerform.Add(() => { Function2(i); });
}
This won't print out what you expect at all, it is something to do with closures which is a very much not a beginner topic.
This is in fact the number one reason why you should seriously consider why you need to do this. As you can see, there are some sophisticated concepts here that aren't normally beginner C#...