简体   繁体   中英

Why isn't the value of class member changing?

Im fairly new to programming and am making a rpg battle simulator for practice. My problem is that I can't seem to make my attack method work. Heres the classes I have:

class Person
{
    protected int attack;
    protected int health;

    public Person(int _attack, int _health)
    {
        attack = _attack;
        health = _health;
    }

    public int GetAttack()
    {
        return attack;
    }

    public int GetHealth()
    {
        return health;
    }

    public int Attack(int _health)
    {
        _health -= attack;
        return _health;
    }
}
class Hero : Person
{
    public Hero(int _attack, int _health)
        :base (_attack , _health)
    {

    }
}
class Enemy : Person
{
    public Enemy(int _attack, int _health)
        :base (_attack , _health)
    {

    }
}

and heres the main:

class Program
{
    static void Main(string[] args)
    {
        Hero Joe = new Hero(4, 10);
        Enemy Tim = new Enemy(5, 20);

        Joe.Attack(Tim.GetHealth());
        Console.WriteLine(Tim.GetHealth());
        Console.WriteLine(Tim.GetAttack());
        Console.ReadLine();
    }
}

My guess is that the attack method is doing the math, but is never changing the health that is passed into it. Or maybe it has something to do with the fact that their protected. Another thought of mine is that it doesn't need to return anything. How would I go about making my attack method work? I just want it to take in somethings health value, subtract the attacking things attack value, and save the calculated value as the health? Thank you for reading this !

When you pass around an int , you are making copies of the number, not passing references to the same number in memory.

When you pass around an instance of a class, you are passing around references to the same object in memory.

Therefore, I suggest changing your design to something like this:

public void Attack(Person target)
{
    target.health -= this.attack;
}

...

Joe.Attack(Jim);

You got a couple things you can improve here. First thing is naming conventions, I recommend reading the design guidelines .

First, If you change your Attack and Health to properties instead of protected fields, you expose getter and setter methods for it. Obviously you only want to set form the controller so make the set a private set :

public class Person
{
    public int Attack { get; private set; }
    public int Health { get; private set; }

    public Person(int attack, int health)
    {
        Attack = attack;
        Health = health;
    }

    // Rest of code
}

When you do it like this you eliminate the need for your individual GetAttack() and GetHealth() methods.

Next, the names of your parameter in Attack() is misleading. I assume you want the parameter to be "attack" and not "health" right? Since our setter is private this method allows us to only access health modifications inside the class. Since we already changed Health to be a property, we don't need to return it anymore so this method can now be void :

//Our property is named Attack so this has to be AttackAction or something different
public void AttackAction(int attack)
{
    Health -= attack;
}

And if we put it all together:

public class Person
{
    public int Attack { get; private set; }
    public int Health { get; private set; }

    public Person(int attack, int health)
    {
        Attack = attack;
        Health = health;
    }

    public void AttackAction(int attack)
    {
        Health -= attack;
    }
}

public class Hero : Person
{
    public Hero(int attack, int health)
        :base (attack , health)
    {

    }
}

public class Enemy : Person
{
    public Enemy(int attack, int health)
        :base (attack , health)
    {

    }
}

I made a fiddle here that shows this new code in action.

You are calling Attack() but are never saving the value returned by that method. You need to add a Setter for the health field, then set that value to the method's returned value. Something like

Health Property

public int Health
{
    get { return health; }
    set { health = value; }
}

Setting the Value

Tim.Health = Joe.Attack(Tim.Health);

If you want to keep the design pattern the same (you don't, see Blorgbeard's answer) you could add a SetHealth() method to Person and do something like this:

Tim.SetHealth(Joe.Attack(Tim.GetHealth());

This gets Tim's health total, passes that to Joe's attack method, which returns a value (what Tim's new health total should be) and then Tim's health is set to this value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM