Question about talking with multiple Objects

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Hi Everybody!

Hoping someone can clear up a great mystery for me….

I'm trying to learn Object Oriented programming, and to do so, I am writing a small Role Playing Game.

I understand why we break Players, Items, and Monsters into Classes… what I don’t “get” is how does the program know which Class object is “in focus”.

For example… if I randomly generate 3 monsters… from within the game… A Zombie, A Wolf, and A Lion… for example, how do my other methods know which of
these is “in play”. If during the game, a Zombie is called new…. How does my attack method reference this ‘new’ zombie? Sorry if that’s confusing.

How I have been handling it…

I have a ‘master’ object called ‘Monster’.

Public templatemonster As New monsterClass
Public mastermonster As New monsterClass
Public zombiemonster As New monsterClass
Public wolfmonster As New monsterClass
Public lionmonster As New monsterClass


I then have to “load” and “unload” them each time I want to use them.

For example…. I will copy “zombiemonster” over top of “mastermonster”.

I will then do all my referencing to “mastermonster”.

Ie:

mastermonster.doDamage
mastermoster.doHealing

Then… to “save” it… I have to copy it back. (Copy mastermonster object to zombiemonster)

Then.. I have to ‘reset’ the mastermonster by copying the templatemonster over top of it.

Then… if a Wolf jumps in.. I have to copy wolfmonster overtop of mastermonster… etc. etc. etc.


This is all because, within the methods of whatever I want to do to these objects (damage, heal, gain xp, etc.) I only know
how to ‘reference’ it by 1 name. “ie: mastermonster”. I have to do this if I am talking to objects as well. This is a key piece I know I am missing.

How do other people handle this?

I’m so sorry if this is too broad of question, or if I’ve made this confusing.
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
A demo.. Maybe someone else can explain? I tried demonstrating with some commenting..

if I randomly generate 3 monsters… from within the game… A Zombie, A Wolf, and A Lion… for example, how do my other methods know which of
these is “in play”.

I only know how to ‘reference’ it by 1 name. “ie: mastermonster”.

How do other people handle this?

I'm not quite sure if i understand exactly what your asking, but i think this is something along those lines..? Here's a demo with some commenting.

Sorry, i'm not too good at explaining, and didn't really feel like writing.. (english... dont mind coding though:p ), maybe someone else here can explain it more?..

i hope this helps though.. ??

The top comment shows what it outputs. What this code does: creates a array of monsters. They are either a monster or derived from the monster base class. when you 'attack' these monsters it goes through a loop and attacks all of the Monsters in the array. However if this monster is a AnimalMonster which is a class that inherits Monster, the monster is healed rather than damaged. Also if the animalMonster is named "wolf" then it will also use growl.


''Console Outputs >>
''
''Monster: monster, HP: 100
''Humanoid Monster: zombie, HP: 100
''Animal Monster: wolf, HP: 100
''Animal Monster: loin, HP: 100

''Attack Monsters... Target monster named wolf will attack you

''monster was attacked!, Now has 99 HP
''zombie was attacked!, Now has 99 HP
''wolf used Growl on you!
''wolf was healed!, Now has 101 HP
''loin was healed!, Now has 101 HP


Module Module1
    'create four new monsters
    Public basicMonster As New Monster With {.name = "monster"} 'syntax
    Public zombieMonster As New HumanoidMonster With {.name = "zombie"}
    Public wolfMonster As New AnimalMonster With {.name = "wolf"}
    Public loinMonster As New AnimalMonster With {.name = "loin"}
    Sub Main()
        'put those four monsters into an array (by reference)
        Dim monstersOnField() As Monster = {basicMonster, zombieMonster, wolfMonster, loinMonster}

        'loop through all elements in monstersOnField array
        For Each Monster As Monster In monstersOnField 'creates a reference to each monster found in the array and names it 'Monster'
            'note that since all of the four monsters inherit from monster they are all monster's
            Monster.writeToConsole() 'call method
            'note that in the two inherited classes
            'the same method is overrided
            'so that method is called rather than the base class method
        Next
        Console.WriteLine()
        Console.WriteLine("Attack Monsters... Target monster named wolf will attack you")
        Console.ReadLine()

        'attack all monsters
        For Each Monster As Monster In monstersOnField
            'get the type of the monster
            'there are three types, the base, humanoidMonster, and AnimalMonster in this case
            If Monster.GetType() = GetType(AnimalMonster) Then 'if it is of animalMonstertype
                If Monster.name = "wolf" Then 'if the name is Wolf
                    'note that without casting it back to its derivied class you cannot call the Growl method
                    'since the base class Monster does not have that
                    CType(Monster, AnimalMonster).Growl()
                End If

                'this is a method from the base class
                'this will heal all animal type monsters
                Monster.doHealing()

            Else 'for all of the other monsters
                Monster.doDamage()
            End If
        Next

        Console.ReadLine()
    End Sub
    Class Monster
        Property name As String
        Property hp As Integer = 100

        Sub doHealing()
            hp += 1
            status("healed")
        End Sub
        Sub doDamage()
            hp -= 1
            status("attacked")
        End Sub

        Private Sub status(ByVal Msg As String)
            Console.WriteLine("{1} was {0}!, Now has {2} HP", Msg, name, hp)
        End Sub

        Overridable Sub writeToConsole()
            Console.WriteLine("Monster: {0}, HP: {1}", name, hp)
        End Sub
    End Class
    Class AnimalMonster
        Inherits Monster
        Sub Growl()
            Console.WriteLine("{0} used Growl on you!", name)
        End Sub
        Overrides Sub writeToConsole()
            Console.WriteLine("Animal Monster: {0}, HP: {1}", name, hp)
        End Sub
    End Class

    Class HumanoidMonster
        Inherits Monster
        Sub DropKick()
        End Sub
        Overrides Sub writeToConsole()
            Console.WriteLine("Humanoid Monster: {0}, HP: {1}", name, hp)
        End Sub
    End Class
End Module
 

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Thanks alot. I will put this in a project and check it out.

I think it answers one of my questions, or at least, I know I'll learn something from it.

I want to load all the monster's from an XML file... which will have all their properties all setup.
 

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
When you use this line:
Dim monstersOnField() As Monster = {basicMonster, zombieMonster, wolfMonster, loinMonster}

Can I cycle through ALL the instances in that array using the index of monstersOnField() ?

If I have 5 zombies, 5 wolves, 5 lions in the array I can cycle through them using the index of the array, get and set properties?
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
When you use this line:
Dim monstersOnField() As Monster = {basicMonster, zombieMonster, wolfMonster, loinMonster}

Can I cycle through ALL the instances in that array using the index of monstersOnField() ?

If I have 5 zombies, 5 wolves, 5 lions in the array I can cycle through them using the index of the array, get and set properties?

Yes, you can loop through the array and get/set the items in the array. i.e i gave i used a for each loop, but you can use a index based loop if you needed to. i.e. you can see that i used the for each loop to call the methods of each monster, you can set a property the same way.


Quick example, i just modded the for each loop i used eariler, this is replacing the previous for each loop

'outputs
'Monster: monster, HP: 100
'Humanoid Monster: zombie, HP: 100
'Animal Monster: wolf, HP: 100
'Animal Monster: loin, HP: 100

'Attack Monsters... Target monster named wolf will attack you

'Monster: for some odd reason, HP: 100
'Humanoid Monster: for some odd reason, HP: 100
'Animal Monster: wolf, HP: 150
'Animal Monster: loin, HP: 150

        For element As Integer = 0 To monstersOnField.Length - 1
            'get the type of the monster
            'there are three types, the base, humanoidMonster, and AnimalMonster in this case
            If monstersOnField(element).GetType() = GetType(AnimalMonster) Then 'if it is of animalMonstertype
                monstersOnField(element).hp = 150

            Else 'for all of the other monsters
                monstersOnField(element).name = "for some odd reason"
            End If

            monstersOnField(element).writeToConsole()
        Next
 
Last edited:

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Is there a way to refer to an instance of an object based on a variable?


Dim targetmonster as string

targetmonster = "zombie"

if monster.name = "targetmonster" then

'respond a certain way, knowing that it's the 'zombie' instance you want to use
targetmonster.dosomething()

end if
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
lets see if i can clear things up a bit?

Dim targetmonster as string
targetmonster = "zombie"

if monster.name = "targetmonster" then
'respond a certain way, knowing that it's the 'zombie' instance you want to use
targetmonster.dosomething()
end if

Yes, thats kinda of what i've been doing in the previous code samples i posted. Here is a quick example

        'ex using one monster
        Dim targetMonster As New Monster With {.name = "zombie"}
        'lets create another monster too
        Dim otherMonster As New Monster With {.name = "other"}

        If targetMonster.name = "zombie" Then
            targetMonster.doDamage()
        End If

        
        'now lets say we added that object to an array of that object
        Dim monsters() As Monster = {targetMonster, otherMonster}

        'so if we were to call by index of the items in the array
        'monsters(0) ' this would be the 'targetMonster'
        'monsters(1) ' this would be the 'otherMonster'

        'lets say we do not know which one is the target monster
        'so create a loop and go through each of them and check the name property of it
        For index As Integer = 0 To monsters.Length - 1
            If monsters(index).name = "zombie" Then
                monsters(index).doDamage()

            Else 'lets say we also want to print out the name of the monster if we do not know it
                Console.WriteLine("The unknown monster is named: {0}", monsters(index).name)

            End If
        Next

        'here is an alt. loop. This uses the for each loop and does the exact same thing as the loop using an index
        For Each Monster As Monster In monsters
            If Monster.name = "zombie" Then
                Monster.doDamage()
            Else
                Console.WriteLine("The unknown monster is named: {0}", Monster.name)
            End If
        Next

        'using the previous class i posted
        'this is the output
        '
        'zombie was attacked!, Now has 99 HP
        'zombie was attacked!, Now has 98 HP
        'The unknown monster is named: other
        'zombie was attacked!, Now has 97 HP
        'The unknown monster is named: other



now let me try and explain what happen with the previous code i posted. This does basically the same thing except this goes through a loop and does it to each item in the array instead of just one.

Pseudo of the code
VB.NET:
For every monster in the array monstersOnField
    If this monster's type is animalMonster then
        If this monster's property 'name' is equal to "wolf" then
            Convert the monster from the base type 'Monster' to 'AnimalMonster' and call the method 'Growl()'
        (End If)

        Then as long as its a 'animalMonster' type, Call the monster's 'doHealing' method
    Else If this monster's type is not animalMonster then
        Call the monster's 'doDamage()' method

code from previous e.g.
        'For every monster in the array monstersOnField
        For Each Monster As Monster In monstersOnField
            'If this monster's type is animalMonster then (*note;there are three types, the base, humanoidMonster, and AnimalMonster in this case)
            If Monster.GetType() = GetType(AnimalMonster) Then
                
                'If this monster's property 'name' is equal to "wolf" then
                If Monster.name = "wolf" Then
                    'note that without casting it back to its derivied class you cannot call the Growl method
                    'since the base class Monster does not have that
                    CType(Monster, AnimalMonster).Growl() 'Convert the monster from the base type 'Monster' to 'AnimalMonster' and call the method 'Growl()'
                End If

                'this is a method from the base class
                'this will heal all animal type monsters
                Monster.doHealing() 'Then as long as its a 'animalMonster' type, Call the monster's 'doHealing' method

            Else 'Else If this monster's type is not animalMonster then
                Monster.doDamage() 'Call the monster's 'doDamage()' method
            End If
        Next



I hope that clears things up a bit?
 

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
I think I get it.

But if I had hundreds to monsters or items, I would have to initially hand type them into the array in the first place, right?

What if I was loading 1000 types of monsters from a text file or xml file?
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
But if I had hundreds to monsters or items, I would have to initially hand type them into the array in the first place, right?
What if I was loading 1000 types of monsters from a text file or xml file?

If you are loading the items then you need to first read those files using something like a xmlreader, xmltextreader, streamreader, io.file class, etc..
then while you are loading the items in from the xml through a loop, you can create your monsters there. or you can first load your data into an array and the use the array to create the objects through a loop later on.

and here's some reference links on msdn that may help if your unfamiliar with reading xml/text files.
for xml see
How to: Parse XML with XmlReader
XmlTextReader Class
for text
File Class
TextReader Class
StreamReader Class
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,553
Location
Norway
Programming Experience
10+
Unless you have a wolf by a specific name that is different from any other wolf you should probably be using Type comparisons to determine action taken, eg:
If TypeOf somemonster Is Wolf Then
    CType(somemonster, Wolf).DoWolfThing()
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
Thanks, John H. I didn't know you can check for the type that way.

If TypeOf somemonster Is Wolf Then
    CType(somemonster, Wolf).DoWolfThing()

is similar to
Flippedbeyond said:
    'from previous post ' excluding comments..
    If Monster.GetType() = GetType(AnimalMonster) Then
         If Monster.name = "wolf" Then
            CType(Monster, AnimalMonster).Growl()

Yours is much neater and faster. That will definitely come in handy. Thanks
 

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
I'm trying to understand this, but still having some difficulty.

If 'wolfmonster' is loaded from a text file that contains hundreds of other monsters, while the Streamreader is looping, how do I 'name' the 'wolfmonster' object.
For example if my text file is a simple flat file like this....

wolfmonster
25
wolf.jpg
zombie
30
zombie.jpg
birdmonster
30
bird.jpg


Where line 1 is the name, line 2 is the Hit Points and line 3 is a string pointing to a graphic for it, how do I declare the 'new' monster's instance name to be 'wolfmonster' ?
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
use the class constructor method: New()

while the Streamreader is looping, how do I 'name' the 'wolfmonster' object.
For example if my text file is a simple flat file like this....

wolfmonster
25
wolf.jpg
zombie
30
zombie.jpg
birdmonster
30
bird.jpg

Where line 1 is the name, line 2 is the Hit Points and line 3 is a string pointing to a graphic for it, how do I declare the 'new' monster's instance name to be 'wolfmonster' ?

Okay, say you have a class called 'Monster'. This class represents a blue print for making a Monster. The properties of this monster will be the Name, HP, and the Image. This means that anything that is of 'Monster' type will have a name,hp, and image, but these names/hp/images can be different values. Lets say for ex. this is the code for the constructor of your 'Monster' class.

    Class Monster
        Property storedName As String
        Property storedHp As Integer
        Property storedImg As Drawing.Image
        Sub New()
            storedName  = ""
            storedHp = 100
            storedImg = Nothing
        End Sub
        Sub New(ByVal name As String, ByVal hp As String, ByVal image As String)
            Me.storedName = name
            Me.storedHp = CInt(hp)
            Me.storedImg = New Drawing.Bitmap(storedImg)
        End Sub
    End Class


e.g. this class requires a constructor with three string parameters, since the default New() constructor without parameters is also specified it can be created without passing in parameters as well.
So using the class i just posted, if you were to read in the text file.

*first* if it is possible to change how your text file is formatted, i would recommend keeping one monster on each line by separating it with a delimiter. Like:
wolfmonster;25;wolf.jpg
zombie;30;zombie.jpg
birdmonster;30;bird.jpg

then when you read the textfile, use the Split method of the String class to separate it into an array by the specified delimiter.

