G'day, I seem to be having a problem with a class variable in my Windows Form Application.
It is a string variable in my Player class. When I create a Player object, I cannot seem to assign a string value to the playerName variable.
I've manually created my Get and Set methods and I can't see anything wrong with it.
I've gotten a message a few times that informs me that the string playerName isn't assigned and will remain its default value of null. I'm not sure why this is the case.
class Player
{
private string playerName = ""; //Variable used for giving each player a unique identifier, eg. 'Player One', etc
//public string PlayerName { get => playerName; set => playerName = value; }
public void setPlayerName(string name) //Sets the player's name for the game (UNSC or Covenant)
{
name = this.playerName;
}
public string getPlayerName() //Returns the player's name
{
return playerName;
}
}
Creating a Player class and trying to show the playerName to a textbox doesn't work, the playerName value remains null
public partial class FrmBoardGameApp : Form
{
public FrmBoardGameApp()
{
InitializeComponent();
}
ArrayList Players = new ArrayList();
public void creationOfPlayers() //BUG!!! Values stay null
{
Player playerOne = new Player(); //Player 1
Player playerTwo = new Player(); //Player 2
playerOne.setPlayerName("Player One");
playerTwo.setPlayerName("Player Two");
Players.Add(playerOne); //Player name value is still null at this point
Players.Add(playerTwo);
}
//Here's the textbox assignment code
public bool playerTurn = true; //A bool variable used to keep track of whose turn it is
public bool setupCheck = false; // Ensures that the endturn button cannot be hit unless all setup is done
public int setupCheckValue = 0; //Ensures that the setup button can only be hit once
public void testingPlayerTurn() //A method used to test whose turn it is
{
if (setupCheck != true)
{
MessageBox.Show("Game is not setup, please setup the game");
}
else
{
//Textbox is empty, as playerName value remains null
if (playerTurn)
{
Players.ToArray();
Player firstPlayer = (Player)Players[0];
txtAns.Text = firstPlayer.getPlayerName();
/*
* This method of accessing an element and controlling/manipulating its values works
*/
}
else if (!playerTurn)
{
//playerTwo.setPlayerName(factionTwo);
//txtAns.Text = playerTwo.getPlayerName();
}
}
}
private void btnEndTurn_Click(object sender, EventArgs e) //Ends the turn of the current player
{
changePlayer();
//testingPlayerTurn();
testingPlayerNames();
}
}
I've added into the code example some methods that handle player assignment, just in case it helps in any way. But the issue starts at the creationOfPlayers method and in the Player class.
this:
public void setPlayerName(string name) //Sets the player's name for the game (UNSC or Covenant)
{
name = this.playerName;
}
should be the other way around:
public void setPlayerName(string name) //Sets the player's name for the game (UNSC or Covenant)
{
this.playerName = name;
}
Problem: you actually assigned the value of your field to the local parameter of the method.
Explanation: on the left side of the = should be the variable that receives the value, on the right side should be the variable that gives the value (or reference in other cases).
In your player class, inside setPlayerName method, you should be asisgning name parameter value to this.playerName. I see you have done reverse
public void setPlayerName(string name) //Sets the player's name for the game (UNSC or Covenant)
{
//name = this.playerName;
this.playerName = name;
}
Related
I have a Skill base class and 2 separate Skill classes that inherit from the Class Skill. Each skill has its own SkillCoolDown value. I set the CoolDownManager Class that is visualising the cooldowns for the skills, but I don't understand how to set the SkillCoolDown value to the manager which is different for each skill. Would appreciate the help.
public class Skill
{
private string skillName;
private int skillDamage;
private string skillDescription;
private int skillCoolDown;
public string SkillName {get;set;}
public int SkillDamage {get;set;}
public string SkillDescription {get;set;}
public int SkillCoolDown {get;set;}
public Skill () {}
}
public class CoolDownManager : MonoBehaviour
{
public Skill skill;
private Stopwatch cooldown;
private Button button;
private Image fillImage;
private int skillCoolDown;
public void OnSkillUse(Button btn) {
skill = new Skill(); // HERE THE VALUE SkillCoolDown SHOULD BE IMPLEMENTED AND I WANT SOMEHOW TO SHOW WHICH SKILL HAS BEEN USED.
button = btn.GetComponent<Button>();
fillImage = btn.transform.GetChild(0).gameObject.GetComponent<Image>();
btn.interactable = false;
fillImage.fillAmount = 1;
cooldown = new Stopwatch();
cooldown.Start();
StartCoroutine(CoolDownAnimation());
}
private IEnumerator CoolDownAnimation() {
while(cooldown.IsRunning && cooldown.Elapsed.TotalSeconds < skill.SkillCoolDown) {
fillImage.fillAmount = ((float)cooldown.Elapsed.TotalSeconds / skill.SkillCoolDown);
yield return null;
}
fillImage.fillAmount = 0;
button.interactable = true;
cooldown.Stop();
cooldown.Reset();
}
}
And here is example of the Skill class from where the value SkillCoolDown should be passed.
public class BasicAttack : Skill
{
public BasicAttack()
{
SkillCoolDown = 2;
}
}
A Skill could be passed to the CooldownManager via constructor injection:
public class CoolDownManager : MonoBehaviour
{
public Skill skill;
// other properties
public CoolDownManager(Skill skillParam)
{
skill = skillParam;
}
// do whatever you want with skill
}
This is the perfect problem to solve using scriptable objects.
The following class inherits from ScriptableObject and defines the same data you have in your Skill class. Using the CreateAssetMenu attribute for this class, you can make a new asset of this type. Right-click in your project window and navigate to the menu item Combat/Skills/New Skill, and then you will have an asset of this type.
Note: Because this is an asset, it implicitly has the property name, so you can name the Skill asset accordingly.
[CreateAssetMenu(fileName = "NewSkill.asset", menuName = "Combat/Skills/New Skill")]
public class Skill : ScriptableObject
{
[SerializeField] private int _damage = default;
[SerializeField] private string _description = default;
[SerializeField] private int _cooldown = default;
public int damage => _damage;
public string description => _description;
public int cooldown => _cooldown;
}
Now that you can create Skill assets, go ahead and create your two skills and fill in the details in the inspector.
Next, you'll need a way to use the Skill. I've gotten rid of the CoolDownManager in favor of a button. Check out the following.
[RequireComponent(typeof(Button))]
public class SkillButton : MonoBehaviour
{
[SerializeField] private Skill _skill = default;
[SerializeField] private Button _button = default;
[SerializeField] private Image _fillImage = default;
private Stopwatch _stopwatch = new Stopwatch();
private void Awake()
{
// Hook up a method to listen for when the button is clicked.
_button.onClick.AddListener(OnClick);
}
// This method is invoked when the button is clicked.
private void OnClick()
{
StartCoroutine(CoolDownAnimation());
}
private IEnumerator CoolDownAnimation()
{
// Immediately keep the button from being clicked again.
_button.interactable = false;
_stopwatch.Start();
while (_stopwatch.IsRunning && _stopwatch.Elapsed.TotalSeconds < _skill.cooldown)
{
_fillImage.fillAmount = (float)_stopwatch.Elapsed.TotalSeconds / _skill.cooldown;
yield return null;
}
_fillImage.fillAmount = 0;
_button.interactable = true;
_stopwatch.Stop();
_stopwatch.Reset();
}
// Use this to hook up references automatically.
private void OnValidate()
{
if (_button == null)
{
_button = GetComponent<Button>();
}
if (_button != null && _fillImage == null)
{
_fillImage = _button.transform.GetChild(0).gameObject.GetComponent<Image>();
}
}
}
Attach the SkillButton component to the Button you wish to have controlling the skill, then hook up your various Skill objects to have them associated with that button.
With all of that out of the way, you should have functionality close to what you desire.
I am having this problem where when I instantiate multiple objects at once, the gameObject references the same instance on all objects whereas they should instead reference the gameObject that component is attached to.
So, I have this MonoBehaviour, which is the main part of my code. When the awake function runs it should create an instance of each BootstrapMacro so I don't overwrite the data in the .asset file (Which happens without this part).
Then in the new instance, I set a reference to the current Bootstrap component.
public class Bootstrap : MonoBehaviour {
[SerializeField] List<BootstrapMacro> macros;
public List<BootstrapMacro> runtimeMacros = new List<BootstrapMacro>();
void Awake() {
// Create a runtime version of the macro so to not overwrite the original asset file
macros.ForEach(macro => {
if (macro != null) {
var mac = Instantiate(macro);
mac.events.ForEach(evt => {
evt.bootstrap = this;
evt.actions.ForEach(act => { act.bootstrap = this; });
});
runtimeMacros.Add(mac);
}
});
RunMacro(e => e.OnObjectAwake());
}
void Start() { RunMacro(e => e.OnObjectStart()); }
void RunMacro(System.Action<BootstrapEvent> action) {
runtimeMacros.ForEach(macro => {
if (macro == null) return;
macro.events.ForEach(evt => {
if (!evt.enabled) return;
action.Invoke(evt);
});
});
}
}
My BootstrapMacro file is really basic:
[CreateAssetMenu(fileName = "Bootstrap Macro.asset", menuName = "Boostrap/Macro")]
public class BootstrapMacro : ScriptableObject {
public List<Bootstrap.BootstrapEvent> events = new List<Bootstrap.BootstrapEvent>();
}
Then the event looks like this:
[BootstrapEvent(0)]
public class OnCreate : BootstrapEvent {
public override void OnObjectStart() {
Debug.Log(bootstrap.gameObject.name);
Trigger();
}
}
Which extends this:
public class BootstrapEvent : ScriptableObject {
Bootstrap _bootstrap;
public Bootstrap bootstrap {
get { return _bootstrap; }
set { if (_bootstrap == null) _bootstrap = value; }
}
public virtual void OnObjectStart() { }
}
I am instantiating the objects like this:
var o = Instantiate(_gameObject, _position, Quaternion.identity);
o.name = Random.Range(0, 1000).ToString();
So it is creating the object and giving it a random number. So when it is created I log the name as seen above (code block 3). However, they are all referencing the first object created....
So, what is causing the items to reference the same gameObject?
From the following picture what is happening is the Debug.Log is printing, the object name. As seen there are multiple object names getting printed. A new object name is written to the console every time the previous one is destroyed.
Edit
So, It looks like the issue is with my property. If I remove if(_bootstrap == null), then the code works as expected. If I leave it, it is using the first created item as the reference until it is destroyed then the next create item becomes the reference. Why?
public Bootstrap bootstrap {
get { return _bootstrap; }
set { _bootstrap = value; }
}
var o = Instantiate(_gameObject, _position, Quaternion.identity);
o.name = Random.Range(0, 1000).ToString();
"So, what is causing the items to reference the same gameObject?"
_gameObject is your object reference, all of your var o objects are clones of this. this is the desired behavior with instantiation.
Note that if _gameObject gets destroyed, var o will no longer have a reference, and you will crash. that's why we use prefabs. they cant be removed from the scene so your reference wont go null.
Well, my issue here is basically what it says in the title. I'm trying to call my bool value of my Player2 class for my Tic Tac Toe-project we have in school. I think it's worth mentioning that I use "Player Player1, Player2;" in the beginning of Form1.cs to create two instances of my class, Player. I've read multiple posts on the internet about this but all of them are people trying to call in more parameters than that they are providing. I don't see how a bool value of true or false is more than one.
Thanks in advance.
One of my buttons where this problem appears.
public void Btn1_Click(object sender, EventArgs e) >{
{
if (click1 == 0)
{
if (Player2.GetActive(true))//(turn == 0)
{
Btn1.Text = "X";
}
else
{
>Btn1.Text = "O";
}
//turn++;
click1++;
}
else
{
Btn1.Text = Btn1.Text;
}
display();
checkit();
}
}
This is my player class.
` public class Player
{
//Characteristics
string name;
int points;
bool Active;
//Constructor
public Player() { points = 0; Active = true; }
//Methods
public void SetName(string n) { name = n; }
public string GetName() { return name; }
public void SetPoints(int p) { points = p; }
public int GetPoints() { return points; }
public void SetActive(bool a) { Active = a; }
public bool GetActive() { return Active; }`
You have the code:
Player2.GetActive(true)
But you define get active as
public bool GetActive() { return Active; }`
So it is correct you have not defined a GetActive with a parameter.
Here,
if(Player2.GetActive(true))
you are passing an extra argument (true) to the method GetActive. As we can see from the method declaration of GetActive, it takes no parameters:
public bool GetActive() { return Active; }
// ↑
// empty parentheses
I think what you mean here is "if Player2.GetActive() is true..." right? You don't need to specify the value you want if it is true, just doing this is fine:
if (Player2.GetActive())
If you want to check if it is false, add ! before the call to negate the result:
if (!Player2.GetActive())
Like BugFinder said, you are using the method to get the Active-Value instead of using the method to set the value.
So change
Player2.GetActive(true)
to
Player2.SetActive(true)
Just as an addition:
Since we are working with C# here and many of your methods are called set and get, I suggest you change those methods to be properties:
public string Name
{
get { return name; }
set { name = value; }
}
public int Points
{
get { return points; }
set { points = value; }
}
public bool Active
{
get { return active; }
set { active = value; }
}
Now when you want to set the value, you can type
Player2.IsActive = true;
and to check the value simple type code like
If(Player2.IsActive)
//Do Stuff
Taking a C#.Net class and we have been introduced a new concept of using a class with a form. It's an online class and basically the instructor has given us instructions, however they are somewhat unclear, at least to me. Unfortunately, his responses to students questions are very vague and basically, in a nut shell, told us to figure it out, so I be here. Below is what the instructor gave us.
=========================================================================
UML: Model: String, CurrentSpeed: Decimal, TopSpeed: Decimal, and Accelerate (change speed: Decimal)
Accelerate adds changeSpeed (which can be positive, negative or 0) to CurrentSpeed. CurrentSpeed can never exceed TopSpeed or be less than 0
e.g. if CurrentSpeed is 10 and dChangeSpeed is -20, CurrentSpeed becomes 0
General Requirements:
Top Speed combo box is filled with numbers 60, 70, 80 …. 200
(at Run time)
Change Speed combo box is filled with numbers 1, 2, 3 ….200
(at Run time)
User must select from combo box (cannot enter own numbers)
Button Action Requirements:
Accelerate For same model, increases Current Speed by Change Speed
For new model, sets Current Speed to Change Speed
(Current Speed can’t exceed Top Speed)
Decelerate For same model, decreases Current Speed by Change Speed
For new model, sets Current Speed to 0
(Current Speed can’t go below 0)
UML diagram is followed exactly.
Work (calculations, etc) done in the class, not the form.
=========================================================================
Ok, so my question is, should I use a Deceleration method, along with the Accelerate in the class? I'm assuming that each button (decel, accel) would need its own method in the class. However I think I'm overly making this complicated, which was the answer to one of my question I asked my instructor. I guess I'm totally stumped as to how to reference the class, specifically the Accelerate with the form.
So far, this is what I came up with, which I know is mostly wrong, however this is a beginners class from what I'm told and the support form the instructor is not there other than relying on a chapter about classes.
public class Car
{
// Backing Fields (Instance Variables)
private string _model;
private int _currentSpeed;
private int _topSpeed;
public int SpeedResult;
// Set Parameters
public Car()
{
this.Model = "";
this.CurrentSpeed = 0;
this.TopSpeed = 0;
}
// Constructor
public Car(string Model, int CurrentSpeed, int TopSpeed)
{
_model = Model;
_currentSpeed = CurrentSpeed;
_topSpeed = TopSpeed;
}
// Model Property
public string Model
{
get { return _model; }
set { _model = value; }
}
// Current Speed Property
public int CurrentSpeed
{
get { return _currentSpeed; }
set { _currentSpeed = value; }
}
// Top Speed Property
public int TopSpeed
{
get { return _topSpeed; }
set { _topSpeed = value; }
}
// Methods
public int Accelerate()
{
SpeedResult = (TopSpeed + CurrentSpeed);
return SpeedResult;
}
//
public void clear()
{
Model = "";
CurrentSpeed = 0;
TopSpeed = 0;
}
}
Form:
public partial class carSpeedForm : Form
{
private Car _myCar;
private int SpeedResult;
public carSpeedForm()
{
_myCar = new Car();
InitializeComponent();
}
private void carSpeedForm_Load(object sender, EventArgs e)
{
// Loads Amount ComboBox with values from 60 to 200 in increments of 10
for (int i = 60; i <= 200; i += 10)
topSpeedComboBox.Items.Add(i);
// Loads Amount ComboBox with values from 1 to 200 in increments of 1
for (int i = 1; i <= 200; i += 1)
changeSpeedComboBox.Items.Add(i);
}
private void GetCarData()
{
try
{
_myCar.Model = carModelTextBox.Text;
_myCar.TopSpeed = int.Parse(topSpeedComboBox.Text);
_myCar.CurrentSpeed = int.Parse(changeSpeedComboBox.Text);
}
catch
{
MessageBox.Show(string.Concat("Please enter a valid model and speed(s) for vehicle.","\r\n"));
}
}
private void accelButton_Click(object sender, EventArgs e)
{
GetCarData();
speedResultLabel.Text = SpeedResult.ToString("n1");
carResultLabel.Text = String.Format("Your car is a new car.");
}
private void decelButton_Click(object sender, EventArgs e)
{
GetCarData();
speedResultLabel.Text = SpeedResult.ToString("n1");
carResultLabel.Text = String.Format("Your car is a new car.");
}
private void clearButton_Click(object sender, EventArgs e)
{
//Clear textbox, combobox, labels
carModelTextBox.Clear();
carModelTextBox.Focus();
topSpeedComboBox.SelectedIndex = -1;
changeSpeedComboBox.SelectedIndex = -1;
speedResultLabel.Text = "";
carResultLabel.Text = "";
}
private void exitButton_Click(object sender, EventArgs e)
{
//Close application
this.Close();
}
}
Not only is your code not “mostly wrong”, I’d even call it mostly right. It is not clear exactly what you are asking, or what “how to reference the class” means.
The instructor is right to tell you to “to figure it out”, and we can’t do your assignment for you. If you have working code you want people to review, post it on the Code Review site.
However, there are a few code smells that, in my experience, will lead to problems in the future:
// Backing Fields (Instance Variables)
Do not comment programming terms; they contribute nothing and soon go out of sync with the code. Only comment things that cannot be expressed in the programming language.
private string _model;
// Model Property
public string Model
{
get { return _model; }
set { _model = value; }
}
That’s about the most verbose way possible to define a property. Defining separate backing fields only encourages people to use the backing field instead of the property. Moreover, making it public makes any consumer of the class able to change the property at any time. Sometimes you need those things, but you should not allow them unless you absolutely need them. Also, vague names like “Model” are hard to understand, especially if other classes use them. A better definition would be:
public string ModelName { get; private set; }
public int SpeedResult;
What is this? It’s not in your UML, and is never used for anything. Moreover, it’s public so anything can change it to anything; it’s totally useless, get rid of it.
// Set Parameters
public Car()
{
this.Model = "";
this.CurrentSpeed = 0;
this.TopSpeed = 0;
}
And then in your form constructor:
_myCar = new Car();
This is worse than useless; you’re creating instances that contain no data, and every field is public so anything can change your data to anything. C# gives you the ability to enforce that your instances only contain valid data. Use them, and only create an instance when you know its data. You should have only one Car constructor like this:
public Car(string modelName, float topSpeed)
{
if (string.IsNullOrWhiteSpace(modelName)) throw new ArgumentNullException("modelName");
ModelName = modelName;
TopSpeed = topSpeed;
}
I assume CurrentSpeed is mutable, so you probably shouldn’t define it in the constructor; it is a candidate for one of those public properties I warned you about.
public int Accelerate()
{
SpeedResult = (TopSpeed + CurrentSpeed);
return SpeedResult;
}
Why would you add TopSpeed to CurrentSpeed? That can make SpeedResult greater than TopSpeed. Why are your speeds ints? Your description calls them “decimal”, but the C# decimal type is for fixed-point values. float is a better choice.
Your question says “Accelerate adds changeSpeed ... to CurrentSpeed ... CurrentSpeed can never exceed TopSpeed or be less than 0”. So do that:
public void Accelerate(float changeSpeed)
{
var predictedSpeed = CurrentSpeed + changeSpeed;
if (predictedSpeed > TopSpeed)
CurrentSpeed = TopSpeed;
else if (predictedSpeed < 0)
CurrentSpeed = 0;
else
CurrentSpeed = predictedSpeed;
}
public void clear()
{
Model = "";
CurrentSpeed = 0;
TopSpeed = 0;
}
Again, you're allowing anything at all to wreck your data. Don't do that; if you need to create a new car, then create a new Car. If you don’t want to display a car, don’t create one.
There are problems with your carSpeedForm as well, but I see MGM is addressing those.
Reading the description you wrote, it looks like you basically have the concept down. From your form, I assume you will be selecting a car type? If that is the case, you basically want to define all your model(Car) behavior in a Car class.
For example, as you have already done, you would want to define accessors for the selected cars data and the Accelerate and Decelerate methods. That way inside you view(carSpeedForm) you can call the perspective method when the corresponding button is pressed. I.E. if the user presses the Accelerate button on the form, you would call the Accelerate method of the instance of Car. Hope that helps. You're not far off.
You should use the button and input controls to store the data in your_myCar instances. For Example
public partial class CarForm : Form
{
private Car theCar;
private bool modelChanged;
public CarForm()
{
theCar = new Car();
InitializeComponent();
loadChangeSpeed_cb();
loadTopSpeed_cb();
modelChanged = false;
}
private void loadChangeSpeed_cb()
{
for (decimal i = 1; i <= 200; i++)
{
changeSpeed_cb.Items.Add(i);
}
}
private void loadTopSpeed_cb()
{
for(decimal i = 60; i <= 200; i+=10)
{
topSpeed_cb.Items.Add(i);
}
}
private void accel_b_Click(object sender, EventArgs e)
{
if(modelChanged)
{
theCar.CurrentSpeed = theCar.ChangeSpeed;
modelChanged = false;
}
else
{
var si = changeSpeed_cb.SelectedItem;
if (si == null)
{
return;
}
theCar.Accelerate((decimal)si);
}
}
private void decel_b_Click(object sender, EventArgs e)
{
if(modelChanged)
{
theCar.CurrentSpeed = 0;
modelChanged = false;
return;
}
else
{
var si = changeSpeed_cb.SelectedItem;
if (si == null)
{
return;
}
theCar.Accelerate(-(decimal)si);
}
}
private void topSpeed_cb_SelectedIndexChanged(object sender, EventArgs e)
{
var si = topSpeed_cb.SelectedItem;
if(si == null)
{
return;
}
theCar.TopSpeed = (decimal)si;
}
private void changeSpeed_cb_SelectedIndexChanged(object sender, EventArgs e)
{
var si = changeSpeed_cb.SelectedItem;
if (si == null)
{
return;
}
theCar.ChangeSpeed = (decimal)changeSpeed_cb.SelectedItem;
}
I have the following, and it works:
My player class:
public Player(string Str, string SP)
{
Strength = Str;
StatPoints = SP;
}
public string StatPoints
{
get;
set;
}
public string Strength
{
get;
set;
}
Now on my form1 I have a textbox, and a button. The button increments the value in the textbox by one so long as there is a value above 0 in the SP textbox. Problem is, I am declaring six variables in order to manage two values because I have to convert strings to ints and all that crap. Is there a way to replace text boxes with something that is inherently int? Here is my character sheet code so far.
private void AddButton_Click(object sender, EventArgs e)
{
Player PCStats = new Player(StrBox.Text, SPBox.Text);
int IntPCSP = Convert.ToInt16(PCStats.StatPoints);
int IntPCStr = Convert.ToInt16(PCStats.Strength);
if (IntPCSP >= 1 && IntPCStr <= 7)
{
IntPCStr++;
IntPCSP--;
PCStats.Strength = IntPCStr.ToString();
PCStats.StatPoints = IntPCSP.ToString();
StrBox.Text = PCStats.Strength;
SPBox.Text = PCStats.StatPoints;
}
else
{
MessageBox.Show("Earn more experience!");
}
/*
MessageBox.Show("PCStats.StatPoints equals" + PCStats.StatPoints);
MessageBox.Show("PCStats,Strength equals" + PCStats.Strength);
MessageBox.Show("IntPCSP Equals" + IntPCSP.ToString());
MessageBox.Show("IntPCStr Equals" + IntPCStr.ToString());
*/
}
Or is there an even easier way to do this I completely overlooked. I was super excited to finally get this bit to work after a lot of trial and error, but I am open to redoing it. I would rather however just replace the text boxes so I am not converting variables all over the place.
This is quick go, not at a computer with Visual Studio on it but should give you a start. Also, try naming your variables etc to have a bit more meaning. Also, this is to fix what you has as-is but see my update / suggestion further down about moving logic into the Player class...
My player class:
public Player(int strength, int statPoints)
{
this.Strength = strength;
this.StatPoints = statPoints;
}
public int StatPoints { get; set; }
public int Strength { get; set; }
My Form:
private void AddButton_Click(object sender, EventArgs e)
{
Player thePlayer = new Player(int.Parse(StrBox.Text), int.Parse(SPBox.Text));
if (thePlayer.StatPoints > 0 && thePlayer.Strength < 8)
{
thePlayer.Strength++;
thePlayer.StatPoints--;
StrBox.Text = thePlayer.Strength.ToString();
SPBox.Text = thePlayer.StatPoints.ToString();
}
else
{
MessageBox.Show("Earn more experience!");
}
}
Obviously you would need to check that the values in the text box were integers. You could use another control, mask the text box etc or on the code replace int.Parse with int.TryParse which checks it is possible before conversion. Just a few ideas to get you going!
- UPDATE -
Another thing you could do is more the logic into the Player class. This is better as it keep the logic contained in one place so you can see what a Player can DO rather than having to search the whole program:
New Player class:
// The Player class
public class Player
{
// Constructor
public Player(int strength, int statPoints)
{
this.Strength = strength;
this.StatPoints = statPoints;
}
// Method to gain strength if enough StatPoints
public bool GainStrength()
{
bool playerHasEnoughStatPoints = true;
if (this.StatPoints < 1)
{
playerHasEnoughStatPoints = false;
}
else if (this.Strength < 8)
{
this.Strength++;
this.StatPoints--;
}
return playerHasEnoughStatPoints;
}
// Property for StatPoints
public int StatPoints { get; set; }
// Property for Strength
public int Strength { get; set; }
}
New Form:
// The Form or similar
public class MyFormOrSimilar
{
// When button pressed try and add strength to the player
protected void AddButton_Click(object sender, EventArgs e)
{
// Create new INSTANCE of the player and try to give them strength
Player thePlayer = new Player(int.Parse(StrBox.Text), int.Parse(SPBox.Text));
if (thePlayer.GainStrength())
{
StrBox.Text = thePlayer.Strength.ToString();
SPBox.Text = thePlayer.StatPoints.ToString();
}
else
{
MessageBox.Show("Earn more experience!");
}
}
}