Cannot change int values created in main using a class function - c#

-I cannot change int values created in main using a class function-
I am making a game and I have a function called sideCollision that checks if the player is touching a pictureBox,and if the player is touching the pictureBox,an integer called Score is incremented by 1.
Here is the function:
public void sideCollision(Control player,Control pointRadius,Control topPipe,Control bottomPipe,Control gameOver,int force,bool timer,int score,int pointRadiusCounter)
{
if (player.Right > pointRadius.Left && player.Left < pointRadius.Right - player.Width / 2 && player.Bottom > pointRadius.Top)
{
if (timer == true && pointRadiusCounter == 0)
{
pointRadiusCounter = 1;
score++;
}
}
}
The function detects the player touching the wall,but it does not increment the score by 1. I also have a message in my main saying "score has not been assigned to,and will always have its default value of 0".
I need to know how to change the score value using the function,because the function isn't changing the value of Score

You shouldn't use pass-by-reference in situations like this. Instead, you could in this situation use something like this.
private void SomeMethod()
{
var score = 0;
var pointRadiusCounter = 0;
if (CollisionOccurred(...))
{
score++;
pointRadiusCounter++;
}
...
...
...
}
public bool CollisionOccurred(Control player,Control pointRadius,Control topPipe,Control bottomPipe,Control gameOver,int force,bool timer)
{
if (player.Right > pointRadius.Left && player.Left < pointRadius.Right - player.Width / 2 && player.Bottom > pointRadius.Top)
{
if (timer == true && pointRadiusCounter == 0)
{
return true;
}
}
return false;
}

Forgive me for this being a little bit offtopic but this might help you avoiding problems like the one you have at the moment:
I would consider to think about what variables need to be passes as a
parameter and what variables could also be accessible from all your
classes because their value will, whether it is changed or not, be the
same at any point of your code (for example lifepoints of the player,
score of the player, position of the player).
Then you could transfer them into a own class (for this example the
"player" class), make those variables attributes of this class, and
make those accessible for your other classes via making the attributes
public static or an Singleton-class if there is just 1 player in
the game.
Passing an amount of variables as high as you do to
sideCollision(...) can cause a lot of trouble when your project
becomes bigger. Arranging and prioritizing your variables, methods,
classes etc. can help you to prevent this. So take your time and think
about what is important and where you need it and stuff like that.

int is a value type. That means it's passed by-value and inside the function you have a copy of your original variable. You can solve this by passing it by-reference explicitly:
public void sideCollision(Control player,Control pointRadius,Control topPipe,Control bottomPipe,Control gameOver,int force,bool timer, ref int score, ref int pointRadiusCounter)
{
if (player.Right > pointRadius.Left && player.Left < pointRadius.Right - player.Width / 2 && player.Bottom > pointRadius.Top)
{
if (timer == true && pointRadiusCounter == 0)
{
pointRadiusCounter = 1;
score++;
}
}
}

Related

How to use a variable from a different script as a method argument

I've been struggling with a method that needs to check, and then change a variable that is from a separate script and object. I'm trying to check an array for entries that are not null, and entries that are not already used in my placeholders. When both of these are true, it's supposed to copy the contents of that array into my actualReadIn string variable, which is held in another script. Categories is the string array I'm reading from.
Here is the code I have:
int checkForNotNull(string[] a)
{
for (int x = 0; x < a.Length; x++)
{
if (a[x]!= "" && orbScript1.actualReadIn != a[x] && orbScript2.actualReadIn != a[x] && orbScript3.actualReadIn != a[x] && orbScript4.actualReadIn != a[x]
&& orbScript5.actualReadIn != a[x] && orbScript6.actualReadIn != a[x]&& orbScript7.actualReadIn != a[x] && orbScript8.actualReadIn != a[x])
//^^ This should both check to see if the entry is not nothing, and see if the entry matches any others orbs.
return x;
}
return -1;
}
^^ This code checks to ensure that the other placeholders don't already contain the array entry
void readArray(string actualRead)
{
if (taskPhase == 1)
{
if (actualRead == "")
{
actualRead = Categories[checkForNotNull(Categories)];
}
}
if (taskPhase == 2)
{
}
}
^^ The argument on this script is supposed to be orbScript1.actualReadIn. Which is a string variable I'm trying to fill. The issue comes when I try to call the method
readArray(orbScript1.actualReadIn);
There's no errors with this, but it isn't filling the value on orbScript1. I'm pretty new at this, so if I'm doing something that is bad form or isn't common practice let me know.
If you need clarifications I'll do what I can to provide it.
Thanks.
I think I've got it. As it turns out, readArray() is completely useless. The way I actually got an output was
if (orbScript1.actualReadIn == "")
{
orbScript1.actualReadIn = Categories[checkForNotNull (Categories)];
}
This methods doesn't ask for an argument that is outside of the script, and fills the actualReadIn variable on my object.