So after you read the three properties from the text you can use the constructor of the Monster class to create a new Monster like such:

            While Not sReader.EndOfStream
                Dim nameProperty As String = sReader.ReadLine()
                Dim hpProperty As String = sReader.ReadLine()
                Dim imgProperty As String = sReader.ReadLine()

                Dim newMonster As New Monster(nameProperty, hpProperty, imgProperty) 'this line uses the constructor

                'here is another way to do it without using the overloaded constructor. This uses the default constructor New() and sets the properties using With syntax
                'Dim newMonster As New Monster With {.storedName = nameProperty, .storedHp = 100, .storedImg = Nothing} 'this line uses the empty constructor and sets the properties instead
                
                'if possible you really should use something to identify which line is the beginning of a new monster, or if you are just using the fact that where will always be 3 properties for each monster, then you should probably check that the total lines in the textfile is divisible by 3 or something.

                'then do something with your newMonster... add it to your Monsters array or something..
            End While
 
Last edited:

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Again, thanks for your help, I've learned so much about classes in the last few posts.

If we load the instances in that manner, I take it I will not be able to program each one later on using the

monster.doSomething()

method, as ALL of my monsters will be an instance called "monster".

Will I essentially have 100 or so objects, all called "monster" but with unique property "names" for each?
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
No problem.

Will I essentially have 100 or so objects, all called "monster" but with unique property "names" for each?

yeah basically. Just note that you are creating a reference to an object, they are not exactly all called "monster".

I believe the for each loop is what your referring to,
For index As Integer = 0 To monsters.Length - 1
    If monsters(index).name = "zombie" Then
        monsters(index).doDamage()
 
    Else 'lets say we also want to print out the name of the monster if we do not know it
        Console.WriteLine("The unknown monster is named: {0}", monsters(index).name)
 
    End If
Next
 
For Each thisMonster As Monster In monsters 'renamed for clarification
    If thisMonster.name = "zombie" Then
        thisMonster.doDamage()
    Else
        Console.WriteLine("The unknown monster is named: {0}", thisMonster.name)
    End If
Next

The for each loop in this example gets a reference to each object in the 'monsters' array as a 'Monster' type and names it 'thisMonster'. For example, lets say there are three Monster objects in this array. the first time through the loop 'thisMonster' will be a reference to the first 'Monster' object, the second time it loops, 'thisMonster' will be a reference to the second 'Monster' object that is stored in the array and then the third time around it'll be the third, and so forth it there is more.

Also note that an array can store duplicates, unless you do something to prevent that, so not every element in an array will have unique properties unless you make it so. ex. You could have made 10 copies of the same object and put it into an array if you wanted to.
 
Last edited:

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Is there anyway I can 'alias' an object's name as a string?

For example....

If a monster was called 'wolf'.

Dim targetmonster as string
targetmonster = "wolf"

'Then try to talk to the object with a string variable as it's name

targetmonster.doSomething
 

Flippedbeyond

Well-known member
Joined
Dec 19, 2008
Messages
198
Programming Experience
1-3
Is there anyway I can 'alias' an object's name as a string?

For example....

If a monster was called 'wolf'.

Dim targetmonster as string
targetmonster = "wolf"

'Then try to talk to the object with a string variable as it's name

targetmonster.doSomething

Can you elaborate on what your trying to do?

I'm not quite sure what your trying to accomplish by doing so, and if i understand correctly I don't think there is a way to do that..

?maybe someone else on the forum has a better suggestion?
 

mattkw80

Well-known member
Joined
Jan 3, 2008
Messages
49
Location
Ontario, Canada
Programming Experience
Beginner
Basically, if we look at this code:

For Each thisMonster As Monster In monsters 'renamed for clarification
If thisMonster.name = "zombie" Then
thisMonster.doDamage()
Else
Console.WriteLine("The unknown monster is named: {0}", thisMonster.name)
End If


This works fine, so long as I mention "zombie" specifically. The problem is, what if my game has hundreds or monster objects, or hundreds of inventory_item objects?

I'm trying to get my class methods to work with whatever my object's name is, without having to make specific reference to hundreds of potential objects, some of which don't even exist yet.


Matt
 
Top Bottom