Class behaviour:how to manage them?

Monkey Forums/Monkey Programming/Class behaviour:how to manage them?

mteo77(Posted 2013) [#1]
Hello all.
At the moment i am not encountering any problems with my code (very strange of me!).
I was just wondering about how to approach different class actions, like movements, shooting, little bit of AI and so on.
I understand that a class should be self sufficient after being created.
Using as an example a shooter kind of game, what's the best practice to handle moving entities?
At the moment i have my class structured this way:
@ fields
@ fields declaration
@ a create function
@ methods that describe different kind of movements
@ methods that handle sub objects creation (like when enemy get destroyed it split in 2 etc etc)

The initialisation is called during the oncreate of the main app.
During the on update i execute the methods that take care of the movements and sub objects creation.
I am not entirely sure how to approach a simple sort of AI like "dodge object" or "shot at player".
At the moment i am handling this with class methods as well.
Is it the best practice?
Should i handle it in the main app on update instead?
Also i create objects this way.
Example:
AlienCreate(x,y,speed,stamina,movement,posx2,posy2,shooting)

As you can see i pass a lot of variables through the initialisation calls, so sometimes i have massive Create() lines just for few waves of enemies, since i want enemies to behave differently.
The code looks REALLY messy this way and i am pretty sure it's not the right way to do it (although it works for me at the moment...) its just very time consuming to initialise every single enemy this way..
Hope everything i said make sense.


Gerry Quinn(Posted 2013) [#2]
There aren't any rules about how you must do these things - it's really up to you how you want to organise it.

Basically a class is a chunk of data (position, velocity, age, ammo, whatever) and a bunch of functions (methods) that are to do with manipulating or accessing such a chunk.

It sounds like you have different types of aliens - you could use extended classes but it is probably simpler to have something like:

Local alien = New Alien( Alien.XWING )
alien.SetPosition( 100, 100 )
aliensList.AddLast( alien )


Here XWING is an int constant in the Alien class that probably has a particular ammo level, sprite, movement pattern, etc.. Maybe even some semi-random values. These get set when the alien is constructed with the constant value. Then you set any other needed things like position.

As for movement, if as is often the case there is only one player position, and it is the only thing that influences any alien's movement aside from things like its current position and movement, you might have a method like:
Alien.Move( timePassed, xPlayer, yPlayer )
..called during update.

It would be fine to have ways for the alien to know these parameters without them being passed too, though.

Hope that is some help in making things tidy.


Paul - Taiphoz(Posted 2013) [#3]
Yeah don't think there is a right or wrong way, just the way you happen to structure your code, I take a new source file per class, then everything related to that specific class goes into that single source file, then anything that acts on that class is a method , or function.

So all my space ships are in ships.monkey and any action I can take with a ship, like shoot, move, kill, explode, are all methods within its class.

and since I'm fond of lists and tend not to have many problems with them all my ships are held in a global shiplist, which is defined within the ship.monkey file as its part of the ships setup.

like Gerry said there are no real rules about how you do this, as long as your way is easy for you to understand and you do not get any kind of slow down as a result then go for it.


mteo77(Posted 2013) [#4]
I must admit i don't quite understand the line "New Alien(Alien.XWING)".
You said it's a constant in the Alien class that sets other variables.
How does it work?


Gerry Quinn(Posted 2013) [#5]
It would look something like this:




Of course you could have other types of aliens, and other variables to set.


mteo77(Posted 2013) [#6]
Oh i see, thanks.
That would be helpful to differentiate movements as well, i just have to put an extra variable in the constructor.
I think i just have to reorganize my code and try to automate as much as i can.
Thank you.


Skn3(Posted 2013) [#7]
Another way to approach it is to define a "ActorMovement" class/interface whose sole purpose is to control... Move the actor (or alien). An alien can be assigned a particular movement class and then will act in whatever way the movement dictates. For example:
Class Actor Abstract
    Field x:float
    Field y:float
    Field movement:ActorMovement

    Method OnUpdate(delta:Float)
        If movement movement.ApplyTo(self,delta)
    End
End

Interface ActorMovement
    Method ApplyTo(actor:Actor,delta:float)
End

Class MoveUp implements ActorMovement
    Method ApplyTo(actor:Actor,delta:float)
        actor.y -= 1
    End
End

Class Alien extends Actor
End

Function Main()
    Local alien := new Alien
    alien.movement = new MoveUp
End


The same method can be used for all manner of things such as ai and user input. Kinda like slotting functionality into your object.


mteo77(Posted 2013) [#8]
That sound interesting.
Will have to study classes a bit more before trying to use that method, but i can see already the possibilities of it.
Thanks!


mteo77(Posted 2013) [#9]
I have played a little bit with interfaces (trying to change some of my code examples)and i was wondering one thing.
I made different movement patterns all interfaced to the same movement class.
My "actors" don't have a movement at all when i initialise them, but instead i assign the movement field/class during runtime with the new command and i was wondering one thing.....if i keep doing this
If distance = 200 Then movement = New homing
If distance = 100 Then movement = New godown
If distance =50 Then movement = New goleft
If distance = 300 Then movement = New runaway

is it ok?
It works but i was wondering if i will consume too much memory, since i keep creating new objects (the movement one) without getting rid of the previous one.
In the above example i use the variable "distance" to set on the fly the movement field, so when the distance between me and an enemy change to the right value the movement changes as well...should i somehow delete the previous field that is no longer valid or will monkey get rid of it for me?
Sorry if it seems a silly question.


mteo77(Posted 2013) [#10]
Since it didn't feel right to keep "Newing" fields i made an array with all the relevant movements stored there (and initialised it during oncreate) so i can swap on the fly like this:
If distance = 200 Then movement = moves[1]
If distance = 400 Then movement = moves[2]



Gerry Quinn(Posted 2013) [#11]
Old objects that are not referenced any more will get garbage-collected by the system. So you won't run out of memory if you keep creating new objects (so long as you keep forgetting about them!). It can lead to some loss of efficiency, though, because the operating system has to find the chunks of memory that are no longer referenced, and mark them available for re-use.

Whether this matters depends on a lot of things. I don't really like the idea of creating a new AI object on every update for every ship, but if the object itself is small it might work fine. If it were me I would probably have a persistent AI that changes state occasionally.

If you have a limited palette of movement patterns, what you are doing is fine, so long as each 'movement' stores no information from the particular ship. If a movement depended on the ship that is moving, you obviously could not do it this way.

At the end of the day, you seem to know what you are doing, so don't worry too much about the 'right' way to do it. There are lots of right ways - what matters is whether you can understand / extend what's going on, i.e. whether it works for you. The way you choose to do this kind of stuff is largely a matter of personal coding style - especially in a flexible language like Monkey, which caters for a lot of styles.


Skn3(Posted 2013) [#12]
Since it didn't feel right to keep "Newing" fields i made an array with all the relevant movements stored there (and initialised it during oncreate) so i can swap on the fly like this:


Yeah that's better to be efficient with objects. On desktop it doesn't matter so much but on mobile it definitely does. The beauty of passing in the actor/alien into the ApplyTo method... Or whatever you call it, means you could essentially just keep 1 global copy of the movement object. Multiple actors could have their movement set to the same movement, very efficient! If you want something more complex such as MoveTo(x,y) to move an actor to a given point on screen, you'd need to create one per actor.

In my code I have a ActorMovement class which handles updating the actor in a particular way. It also handles creating ActorMovementInstance, which is used to store the runtime values for one version of the movement. This means I can create a MoveTo global object, let's say I want coins collected to move to one place on the screen. I would create a MoveTo object and set the x,y. This is now a blueprint I can create instances of. A coin is collected, a MoveToInstance is created, the MoveToInstance is used to update the actor coin and move it to the predetermined location on screen. When it reaches the location, I delete the instance but keep the MoveTo blueprint ready for the next coin.