I have been trying to create an Othello game, but I can't seem to be able to check for a case that is not there (checking for a black token, and if it isn't there, dont do anything)
private void CaseClick(object sender, MouseEventArgs e)
{
Case allCases = (Case)sender;
int a = 1;
if (allCases.ColorToken == Case.Token.Nothing)
{
Case caseToModify;
if (_turnIsBlack)
{
//Verify tokens from top to bottom
if (Cases[allCases.Position.X, allCases.Position.Y + a].ColorToken == Case.Token.White)
{
while (Cases[allCases.Position.X, allCases.Position.Y + a].ColorToken == Case.Token.White)
{
caseToModify = Cases[allCases.Position.X, allCases.Position.Y + a];
allCases.ColorToken = Case.Token.Black;
caseToModify.ColorToken = Case.Token.Black;
a++;
caseToModify.Refresh();
allCases.Refresh();
_turnIsBlack = false;
}
}
}
}
}
I was just wondering if there was a way to check for the black token that isn't there. Doesn't need to be for this specific code, just an example of checking for something, and if it is not there, do nothing
The position is assigned with coordinates like (0,0) (1,1), the game is an 8x8 with each case being assigned a coordinate
It's completely fine that way. These kind of statements are pretty common and although sometimes you may be able to write some fancy stuff my advice is to keep it simple unless the performance is super crucial.
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().
After hunting the internet for two days and not finding a solution that I can understand properly I have to ask on here for an answer.
I have a windows forms application that was written in vb.net and works fine. I have decided to rewrite this in c# which I thought wouldn't be too much of a problem but ...
I have two classes in the project :
FormJobs & AppJobs
FormJobs contains methods and functions that modify the forms in some way.
AppJobs contains methods and functions for everything else (Checks,Scanning and so forth).
On my main form (FrmStart) the On_load event uses a function from AppJobs to check that the network is up (public bool CheckNetConnection) and then Checks to make sure that the root save folder exists (public void CheckRoot).
If CheckNetConnection is false or CheckRoot does not exist then a method in the FormJobs class sets some buttons to disabled, some labels to display information as to what has gone wrong and also sets the height of the form.
The above works in VB.net but I keep getting a StackOverflowException or NullReferenceException with the C# code.
I know the reason for the Exceptions is because the two classes and the form all keep calling each other so I know that I need to remove this code but I am not sure how to let each class and the form access each other. It is obviously bad design as I`m just starting to learn C# so any help on this would be much appreciated.
But my main questions are:-How do I get a form to access multiple classes?
Allow the classes to access each other?
Let the classes make changes to a form?
FrmStart Code
AppJobs Appjobs = new AppJobs();
private void FrmStart_Load(object sender, EventArgs e)
{
KeyPreview = true;
if (Appjobs.CheckNetConnection(this) == true)
{
Appjobs.CheckRoot(this);
}
AppJobs Code
public class AppJobs
{
FormJobs Formjobs = new FormJobs();
public string AppRoot = Properties.Settings.Default.DefaultFolder;
public string DefaultDevice = Properties.Settings.Default.DefaultScanner;
public bool NoDirectory = false;
DialogResult MsgBoxQuestion;
public bool CheckNetConnection(Form StartForm)
{
IPHostEntry ServerIP = new IPHostEntry();
bool ConnectedToServer = false;
string CurrentRoot = "MyServer";
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
try
{
IPHostEntry DNSTest = Dns.GetHostEntry(CurrentRoot);
if (DNSTest.AddressList.Length > 0)
{
ConnectedToServer = true;
}
else
{
ConnectedToServer = false;
}
}
catch (System.Net.Sockets.SocketException ex)
{
ConnectedToServer = false;
}
}
return ConnectedToServer;
}
public void CheckRoot(Form StartForm)
{
if (string.IsNullOrEmpty(AppRoot))
{
Formjobs.SetHeight(StartForm);
return;
}else if(AppRoot == "0")
{
Formjobs.SetHeight(StartForm);
return;
}
else
{
if ((!Directory.Exists(AppRoot)))
{
NoDirectory = true;
MsgBoxQuestion = MessageBox.Show(AppRoot + " is set, but the directory does not exist." + Environment.NewLine
+ Environment.NewLine + "Would you like to create the folder now?", "Root folder missing", MessageBoxButtons.YesNo);
if (MsgBoxQuestion == DialogResult.Yes)
{
Directory.CreateDirectory(AppRoot);
NoDirectory = false;
}
else
{
MessageBox.Show("You will not be able to use this program until you create a root folder.", "No root folder selected",MessageBoxButtons.OK);
}
}
}
}
}
FormJobs Code
public class FormJobs
{
AppJobs Appjobs = new AppJobs();
public void SetHeight(Form StartForm)
{
if (Appjobs.AppRoot == null | Appjobs.AppRoot == "0") {
if (Appjobs.DefaultDevice == null | Appjobs.DefaultDevice == "0") {
if (StartForm.Controls["MenuStrip1"].Visible == true) {
StartForm.Height = 167;
StartForm.Controls["LblNoRoot"].Visible = true;
StartForm.Controls["LblNoRoot"].Location = new Point(0, 24);
StartForm.Controls["LblNoRoot"].Text = "There is no root folder selected. Please select a root folder to continue.";
StartForm.Controls["LblNoDevice"].Visible = true;
StartForm.Controls["LblNoDevice"].Location = new Point(0, 48);
StartForm.Controls["LblNoDevice"].Text = "There is no default device selected. Please select a default device to continue.";
StartForm.Controls["BtnOkTickets"].Enabled = false;
StartForm.Controls["BtnQueryTickets"].Enabled = false;
StartForm.Controls["BtnSearch"].Enabled = false;
}else
{
StartForm.Height = 147;
StartForm.Controls["LblNoRoot"].Visible = true;
StartForm.Controls["LblNoRoot"].Location = new Point(0, 9);
StartForm.Controls["LblNoRoot"].Text = "There is no root folder selected. Please select a root folder to continue.";
StartForm.Controls["LblNoDevice"].Visible = true;
StartForm.Controls["LblNoDevice"].Location = new Point(0, 33);
StartForm.Controls["LblNoDevice"].Text = "There is no default device selected. Please select a default device to continue.";
StartForm.Controls["BtnOkTickets"].Enabled = false;
StartForm.Controls["BtnQueryTickets"].Enabled = false;
StartForm.Controls["BtnSearch"].Enabled = false;
}
}
One of the causes of your problems is that everyone is changing your StartForm. Apart from that this spaghetti makes it difficult to understand, it certainly doesn't help to make your classes reusable and maintainable if your Startform changes.
It seems to me, that AppJobs is meant to decide what the form should look like (for instance it decides that the StartForm should change height), while FormJobs performs the calculations needed to change this height. StartForm apparently is just allowing to let everyone make changes to him.
A better design would be that StartForm would not ask AppJobs to change its size, and to ask the operator whether a folder should be generated. Instead if ought to ask appJobs for advise: "Which height do you think I should have". after that it could ask FormJobs: "Please adjust my height according to this specification"
FormJobs should trust StartForm that it has gathered the correct information about how a StartForm ought to look like. FormJobs should not ask AppJobs for any information: "Hey AppJobs, StartForm asked me to change its appearance to certain specifications, but I'm not certain whether StartForm has done its job correctly. Please tell me if these specifications are correct, and give me some missing information")
The correct division into tasks would be:
AppJobs specifies the format of any StartForm according to its internal state (a.o. AppRoot, and existence of certain folders)
StartForm is the one who displays all items. He decides who to ask for specifications, and what to do with the returned specifications. He is also the only one who communicates with operators
FormJobs is a class that apparently knows all elements from a StartForm. If you will only have one type of StartForm, then Appjobs should be part of the Startform class. If you think there might be several different Startform classes, all with the same elements that ought to be manipulated similarly, shouldn't all these StartForm classes be derived from a FormJobs class?
Anyway, redesign without everyone causing to manipulate StartForm
Apparently there are a limited number of StartForm layouts depending on AppRoot, defaultDevice etc. You seem to be missing some "else" after your if, so this list might not be accurate. Still you will get the idea:
enum StartFormLayouts
{
DefaultDevice0,
AppRoot0,
Other,
}
// class that specifies the layout of any startform
class AppJobs
{
private bool IsAppRoot0
{
get{return Appjobs.AppRoot == null || Appjobs.AppRoot == "0";}
}
private bool IsDefaultDevice0
{
get{return Appjobs.DefaultDevice == null || Appjobs.DefaultDevice == "0";}
}
public StartFormLayoug GetPreferredLayout()
{
if (this.IsAppRoot0)
{
if (this.IsDefaultDevice)
{
return StartFormLayout.DefaultDevice0;
}
else
return StartFormLayout.AppRoot0;
}
else
{
return StartFormLayout.Other;
}
}
public bool ShouldAskDirectoryCreation()
{
return (!this.IsAppRoot0 && !Directory.Exists(AppRoot));
}
}
Note that this class doesn't need StartForm, nor AppJobs. It could work with any class that wants to know if it should ask for DirectoryCreation. Since it also does not speak any language, even a Chinese StartForm could use it. After all, the StartForm is the only one who knows what language it speaks and what to do if a certain layout is requested.
Furthermore, did you notice that I used a double || to use a Boolean OR instead of a bitwise or?
And I use statements like if (a) instead of if(a=true) a C# Boolean is a real Boolean, in contradiction to Booleans in C and C++.
The class of all kinds of forms that should be able to be layout according to the requested layout contains the functions similar to your
It depends a bit of whether you decide to let it be a base class of StartForm or StartForm itself. If you want it to handle every form class that has the required controls, consider of using an interface:
public Interface IStartForm
{
public int Height {get; set;}
public Label LabelNoRoot {get;}
public Label LabelNoDevice {get; }
public Button BtnTickets {get;}
...
This way you can set the size of any form that has these labels and buttons, even if they have different names than those strings you use.
But again: if you ever only want to size StartForm, then this should be a function in StartForm.
public SetHeight(StartFormLayout layout, IStartForm startForm)
{
switch (layout)
{
case StartFormLayout.DefaultDevice0:
if (startForm.MenuStrip.Visible)
{
startForm.Height = ...;
startForm.LabelNoRoot.Location = ...
// etc
}
else
{
...
Noticed that because of this separation of concerns the AppJobs and FormJobs don't have to know each other. AppJobs and FormJobs also don't really have to know what 'StartForm` is, only that it has the labels and buttons etc that it needs to change.
class StartForm : Form, IStartForm
{
public Label LabelNoRoot {get{return this.label1; } }
...
private void FrmStart_Load(object sender, EventArgs e)
{
AppJobs layoutdesigner = new AppJobs(...);
StartFormLayout layoutdesigner = layouter.GetPreferredLayout();
FormJobs layouter = new FormJobjs();
layouter.SetHeight(this)
}
Noticed that my form didn't have a label named "LabelNoRoot", but a Label1 that should function as a LabelNoRoot. Also: because I used types instead of string, You can be certain that I can't handle a label as if it was a button. I can't by accident try to press the label. Something that could easily been done when you were using strings to identify the items you want to layout.
Extending the comments: you just remove the new part in your FormJobs and AppJobs classes.
leaving the code in i.e. in the FormJobs class like : AppJobs appObj;
Then in your main form create at some point a FormJobs obj and an AppJobs obj and set its property.
I.e. in main Form:
AppJobs appObj = new AppJobs();
FormJobs formObj = new FormJobs();
formObj.appObj = appObj;
Tho I must say i dont like that approach you are taking with this...
You should think of another way or at least refactor your code that FormJobs does not need AppJobs methods and vice versa in a way that all calls to FormJobs and AppJobs come from your main form.
I want to create a form that allows the user to set a certain amount of points in five different fields (NumericUpDown). When that amount of points reaches 0, the user can't add any more. (I still want the user to be able to remove points, though.)
Here is my code so far:
private void calculateValue() {
decimal tempValue = CMB_num_Aim.Value + CMB_num_Reflexes.Value +
CMB_num_Positioning.Value + CMB_num_Movement.Value + CMB_num_Teamwork.Value;
controlValue = currentValue - tempValue;
MyBox.CMB_tb_cv.Text = controlValue.ToString();
}
This Method (calculateValue) is calculates how many points the user have left (controlValue).
private void CMB_num_Aim_ValueChanged(object sender, EventArgs e) {
calculateValue();
if (controlValue < 0) {
//Prevent Default here
MessageBox.Show("You are out of points!");
}
}
This method (CMB_num_Aim_ValueChanged) fires when the value of the NumericUpDown control has changed. I have one of these for each field, each doing the same thing.
The method fires as expected, but I can't prevent it from happening - the user can apply more points than they have. How can I prevent the user from applying more points?
(I thought about making a mouseUp method, but I don't know if the user will use the mouse or if he will type in the value using the keyboard.)
Seems like you want to create a point distribution system between some skills - aim, movement, teamwork etc. You can do that easily by setting Maximum value of NumericUpDown control when you enter it. Subscribe all skill updown controls to the same event handler:
private void SkillNumericUpDown_Enter(object sender, EventArgs e)
{
var skill = (NumericUpDown)sender;
var availablePoints = 42;
var maxSkillPoints = 20; // usually you cannot assign all points to one skill
var unassignedPoints = availablePoints - SkillPointsAssigned;
skill.Maximum = Math.Min(maxSkillPoints, unassignedPoints + skill.Value);
if (unassignedPoints == 0)
{
MessageBox.Show("You are out of points!");
return;
}
if (skill.Value == maxSkillPoints)
{
MessageBox.Show("Skill maximized!");
return;
}
}
private decimal SkillPointsAssigned =>
CMB_num_Aim.Value +
CMB_num_Reflexes.Value +
CMB_num_Positioning.Value +
CMB_num_Movement.Value +
CMB_num_Teamwork.Value;
Benefit - you will not be able to input illegal value neither by arrows nor manually.
Replace
if (controlValue < 0) {
By
if (controlValue <= 0) {
I'm working on a programming assignment, and I'm trying to make this button take the values from two textboxes, and calculate the new location for the form window. I'm having trouble converting the textbox values to type int, and being made usable by the btnCompute_click method.
private void btnCompute_Click(object sender, EventArgs e)
{
int x = Convert.ToInt32(txtXvalue);
int y = Convert.ToInt32(txtYvalue);
Location = new Point(x,y);
}
private void xValue_TextChanged(object sender, EventArgs e)
{
int xValue =
Convert.ToInt32(txtXvalue);
}
private void yValue_TextChanged(object sender, EventArgs e)
{
int y =
Convert.ToInt32(txtYvalue);
}
I forgot to add some additional info, the acceptable values for x and y must be positive. Would I use an if...else statement to control the acceptable values?
user29... i have no idea why death... replied that. it makes no sense to me. but you question makes sense to me. i suppose death... did not understand your question.
First off, everything you ask does not need anything in the TextChanged methods.
Do all your handling in the btnCompute_Click() method because you want to do something *when you click your button, not when the user edits the text of the text boxes, according to your question.
The code that is in your TextChanged() methods will get executed whenever the Text values of those text boxes change. that's not what you asked for it to do. But you could use these events for example, if you wanted a label to become visible or hidden and to set the text of a label which shows text, so you can use it as an error message label, for instance if the integer value of a text box is negative or even if it cannot be parsed.
So in your btnCompute_Click() methods, you first want to get the int values. You need to decide exactly what you want your code to do if the text is not integers. In my opinion, most beginners code things like message boxes or something. I like to give the user feedback with Labels or a status bar message, depending on what I feel is appropriate. Since my first choice would be to use a Label to show the 'error' message when text boxes cannot be parsed to integers, then i would simply return from the button click method without doing anything when the values are not what i want. That way the user gets their messages without annoying popup message boxes or anything. But it's up to you whether you want to pop up a message box or not. Others have given you good code to do that. I want to give you good code that avoids what i consider annoying popup boxes.
When converting strings to an int, Convert.ToInt32 will throw an error if the string cannot be parsed. int.TryParse is the silver bullet for truly parsing strings to integers without any error. Here is the entire code i would use. I made a new project just to make sure i'm not giving you buggy code. I give you my code on how I handle this.
In your updated prerequisite, you mention x & y must be positive and not negative. I note to you that these are not the same. For instance, 0 is neither positive nor negative. I assume that you technically mean that x and y cannot be negative, (and that it does not need to be positive, since 0 should be allowed).
private void Form1_Load(object sender, EventArgs e)
{
lblErrorX.Text = null;
lblErrorY.Text = null;
}
private void btnMoveForm_Click(object sender, EventArgs e)
{
int x = 0; if (int.TryParse(txtX.Text, out x) == false) { return; }
int y = 0; if (int.TryParse(txtY.Text, out y) == false) { return; }
if (x < 0 || y < 0) { return; }
this.Location = new Point(x, y);
}
private void txtX_TextChanged(object sender, EventArgs e)
{
int x = 0;
if (int.TryParse(txtX.Text, out x) == false)
{ lblErrorX.Text = "X is not an valid integer."; return; }
if (x < 0) { lblErrorX.Text = "X cannot be negative."; return; }
lblErrorX.Text = null;
}
private void txtY_TextChanged(object sender, EventArgs e)
{
int y = 0;
if (int.TryParse(txtY.Text, out y) == false)
{ lblErrorY.Text = "Y is not an valid integer."; return; }
if (y < 0) { lblErrorY.Text = "Y cannot be negative."; return; }
lblErrorY.Text = null;
}
In my project, on the form, in the following left to right order: lblX, txtX, lblErrorX. I have the same corresponding for Y: lblY, txtY, lblErrorY. Then i have one Button: btnMoveForm. So my txtX corresponds to your txtXvalue. my btnMoveForm corresponds to your btnCompute, but to me, 'compute' means to calculate, which is not really what this button is doing. this button is moving the form, so that's why i name it as such.
I have played with setting both the Location and the DesktopLocation and it seems to do the same thing. I've always used Location and i just learned that DesktopLocation works too, but since Location is shorter, i use it.
Someone asked why i don't use if(!int.TryParse(...)) { return; } rather than my if(int.TryParse(...) == false) { return; }. My reason is unfortunately that i think ! is an easy one character to miss when reading code, so i avoid it, especially when that little mistake means the opposite of what the code really would do. So my use of '== false' is always for human clarity. But i do like the C# ease of only needing one character. I just think it's a shame that in my opinion, it's a lot safer to write code that is better for humans so we don't mistake it. That's the only reason i use '== false' instead of !. Use ! if you like. It's quite convenient. I regret not using it. hehe.
Oh, and the reason i set the lblErrorX.Text = null; and lblErrorY.Text = null; is on my form in design view, i give them a text value so i can see them. :) so when the program runs, i set the Text to be blank. But you can use the Visible property if you prefer. I just leave them always visible and only set their Text properties.
Based on your expanded criteria you can check for negative numbers conditionally or use Math.Abs to get the absolute value. Something like this.
int x, y;
if (int.TryParse(txtXvalue.Text, out x) && int.TryParse(txtYvalue.Text, out y))
{
if (x < 0 || y < 0)
{
MessageBox.Show("Negative numbers not allowed");
}
else
Location = new Point(x, y);
}
else
{
MessageBox.Show("Must be an Integer");
}
or
int x, y;
if (int.TryParse(txtXvalue.Text, out x) && int.TryParse(txtYvalue.Text, out y))
{
Location = new Point(Math.Abs(x), Math.Abs(y));
}
else
{
MessageBox.Show("Must be an Integer");
}
I think you are looking for this.
private void btnCompute_Click(object sender, EventArgs e)
{
int x = Convert.ToInt32(txtXvalue.Text);
int y = Convert.ToInt32(txtYvalue.Text);
DesktopLocation = new Point(Math.Abs(x), Math.Abs(y));
}
This gets the location for the desktop. Also you need the .Text to get the text inside the textbox. You should also check to make sure the text is not null or empty before using or it will cause an error.
If this isn't what you are looking for please explain a little more.
For my programming class we are required to make a memory match game. When the player clicks on a panel an image is displayed. The player clicks on two panels, if the images match they are removed, if they are different they are turned face down.
The problem I am having with this is that only the image from the first panel gets displayed, even though I am using the same line of code to display the images from both panels, and use Thread.Sleep to pause the program after the second tile has been picked. I don't understand why this is happening, any help would be appreciated.
private void tile_Click(object sender, EventArgs e)
{
string tileName = (sender as Panel).Name;
tileNum = Convert.ToInt16(tileName.Substring(5)) - 1;
//figure out if tile is locked
if (panelArray[tileNum].isLocked == false)
{
pickNum++;
//although the following line of code is used to display the picture that is stored in the tile array
//what is happening is that it will only display the picture of the first tile that has been picked.
//when a second tile is picked my program seems to ignore this line completely, any ideas?
panelArray[tileNum].thisPanel.BackgroundImage = tiles[tileNum].tileImage;
if (pickNum == 1)
{
pick1 = tileNum;
panelArray[tileNum].isLocked = true;
}
else
{
pick2 = tileNum;
UpdateGameState();
}
}
}
private void UpdateGameState()
{
Thread.Sleep(1500);
if (tiles[pick1].tag == tiles[pick2].tag)//compares tags to see if they match.
{
RemoveTiles();
}
else
{
ResetTiles();
}
pickNum = 0;
guess += 1;
guessDisplay.Text = Convert.ToString(guess);
if (correct == 8)
{
CalculateScore();
}
}
try this:
(sender as Panel).BackgroundImage = tiles[tileNum].tileImage;
you have to be sure that your tile_Click method is associated to both panel...