Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Help, I cant make classes interact.

ItsZewsItsZews Member
edited September 2020 in Programming

Hi guys, today I've been writing some code which I'll show you in a moment, and I created 2 entities, cat01 and cat 02, but I cant figure out how to make one attack the other, because when i go to the CatAttack method, from there I cant access the two cats! Hope you understood, I'll leave u the code. I forgot to say that I'm a beginner and this code is c#.

================================================================

using System;


namespace My_Program

{

    class Cat

    {

        public string name;

        public float level;

        public string abilityName;

        public int attackCount;

        public int health;

        public float damage;




        public Cat(string _name, string _abilityName, float _damage)

        {

            abilityName = _abilityName;

            name = _name;

            level = 0f;

            attackCount = 5;

            health = 100;

        }



        public void CatAttack()

        {

            if (attackCount > 0)

            {

                Console.WriteLine(name + "attacked with " + abilityName + ".");

                attackCount -= 1;

                level += 0.1f;

                //attaccare cat02 con cat 01 da cercare su internet

            } else 

            {

                Console.WriteLine(name + "has no attacks left.");

            } 

            

        }

    }

    

    

    

    

    class Program

    {

        static void Main(string[] args) 

        {

            Cat cat01 = new Cat("Fuffy", "Furia Cieca", 10);

            Cat cat02 = new Cat("Gandalf", "Abracadabra", 5);

            

            Console.WriteLine(cat01.name + "has " + cat01.attackCount + " attacks remaining."); //Prints number of attacks remaining.

            

            cat01.CatAttack();


            Console.WriteLine(cat01.name + "has " + cat01.attackCount + " attacks remaining.");

            Console.WriteLine(cat01.name + " level : " + cat01.level);

            

            //ReadKey

            Console.ReadKey();

        }

    }


}

Thanks!