Check winner in puzzle

I want to design a function that checks whether Player A or B wins.
Right now I'm just reusing a bunch of code. I would like to use the same function for each if possible. Right now I have two different if statements, one for A and for B. Any tips on how I should merge them?
Can I create a function which takes in both A and B values and use some kind of tenary function with just one if statement?
if (label[x,0].theValue() == A && label[x,1].theValue() == A && label[x,2].theValue) == A)
{
MessageBox.Show("A Wins!");
}
if (label[x,0].theValue() == B && label[x,1].theValue() == B && label[x,2].theValue) == B)
{
MessageBox.Show("B wins!");
}
I think you can do something like this:
public string CheckWinner(int x){
if( "your code" ) { return "A wins"; }
if( "your code" ) { return "B wins"; }
}
And then on your main function (form)
MessageBox.Show(CheckWinner(1));
I Hope this helps.
You can write a funktion to check if a given player has won like this (assuming A and B in your code are Player-objects)
private bool HasWon(Player player)
{
if (label[x,0].theValue() == player && label[x,1].theValue() == player && label[x,2].theValue() == player)
{
return true;
}
return false;
}
You can use this function like so:
if(HasWon(A))
{
MessageBox.Show("A Wins!");
}
or, if you have a List or something like this of all playing players, do like so:
foreach(var player in players)
{
if(HasWon(player))
{
MessageBox.Show(player.Name + " Wins!");
}
}
Add a method to check if A is the winner:
public bool IsAWinner(string x0value, string x1value, string x2value)
{
if (x0value == "A" && x1value == "A" && x2value == "A")
return true;
return false;
}
Call this one from your UI code to check if A is the winner, if it isn't, B is the winner.
The idea is to NOT use windows controls in this method; so that it can be tested (loose coupling from UI).
So from your UI:
if (IsAWinner(label[x,0].theValue(), label[x,1].theValue(),label[x,2].theValue))
MessageBox.Show("A Wins!");
else
MessageBox.Show("B wins!");
Also, don't forget to add some exception handling.
While I've never used C# I would imagine the second If statement is not needed. If A wins, then B loses whereas if B Wins A loses.
If A wins ... else B wins!
Sorry I can't give you a code sample, C# isn't my thing.

going through a list with a for loop

Okay, i have a list and where i have structs stored, and i need to go through them from the last to the first, to check if one of the variables in the struct is 1. the code look like this:
for(int i = (checkpoints.Count - 1); i == 0; i--)
{
if(checkpoints[i].active == 1)
{
playerPositionX = checkpoints[i].xPosition;
playerPositionY = checkpoints[i].yPosition;
camPositionX = checkpoints[i].xPosition;
break;
}
}
this is the struct that i use:
private struct checkpoint
{
public int xPosition;
public int yPosition;
public int active;
}
what i need to do is to check if the variable active is == 1 in the struct that i have stored in the list. i have around 3-8 structs stored in the list. I need to start the check from the last struct in the list and work my way to the first.
when i try to debug the program it looks like it's not going from the last, but it starts at i=0.
please leave a comment if you have a fix, or if you need more information.
You can also use LastOrDefault() function. But, here can be one problem, because we are searching for Struct.
If nothing found?
LastOrDefault() will return default(checkpoint) if nothing found. The default value of a struct is the struct with all its values in turn default initialized. So, we must cast them to nullable using .Cast<checkpoint?>.
var activeCheckPoint = checkpoints
.Where(x => x.active == 1)
.Cast<checkpoint?>()
.LastOrDefault();
Or we must do the second check afterward that the returned object's active value is 1.
var activeCheckPoint = checkpoints.LastOrDefault(x => x.active == 1);
if(actactiveCheckPoint.active == 1)
{
// Then it is Ok
}
else
{
// Nothins was found
}
But, if you want to use for loop, then you must change i == 0 to i >= 0.
Your mistake was that you said to go though the loop if i was equal to 0, when it wasn't. You want the loop to loop until i is greater or equal to zero.
for(int i = (checkpoints.Count - 1); i >= 0; i--) // your mistake was here
{
if(checkpoints[i].active == 1)
{
playerPositionX = checkpoints[i].xPosition;
playerPositionY = checkpoints[i].yPosition;
camPositionX = checkpoints[i].xPosition;
break;
}
}

