Trying to make a simple C# program where a ship goes through several "checkpoints" and when it's bounds interesect, it adds to the players score, then game ends when you reach the final checkpoint. Can't figure out how to make the score go up and print to the label each time. Thanks!
UPDATE: I can get my boxes to increase the score once, but not on all the other pictureboxes. Also, when I hit the final "spaceport" picturebox I get stuck in a messagebox redirect loop. How do I solve these 2 things? Tutors at school are no help.
public partial class consoleForm : Form
{
public consoleForm()
{
InitializeComponent();
}
private void consoleForm_Load(object sender, EventArgs e)
{
}
private void outputBox_TextChanged(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
int score = (0);
if (ship.Bounds.IntersectsWith(wormhole1.Bounds))
{
score += (1);
userScore.Text = score.ToString();
this.Refresh();
}
else if (ship.Bounds.IntersectsWith(wormhole2.Bounds))
{
score += (1);
userScore.Text = score.ToString();
this.Refresh();
}
else if (ship.Bounds.IntersectsWith(wormhole3.Bounds))
{
score += (1);
userScore.Text = score.ToString();
this.Refresh();
}
else if (ship.Bounds.IntersectsWith(wormhole4.Bounds))
{
score += (1);
userScore.Text = score.ToString();
this.Refresh();
}
if (ship.Bounds.IntersectsWith(spaceport.Bounds))
{
MessageBox.Show("you win");
this.Refresh();
}
}
The problem you've got is, that you're only doing this check once when the form loads, and never again.
Remove the logic from the consoleForm_Load event, and put it in your own method, called CheckScore(), or something else meaningful.
What would be good is to use a timer to check for the intersection every, let's say 100ms (0.1 seconds).
Create a timer:
In your constructor for the consoleForm, create a timer and a handler for it, then Start it. *You could even put it in your already-existing consoleForm_Load event - your choice :)
Like so:
public consoleForm()
{
var timer = new System.Timers.Timer(100); // Create a timer that fires every 100ms (0.1s)
timer.Tick += OnTimer_Tick;
timer.Start();
}
Add an event for the Tick event of the timer:
The OnTimer_Tick you can either "auto create" from VS, or add yourself:
private void OnTimer_Tick(object sender, ElapsedEventArgs e)
{
CheckScore(); // Call your logic method to check the score
}
Do the logic:
If you haven't already, make sure you've created the CheckScore() method using your original logic (that used to be in the consoleForm_Load event).
Final note:
I would seriously consider tidying up your CheckScore() (or whatever you like to call it) method, but that's just me :)
Further final note: there are loads of other ways of creating timers; I'm just being nice and using the most basic use of a Timer in WinForms :)
Hope this helps!
MORE!!!
At the moment, you're creating a new "score" every time you call the CheckScore() method.
In order to store your score, create a private field called _score or similar:
private int _score = 0;
Then, whenever you're adding to the user's score, reference the _score field, and use that to calculate and display:
_score++;
// or your own logic
_score += 20; // etc. etc.
// At the bottom of your logic,
// when you're ready to display the score:
userScore.Text = "Your score: " + _score;
Then, you can reference the _score wherever else you need it in your form.
Such as re-setting it:
private void ResetScore()
{
_score = 0;
}
or checking if the score has reached a certain value:
public void CheckScore()
{
...
// Your other logic to increment the score.
...
if (_score >= 10) // Check if the score has reached a certain value.
{
MessageBox.Show("You reached 10 points! YOU WIN!");
}
}
Bingo! ;)
Ok so your issue is that your only calling your code once - when the form is loaded. You need an update event set up and called regularly with the above code to make it work. Otherwise your code looks quite sound. Look into c# timers to get your update method called.
Related
I've AdMob test ads fully working in my project.
When the ad is watched the below code should run, however only the first line is being executed, the 2 other lines are being ignored with no error.
public void HandleUserEarnedReward(object sender, Reward args)
{
GameControl.control.life += 1;
GameControl.control.Save();
txtLife.text = GameControl.control.life.ToString();
}
I've placed the same code in another method that I trigger with a button to test.
In this instance the full method is run.
public void runtest()
{
GameControl.control.life += 1;
GameControl.control.Save();
txtLife.text = GameControl.control.life.ToString();
}
If i'm not wrong you are trying to give reward after User watches rewarded video. I had the same problem one time, the problem is that functions that are executing inside of "HandleUserEarnedReward" will NOT be executed on unity's MainThread, but on Google's SDK thread.
There are several solutions:
https://github.com/PimDeWitte/UnityMainThreadDispatcher - Switch to main thread using this. Check readme file to more info.
Create global booleans with false value. Then on "HandleUserEarnedReward" change "isRewarded" boolean to true. Create Update function to check boolean value. Something like:
void Update()
{
if (isRewarded)
{
// do all the actions
// reward the player
isRewarded = false; // to make sure this action will happen only once.
}
}
Use Coroutine. Coroutines autoMagically switch to Unity's MainThread after "yield return"
public void HandleRewardBasedVideoRewarded(object sender, Reward args)
{
string type = args.Type;
double amount = args.Amount;
Debug.Log(
"HandleRewardBasedVideoRewarded event received for "
+ amount.ToString() + " " + type);
StartCoroutine(AfunctionName());
}
IEnumerator AfunctionName()
{
yield return new WaitForSecondsRealtime(0.1f);
// FB.LogAppEvent("AdmobRewardedView");
Debug.Log("Reward Function Called!!!!!");
GiveReward();
this.RequestRewardBasedVideo();
}
I am struggling to workout how to create something that essentially pauses my while loop until my button1 is pressed, I know about the event handler button1_Click but I don't think that will work in this situation as I have lots of loops nested in each other on my form_load.
Any help would be highly appreciated!
This is a snipped of my code where I want the loop to be 'paused' with the notes:
while (reader2.Read())
{
QuestionSpace = Convert.ToString(reader2["Question Space"]);
label1.Text = QuestionSpace;
if (button1.Click = true) // if the button is clicked)
{
// continue with the while loop (I am going to add an INSERT SQL query in here later)
}
else
{
// pause until the button is pressed
}
}
My whole code for the form:
public partial class CurrentlySetTestForm : Form
{
private int QuestionID { get; set; }
private string QuestionSpace { get; set; }
public CurrentlySetTestForm()
{
InitializeComponent();
}
private void CurrentlySetTestForm_Load(object sender, EventArgs e)
{
string y = GlobalVariableClass.Signedinteacher;
MessageBox.Show(y);
Convert.ToInt32(y);
string connectionString = ConfigurationManager.ConnectionStrings["myconnectionstring"].ConnectionString;
SqlConnection connect = new SqlConnection(connectionString);
connect.Open();
SqlCommand command18 = new SqlCommand("SELECT [QuestionID] FROM QuestionStudentAssociation WHERE ( [StudentID]=#Signedinstudent)", connect);
command18.Parameters.AddWithValue("#Signedinstudent", y);
var reader = command18.ExecuteReader();
while (reader.Read())
{
QuestionID = Convert.ToInt32(reader["QuestionID"]);
SqlCommand command19 = new SqlCommand(#"SELECT [Question Space] FROM Questions WHERE ( [QuestionID] = #currentQID )", connect);
command19.Parameters.AddWithValue("#currentQID", QuestionID);
try
{
var reader2 = command19.ExecuteReader();
while (reader2.Read())
{
QuestionSpace = Convert.ToString(reader2["Question Space"]);
label1.Text = QuestionSpace;
if (button1.Click = true) // if the button is clicked)
{
// continue with the while loop (I am going to add an INSERT SQL query in here later)
}
else
{
// pause until the button is pressed
}
}
}
catch (SyntaxErrorException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
MessageBox.Show("Done one loop");
}
}
}
}
Sounds like your not ready to learn TPL
So maybe a BackgroundWorker , you can paint it on the form
To make the click cancel the background worker have a look at Cancel backgroundworker
I would some time to learn TPL as its going to create a simpler and more elegant solution.
As for pausing I would refactor the code, you should not keep the reader open waiting on the user.
You do want event-driven response to UI events, always. However, I guess that you don't want to split your logic into a state machine by hand (where each event triggers progress to the next state). Well, you're in luck, the C# compiler has some keywords to build state machines automagically so you don't have to manage the details.
There are actually two different mechanisms for continuation-passing style implemented in C#. The old one, yield return, works great if your UI events are pretty much interchangeable (or you're only interested in one). Works like this:
IEnumerator<int> Coroutine;
// this could be a Form_Load, but don't you need to get the user information before making the database connection?
void BeginQuiz_Click( object sender, EventArgs unused )
{
Coroutine = RunQA();
}
IEnumerator<int> RunQA()
{
// connect to DB
// show first question on UI
return ContinueQA();
}
IEnumerator<int> ContinueQA()
{
// you can use a while loop instead if you really want
for( int question = 0; question < questionCount; ++question )
{
// check answer
if (/* too many wrong answers*/) {
// report failure in DB
yield break;
}
// get next question from DB
// show new question on the UI
// wait for UI action
yield return question;
}
// report score in DB
// update UI with completion certificate
}
void AnswerButton_Click( object sender, EventArgs unused )
{
answer = sender;
Coroutine.MoveNext(); // MAGIC HAPPENS HERE
}
void TimeoutTimer_Tick( object sender, EventArgs unused )
{
answer = TimeoutTimer;
Coroutine.MoveNext();
}
The magic comes from yield return. Every time the function reaches yield return, the compiler saves what you were doing. When the button click event comes and calls MoveNext, the compiler generates code that starts where yield return paused everything, and keeps going from there until the next yield return.
Important note, the code inside ContinueQA doesn't start when RunQA() does return ContinueQA(); It actually starts on the first MoveNext(). So split your code between RunQA() and ContinueQA accordingly.
If you need different pause reasons at different places in your code, then async/await will be more helpful.
A better way to handle this would be the use of a timer. This would allow the form to draw it's controls and handle all input, such as clicking the button.
Adjust the timer interval (ms) to your needs.
Another way of doing this would be, as Mehrzad Chehraz said, to use multi-threading.
On a side note, I would strongly recommend condition checks over the try/catch checks if possible.
Enable/Disable the timer using the button and call the loop when the timer ticks.
Example:
Timer loopTimer = new Timer();
private void Form1_Load(object sender, EventArgs e)
{
loopTimer.Interval = 100;
loopTimer.Tick += loopTimer_Tick;
loopTimer.Enabled = true;
}
void loopTimer_Tick(object sender, EventArgs e)
{
//perform the loop here at the set interval
}
private void button1_Click(object sender, EventArgs e)
{
//pause/play the loop
loopTimer.Enabled = !loopTimer.Enabled;
}
After being out of scripting for ages I have decided to learn a programming language and I have gone for C#. I'm getting along pretty well but now for the first time I seem to have been faced with a problem that I have not been able to solve with google.
I am making a simulated aircraft system as a learning exercise and I want to invoke a loop when an option is selected from a drop down combobox.
I have a combobox/list with three options which simulates the starter switch, the values are (0)Off, (1)On, (2)Ignition Only . In the real aeroplane, when 'On' is selected the switch locks in place for 10 seconds and then releases. So what I am trying to achieve is :
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 0)
{
//Starter is off
eng2Start.Value = 0;
}
if (starterRight.SelectedIndex == 1)
{
//starter is on
//Start Timer
eng2Start.Value = 1;
if (eng2Tourqe >= 6000)
{
//open fuel valve
// set Hot Start counter to 0
}
else
{
//ensure fuel valve stays closed
// set Hot Start counter to x+1
}
// End of Timer
// set selected index back to 0
(starterRight.SelectedIndex == 0)
}
}
I have googled and googled and the more I read the more I am getting lost in this. I have found answers containing a mass of code which I am not able to fully decipher just yet.
Is it possible to do what I want to do?
Thanks in advance for your time.
You can Add Timer to your Form and Set the Interval property to 10000(10 seconds).
from code:
if (starterRight.SelectedIndex == 1)
{
//starter is on
//Start Timer
timer1.Enabled=true;
}
//in timer tick Event write the following:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled=false;
//Statements to start aircraft
}
You could achieve this by setting it to true (or selected, or whatever you want) sleeping for 10 seconds, like this:
Thread.Sleep(10000) ;
and then set it back to false (or unselect, or whatever you want)
Another way to go would be to start a background thread that will sleep for ten seconds, and then call a method that will "unset" the button, this way, not blocking the GUI ...
Or depending on what you're using, I could probably come up with other options, but i'll take it you're trying to learn the basics atm ... :)
See this one msdn timer
And you can use Threed.Sleep(10000);
I think this should works. I didn't compile it, but with this you lock the swtich, do your stuff checking a timer that when arrives to 10 sec, re-enable your switch.
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 0)
{
//Starter is off
eng2Start.Value = 0;
}
if (starterRight.SelectedIndex == 1)
{
//starter is on
starterRight.enable = false;
StopWatch sw = new StopWatch();
sw.Start();
eng2Start.Value = 1;
if (eng2Tourqe >= 6000)
{
//open fuel valve
// set Hot Start counter to 0
}
else
{
//ensure fuel valve stays closed
// set Hot Start counter to x+1
}
if (sw.ElapsedMilliseconds <= 10000)
{
do
{
//Dummy Loop
}
while (sw.ElapsedMilliseconds > 10000)
sw.Stop();
}
else
{
// set selected index back to 0
sw.Stop();
starterRight.Enabled = true;
(starterRight.SelectedIndex == 0)
}
}
}
You can use a Timer and the Tick event. Disable your switch, and when the Timer tick, Enabled it.
Timer timerSwitchOn;
public SomeConstructor()
{
timerSwitchOn = new Timer(){Interval = 10*1000}; // 10 seconds
timerSwitchOn.Tick += new EventHandler(timerSwitchOn_Tick);
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (starterRight.SelectedIndex == 1)
{
//starter is on
starterRight.Enabled = false;
timerSwitchOn.Start();
}
}
void timerSwitchOn_Tick(object sender, EventArgs e)
{
timerSwitchOn.Stop();
starterRight.Enabled = true;
// set selected index back to 0
starterRight.SelectedIndex = 0;
}
In my initial question I said I had wanted to invoke a loop, I meant a timer but it seems that you all figured that out.
Thank you for the rapid answers, I am going to get stuck into them this weekend and see if I can solve my problem.
So, I'm trying to develop a simple application in visual C# which gets data from serial port and displays it in a textbox (to monitor temperature). I'm acquiring and displaying the data successfully, using the DataReceived event to update a global string variable and a timer to update the text field on my text box, as shown:
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
try
{
globalVar.updateTemp = port.ReadLine(); //This is my global string
}
catch (IOException)
{
}
catch (InvalidOperationException)
{
}
catch (TimeoutException)
{
}
}
private void timer1_Tick(object sender, EventArgs e)
{
tempDisplayBox.Text = globalVar.updateTemp; //This is my textbox updating
}
The only issue I have is that the value shown in the textbox keeps flashing, making it hard to read. My timer is set to trigger every 10 ms (which should be fast enough, right?). Is there any way to make it more stable? I realize this may be a newb question, but to be fair I am a newb :) Any help is appreciated! Thanks!
Do you really need it updating every 10ms? What about every 500 ms or if not that then 100ms. 100ms will require your update method run 10 times less and therefore update 10 times less. The flickering you are expiriencing is due to the refresh speed. You could create custom method which will only update the temp only when target Label or textBox value is different than source port. But that will only sort the flickering when temp is steady, when temp will start vary it will bring back the flickering. Good luck ;-)
UPDATE
Hi I tried to reproduce the conditions and could not make my textbox nor Label flash. The way I tested it was by assigning int ntick = 0; and then increment the ++ntick; inside of the timer_tick method. The results didn't make any of the controls flash and were updated even every milisecond at some point. I also tried string.Format to put some load on the method. Is your app responsive?
The trick is to use double buffering. This way the operating system will redraw the Control off-screen, and only show the control when it is fully redrawn.
I have had the same problem, and solved it by extending the TextBox control like this:
public FastLogBox()
{
InitializeComponent();
_logBoxText = new StringBuilder(150000);
timer1.Interval = 20;
timer1.Tick += timer1_Tick;
timer1.Start();
SetStyle(ControlStyles.DoubleBuffer, true);
}
void timer1_Tick(object sender, EventArgs e)
{
if (_timeToClear)
{
_logBoxText.Clear();
_timeToClear = false;
}
if (_logQueue.Count <= 0) return;
while (!_logQueue.IsEmpty)
{
string element;
if (!_logQueue.TryDequeue(out element)) continue;
{
_logBoxText.Insert(0, element + "\r\n");
}
}
if (_logBoxText.Length > 150000)
{
_logBoxText.Remove(150000, _logBoxText.Length - 150001);
}
Text = _logBoxText.ToString();
}
public new void Clear()
{
_timeToClear = true;
while (!_logQueue.IsEmpty)
{
string element;
_logQueue.TryDequeue(out element);
}
}
public void AddToQueue(string message)
{
_logQueue.Enqueue(message);
}
}
I also use a timer and a concurrentQueue to avoid using Invoke to update the control from another thread. I also use a StringBuilder to prepare the string before putting it into the TextBox. StringBuilder is faster when building larger strings.
You can use ReadExisting() to read the whole data at a time.
You need to handle DataReceived Event of SerialPort
serialPort1.ReadExisting();
Sample:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
String myData=serialPort1.ReadExisting();
}
Example Code: Here i would like to show you the code to Read Data(RFID Tag Code which is basically of length 12)
String macid = "";
private void DoWork()
{
Invoke(
new SetTextDeleg(machineExe ),
new object[] { macid });
macid = "";
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string str1;
macid += serialPort1.ReadExisting();
if (macid.Length == 12)
{
macid = macid.Substring(0, 10);
Thread t = new Thread(new ThreadStart(DoWork));
t.Start();
}
}
public void machineExe(string text)
{
TextBox1.Text=text;
}
Thank you so much for the answers! I found a way to work around this issue:
Instead of replacing the contents of my textbox by rewriting the TextBox.Text property - which, as HenningNT implied, refreshes the control and causes the flickering - I'm now using the TextBox.AppendText method. Though, as I want to display only one line of data at a time, I use the textbox in multiline mode and the Environment.NewLine to jump to a new line before appending the text. As for the method of updating, I've gone back to using the timer because with the invoke method was crashing my application when I close the form, for some reason. Also, enabling double buffering didn't do me much good, although I guess I was doing it wrong... It still flickers a bit, but it's much better now :) I know this is not really a perfect solution (much more of a workaround), so I'll keep looking for it. If I find it, I'll be sure to update it here ;) My code:
private void timer1_Tick(object sender, EventArgs e) //Timer to update textbox
{
if (tempDisplayBox.Text != globalVar.updateTemp) //Only update if temperature is different
{
try
{
tempDisplayBox.AppendText(Environment.NewLine);
tempDisplayBox.AppendText(globalVar.updateTemp);
}
catch (NullReferenceException)
{
}
}
}
This is what I did in MainPage.xaml.cs to create the text animation effect:
private readonly double TEXT_TIMER = 30.0;
private int index;
private void updateText(String text)
{
_text = text;
index = 0;
MainTextBlock.Text = "";
_textTimer.Tick += _textTimer_Tick;
_textTimer.Interval = TimeSpan.FromMilliseconds(TEXT_TIMER);
_textTimer.Start();
}
private void _textTimer_Tick(object sender, EventArgs e)
{
if (index < _text.Length)
{
string s = _text[index].ToString();
MainTextBlock.Text += s;
index++;
}
else
{
_textTimer.Stop();
}
}
I have a list of texts/strings and also a button, say NextButton on the MainPage.xaml. The updateText method is in the click event of NextButton, and what it does is to fetch a text from the list of texts/strings and update the textblock using the animation effect.
But I realised that as I continued to click on the NextButton, it was as if the value of TEXT_TIMER was reducing and the animation effect happened more rapidly until there was no animation anymore (i.e. the text just appeared in the textblock without any effects).
Anybody got any idea why this is happening and how I can fix it?
EDIT:
I have included code to stop the timer after the textblock has been updated with the hopes that solves possible multiple Tick callbacks but nothing still.
It's not that TEXT_TIMER value is reducing, but _textTimer is not stopping, so you have multiple timer ticks.
Try adding _textTimer.Stop() at the start of updateText() method.
On Dan Bryant's advice:
My program flow was registering for the Tick event multiple times beacuse I put it into the updateText method which got called multiple times during program run. All I had to do was move that line of code where the Tick event is registered, _textTimer.Tick += _textTimer_Tick; into the constructor, i.e after InitializeComponent() and problem solved!