Best Answers

  • Sl0thSl0th Member
    Accepted Answer

    Hello there

    The problem you are facing is actually not that you can't access the two cats from within each cat, but rather that you need a different solution. This is a topic that you'll continue hearing about for a very long time when writing any object oriented programming language, which C# is. To explain it, I'll tell you about something called scope and encapsulation.

    Scope is about where you can access things from. You can think of every code body {} as being its own closed box. As standard, you can't get anything inside a box from outside the box. But if you make a new box within a box, the innermost box is still part of the larger box, and can therefore see everything inside it. So in your case, the namespace My_Program is a box that everything you have written is inside. Then inside that, you have a class called Cat, which again is its own box. Cat then has two boxes in it, which are the methods. One of those is your CatAttack. Inside CatAttack, you can reach all the variables you defined in Cat, because CatAttack is inside Cat. If you however define something inside CatAttack, you can't reach it from another method in Cat, because those are different boxes. You have defined cat01 and cat02 inside your Main method, which means that they can't be accessed from the Cat class, because those again are completely different boxes. The places where you can access a variable is called the variable's scope. Now, there is a way to change this, which is when you make something public, which you have done with the variables and methods of Cat. This means that they are available everywhere else, no matter where they were defined. That is why you for example can access attackCount and CatAttack of cat01 inside your Main method. This would not be possible, if they had been private instead of public (which they are by default). Be aware that you can't make public variables within a method.

    Now, what pretty much all new programmers think when learning about scope is that "private" is a silly thing and that everything just should be public, to make everything easier. This is where encapsulation comes in. It's the concept of hiding information from everyone that doesn't need that information. Why should a cat be aware of all the other cats that exist? That doesn't make sense. First, it's impractical, because you'd have to write some very weird code to maintain that. Second, it's very likely to cause bugs. The more ways you can change something, the more places in your code you have to look when something unexpected happens. For this to make sense, imagine those two cats in real life. They wouldn't just know about each other. They might however meet and see each other. They are given some input through their senses from the world, and thus become aware of each other. So your Main method, which works as your "world" needs to tell the cats about each other. The solution is in this case very simple. When you call CatAttack, you should just pass the cat which is to be attacked. CatAttack will look like this:

    public void CatAttack(Cat cat)

            {

                if (attackCount > 0)

                {

                    Console.WriteLine(name + "attacked with " + abilityName + ".");

                    attackCount -= 1;

                    level += 0.1f;

    cat.health -= damage;

    Console.WriteLine(cat.name + " was attacked and took " + damage + " damage. It now has " + cat.health + " health left.");

                } else 

                {

                    Console.WriteLine(name + "has no attacks left.");

                } 

                

            }


    Then your Main method will just look like this:

    static void Main(string[] args) 

            {

                Cat cat01 = new Cat("Fuffy", "Furia Cieca", 10);

                Cat cat02 = new Cat("Gandalf", "Abracadabra", 5);

                

                Console.WriteLine(cat01.name + "has " + cat01.attackCount + " attacks remaining."); //Prints number of attacks remaining.

                

                cat01.CatAttack(cat02);


                Console.WriteLine(cat01.name + "has " + cat01.attackCount + " attacks remaining.");

                Console.WriteLine(cat01.name + " level : " + cat01.level);

                

                //ReadKey

                Console.ReadKey();

            }


    I'd argue that you could make more of the variables in Cat private. It's a good thing to practice. Perhaps you can figure out how you could make health be private and still have attacks work?

    As I said, this topic goes waaaaaay deeper than this. If you want to learn more about it, I recommend checking out Mosh on Udemy. I've learned a lot from his courses.

    Hope it helps!

  • ItsZewsItsZews Member
    Accepted Answer

    Hi SI0th, thanks for your reply, I resolved some errors, but some others have came out, like this on line 61 where I try to attack cat02 with cat01. I wrote cat01.CatAttack(cat02); but it gives this error:

    "No arguments were specified corresponding to the mandatory formal parameter 'cat02' of 'Cat.CatAttack (Cat, Cat)' [C: \ Users \ User \ Desktop \ My Program \ My Program.csproj]
    

    I will leave u the updated code right down here.

    using System;


    namespace My_Program

    {

        class Cat

        {

            public string name;

            public float level;

            public string abilityName;

            public int attackCount;

            public int health;

            public float damage;




            public Cat(string _name, string _abilityName, float _damage)

            {

                abilityName = _abilityName;

                name = _name;

                damage = _damage;

                level = 0f;

                attackCount = 5;

                health = 100;

            }



            public void CatAttack(Cat cat01, Cat cat02)

            {

                if (cat01.attackCount > 0)

                {

                    Console.WriteLine(cat01.name + "attacked with " + cat01.abilityName + " " + cat02.name + ".");

                    cat01.attackCount -= 1;

                    cat01.level += 0.1f;

                    cat02.health -= Convert.ToInt32(cat01.damage);

                } else 

                {

                    Console.WriteLine(cat01.name + "has no attacks left.");

                } 

                

            }


            

        }

        

        

        

        

        class World

        {

            

            

            

            static void Main(string[] args) 

            {

                Cat cat01 = new Cat("Fuffy", "Furia Cieca", 10);

                Cat cat02 = new Cat("Gandalf", "Abracadabra", 5);

                

                Console.WriteLine(cat01.name + " has " + cat01.attackCount + " attacks remaining."); //Prints number of attacks remaining.

                Console.WriteLine(cat01.name + " level : " + cat01.level);

                Console.WriteLine(cat01.name + " has " + cat01.health + " HP remaining.");

                cat01.CatAttack(cat02);

                

                Console.WriteLine(cat01.name + " has " + cat01.attackCount + " attacks remaining.");

                Console.WriteLine(cat01.name + " level : " + cat01.level);

                Console.WriteLine(cat02.name + " has " + cat02.health + " HP remaining.");

                

                

                //ReadKey

                Console.ReadKey();

            }

        }


    }

    Thank you for the help!😀

  • Sl0thSl0th Member
    Accepted Answer

    Hey there

    This problem comes because you ask for two inputs in the CatAttack method. You do not need a reference to the cat that is attacking, because this method is called on that very cat. You don't need to write cat01.damage, because you can just write damage. (Or this.damage, it's the same). It will reference the the instance of Cat that it is called on. An instance of a class is called an object, btw. So, the method should just look like this:

    public void CatAttack(Cat cat)

            {

                if (attackCount > 0)

                {

                    Console.WriteLine(name + "attacked with " + abilityName + " " + cat.name + ".");

                    attackCount -= 1;

                    level += 0.1f;

                    cat.health -= Convert.ToInt32(damage);

                } else 

                {

                    Console.WriteLine(name + "has no attacks left.");

                } 

                

            }


    Also, something else, damage and health should be the same type. So either float or int. Then you don't have to make a conversion.

    If you really want to have them be different types, though, you can write it differently. Instead of

    cat.health -= Convert.ToInt32(damage);

    write:

    cat.health -= (int)damage;


    The Convert.ToInt32 thingy is when casting from string to int.

Answers

Sign In or Register to comment.