List<T> find index of GameObject

I am making a game with turn-based combat.
For the combat i am pulling between 1-3 monsters and then placing them. The monsters are GameObjects.
I then put the monsters in a List so i can check their position from left-right. (left being index 0 and right being index 2 if there is 3 monsters ofc)
My only problem is getting the index of the GameObject..
This bit of code is on my CombatMainController.cs
void createMonster(){
float numberOfMobs = Random.Range (1, 4);
print (numberOfMobs);
if (numberOfMobs > 2) {
monsterStartpointX = -4f;
}
else if (numberOfMobs > 1) {
monsterStartpointX = -2f;
}
else {
monsterStartpointX = 0f;
}
for (int i = 0; i < numberOfMobs; i++) {
randomMonster = Random.Range(0, monsters.Count);
GameObject monster = Instantiate(monsters[randomMonster], Vector3.up, Quaternion.identity) as GameObject;
aliveMonsters.Add(monster);
Vector3 temp = monster.transform.position;
temp.x = monsterStartpointX;
temp.y = monsterStartpointY;
monster.transform.position = temp;
monsterStartpointX += 4f;
}
}
public void removeMonster(GameObject gameObject){
print (gameObject);
aliveMonsters.Remove(gameObject);
}
print (gameObject) returns: Goblin(Clone) (UnityEngine.GameObject)
UnityEngine.MonoBehaviour:print(Object) - which is the GameObject that is being clicked on.
But aliveMonsters.Remove(gameObject); does not remove said GameObject.
This is the code that is attached to the monster
void OnMouseUp(){
OnClickGUI = !OnClickGUI;
//Destroy (gameObject);
}
void OnGUI(){
if (OnClickGUI) {
Vector3 V = Camera.main.WorldToScreenPoint(transform.position);
if (GUI.Button(new Rect(V.x - 50,Screen.height - V.y,100,30),"Attack")){
takenDamage();
}
}
}
void takenDamage(){
combatController.removeMonster (gameObject);
}
I have no idea what i'm doing wrong and hope you can help me or atleast point me in a better direction.
On MSDN you can read this about the List.Remove Method:
If type T implements the IEquatable<T> generic interface, the equality comparer is the Equals method of that interface; otherwise, the default equality comparer is Object.Equals.
If neither IEquatable<T> is implemented by the game object nor Object.Equals is overridden then reference equality is used for the comparison and this one will never fail if the given object is really in the list. This is the default behavior of Object.Equals.
I could imagine that either a faulty Object.Equals override or IEquatable<T> implementations exists that makes the Remove method fail.
Another possibility is that you try to remove a clone of the game object. In that case reference equality cannot work! You could fix it by overriding the Object.Equals method and to make it compare object IDs. Or you could remove like this:
int index = aliveMonsters.FindIndex(m => m.ID == monster.ID);
if (index >= 0 ) {
aliveMonsters.RemoveAt(index);
}
But in any case, make sure that there is really a problem with the list and not just with the game logic. The object might be removed from the list but not from the game.
Could you do something like:
public void removeMonster(GameObject gameObject){
print (gameObject);
GameObject objToRemove = allMonsters.DefaultIfEmpty(null)
.FirstOrDefault(f=>f.obj.ID=gameObject.ID);
if (objToRemove!=null)
aliveMonsters.Remove(objToRemove);
else
throw new Exception("That monster isn't in the list.")
}

How to reference an object of a class in a statement?

At the top of my form I have:
public static int hoursInt;
public static int minutesInt;
public static int secondsInt;
public static int CompletedIn24;
Then further down I have the following to reset the numericUpDown boxes to zero when selecting a new runner:
private void lstRunners_SelectedIndexChanged(object sender, EventArgs e)
{
Runner selectedRunner = (Runner)lstRunners.SelectedItem;
numericUpDown1.Value = 0;
numericUpDown2.Value = 0;
numericUpDown3.Value = 0;
}
Then in the Finish button click event I have:
hoursInt = Convert.ToInt32(numericUpDown1.Value);
minutesInt = Convert.ToInt32(numericUpDown2.Value);
secondsInt = Convert.ToInt32(numericUpDown3.Value);
if (lstRunners.SelectedIndex > -1 && hoursInt + minutesInt + secondsInt != 0)
{
// Obtain selected climber
Runner selectedRunner = (Runner)lstRunners.SelectedItem;
selectedRunner.Hours = hoursInt;
selectedRunner.Minutes = minutesInt;
selectedRunner.Seconds = secondsInt;
var expertRunner = selectedRunner as Expert;
if (expertRunner != null)
{
expertRunner.UponFinish();
}
Here is my overriden method in Expert : Runner:
public override void UponFinish()
{
base.UponFinish();
// The integer must increment by one if the time is 24:00:00 or less i.e. 23:59:59 would increment the integer as well
if (Hours < 24 || (Hours == 24 && Minutes == 0 && Seconds == 0))
{
CompletedIn24++;
}
}
At present the UponFinish() method in Runner doesn't have anything inside the braces as I'm not sure if anything is required?
I tried to output the CompletedIn24 integer to a string to see if it would work when the button is clicked but the value stayed at zero even if an expert runner was selected and the time was 24:00:00 or less. The integer is not incrementing and I'm not sure what is causing the problem?
Any help would be appreciated.
Simply use the as keyword like this:
var runner = selectedRunner as Expert;
if(runner != null) runner.UponFinish();
If your class Runner already defines some method called UponFinish, you should define this method as virtual and override that method in the derived classes, like this:
public class Runner {
public virtual void UponFinish(){
//...
}
}
public class Expert : Runner {
public override void UponFinish(){
//You talked about the time, I asked for clarification on this
//but it's still very unclear. I suppose when you mean the time is 24:00:00
//that means the hours is 24, the minutes is 0 and the seconds is 0
if(Hours < 24 || (Minutes == 0 && Seconds == 0)) Completedin24++;
}
}
Then of course you don't need any cast, just call UponFinish and the overridden code (if any) will be called correctly:
selectedRunner.UponFinish();
You can check type like this:
if (selectedRunner.GetType() == typeof(Expert))
{
Expert expert = (Expert)selectedRunner;
}
You can do
if(selectedRunner is Expert)
{
UponFinish((Expert)selectedRunner);
//or ((Expert)selectedRunner).UponFinish(); if that was the intention
}
or alternatively
Expert selectedExpert = selectedRunner as Expert;
if(selectedExpert != null)
UponFinish(selectedExpert);
edit:
If your UponFinish function is already part of both Runner and Expert (that is, overridden in Expert), you don't need to cast selectedRunner before calling it.
There are several ways to do this, exists the operator is for example:
Operator IS
You can check if your Runner is an ExpertRunner by using the is keyword:
if(selectedRunner is ExpertRunner)
However, in terms of OOP you should never have to do this, you may want to check your hierarchy or logic why you need to handle this case seperately and not in overridden behaviour (function or properties).
Try this :
if(lstRunners.SelectedItem is Expert)
{
Expert selectedRunner = lstRunners.SelectedItem as Expert;
selectedRunner.UponFinish();
}
if (lstRunners.SelectedItem is Expert)
{
((Expert)lstRunners.SelectedItem).UponFinish();
}

Categories