BGE class Work Flow

First, I’d like to thank the community for sharing all their skills. I seen a lot of great examples here at BlenderArtists.org but what I don’t see often enough are examples of true OOP done with the blender API. I am curious and like to pick-up some better habits and work flow from this pool of talent. As an example and in your own opinion, how would you design a class or classes for multiple charters or enemies and implement them as individuals.

Happy Blending to all.:slight_smile:

To be honest Python is OOP and therefore all code you do with it is OOP as well. OOP does not mean you have to define your own classes. It is enough to use already defined classes to be OOP ;).

If you want OOP, see Novus Terra. I too use OOP behaviours in my game, but for simple games it is already object orientated so as Monster said, there is little distinction between the two:
http://code.google.com/p/novus-terra-code/source/browse/#svn%2Ftrunk%2Fsrc

Yes. You are right Monster. I still consider myself a noob at Python, yet I have done some reading and as I understand, everything in Python is Object Oriented including ‘classes’ which is also referred to as ‘objects’. Every object has certain characteristics, or ‘properties’, and certain predefined functions, or ‘methods’. These properties and methods of the object correspond directly with the variables and functions within the class definition. What I see most commonly used with the Blender module is the standard function…

def main(cont):
obj = cont.owner

I want to expand my Blender API work flow with all the ‘Python objects’. I would like to learn how to also use Blender Objects with class objects and be able to expand those objects with subclasses as well, that way I could have a full understanding how Blender objects works with Python objects. I understand classes in the Python general text book context. If I was to form this into a question, I would ask. What would be an example of a proper work flow for a Blender object to get attributes from a class so that I am not typing the same code for every object as well as not to have the objects share or duplicate every attribute such as, for example, hit points, collisions, etc.

Classes don’t really help out that much in my experience, though it is possible to cast game objects as normal Python classes that you can access and subclass. It would probably be better if you made common game object functions, rather than using Python classes and sub-classing them out. You could even think of the game object functions as components that you build different enemy behaviors out of. As an example:



def EnemyCommon(cont):     # Common enemy setup

     obj = cont.owner

     def Init():

          if not 'init' in obj:
          
               obj['init'] = 1
               obj['health'] = 100 # Set your health
               obj['enemy'] = 1 # Tag yourself as an enemy, so to speak
  
          else:

               return 1

     def Update():

         Walk()
         Aim()
         if obj['health'] <= 0:
              Die()

     if Init():
          Update()
     

def Walk(destpos, movespeed):

     pass # Code for walking

def Aim (target):

     pass # Code for aiming

def Die (obj):

     pass # Code for dying when an enemy's health < 0


The EnemyCommon() function does everything common enemies would need to do, like move, aim at targets, and die when their health is too low. You can replace the ‘stub’ functions above with actual code, of course, but you can also substitute your own functions if you need specialized enemies (i.e. one that doesn’t aim, or that explodes on contact with the player).

In truth, the EnemyCommon function above is a bit specialized already, since not every enemy will move or aim - the common function should probably be setting up and performing common tasks that almost all enemies will need to do, like die when their health gets too low.

The good thing about this approach is that it’s still modular - you can, for example, make the Die() function drop a base number of gold when an enemy dies. Then, you can replace the gold amount with a custom number per enemy if you want by executing a special enemy function:



def Guard(cont):

    EnemyCommon(cont)

    #... And so on.


As a side note, while I use a return 1 above on the enemy’s Init() function, that check will run every frame the enemy computes logic. It might be better to simply go ahead with the Update(), and if an error arises, catch it and initialize the object (so that it will only do it once). However, I usually end up checking to see if the game’s properly initialized anyway (i.e. after the camera / global variables have been set up), so your mileage may vary.

i also want learn how using classes, but in a way usefull (if exist)
in my experiment with class it seem just a “module redundant” (ie: a module more slow and more repetitive)

the big issue is that you have a sort of double object , very annoyng:
-self
-self.owner

when in the “module level” this is more simply only one thing

i guess i had used the class in the wrong way!

They point is to see that you need multiple classes. One class for each purpose.
People tend to create one big class that contains all. As soon as they have it they realize this is not very flexible and maintenance is quite hard.

What you really need is to model the relationship between different objects. E.g. the status of a “RPG character” in relation to its 3D representations.

For example:

  • does a RPG character (your own Python object) has a 3D Model as representation in 3D space (KX_GameObject)
    or
  • does a 3D representation in 3D space has a RPG character
    or
  • both

Which one represents you game model?
You can do both. But in a lot of cases it is a good way to keep model and view (visible representation) separate. This would allow to use the model within a different visual visualisation (e.g. high detailed environment and low detailed environment - the game logic (game model) stays the same).

@SolarLune

I suspect that Python compiles-out the inner functions whenever possible, but I’m pretty sure that it has to rebind the function names on the stack whenever EnemyCommon is called. It’s probably negligible, in terms of overall performance, but it’s good to know.

As for your approach (I assume you would welcome feedback): The “nested function” style seems very out of place. Even if we ignore the potential performance pitfalls (which I think we can actually do safely in this case), there’s the question of necessity, because this would work just as well, loosing nothing in clarity:


def EnemyCommon(cont):

     obj = cont.owner

     if not 'init' in obj:
          obj['init'] = 1
          obj['health'] = 100
          obj['enemy'] = 1

     Walk()
     Aim()
     if obj['health'] <= 0:
          Die()

There’s no need for nested function declarations - They have no clear benefits, and actually complicate the overall structure.

Actually, in addition to being easier to type, self.var is shorter than obj[“var”], and there’s no need to type self.owner if you subclass from types.KX_GameObject - self is the owner, and the actual object available in scene.objects.

That said: self is just a conventional variable name for the current instance. You can use something else (shorter), if you want, but I wouldn’t recommend it, because self is common convention, and short enough already.

Even if you’re a beginner programmer, you probably know that most of your time is spent on thinking rather than typing, so saving up on a few characters is not going to produce significant productivity gains.

+1 for a very well worded, practical post.

I’m not sure what you meant by the top half of your post. Are you saying that nested functions run slower (I’m just having a hard time understanding)?

As for the second post, yeah, I welcome feedback. I use nested functions because often I need to separate my code into sections - it helps readability to me, particularly as I use an external code editor that allows me to collapse function definitions. So, I don’t have to look through the object initialization code if I don’t want to, for example.

While the folding works for if statements as well, some sections don’t start with if-statements. Using nested functions allows me to collapse behaviors (i.e. aiming at a target) into sections as well. In any case, I do agree that it’s probably not good practice to tell others to use nested functions, and it might be a little slower than usual. Maybe I should separate those functions out, rather than keeping them nested.

I outlined how I usually do OOP in my games. It may be worth a read, especially how I use getattr and setattr to make a class act like it’s a KX_GameObject class.
http://andrew-101.blogspot.com.au/2012/01/object-orientated-approach-to.html

I think this should explain it: http://stackoverflow.com/questions/7839632/is-there-an-overhead-when-nesting-functions-in-python

@andrew-101

Actually, you don’t have to “fake” KX_GameObject inheritance. There are a few quirks to it, but it works just fine. You can watch me demonstrate it in many of my tutorials, Simple AI being the latest.

Monster
I agree, keeping classes short and/or the methods within the classes focused on a direct purpose for each. That is where, I believe, classes become very beneficial. If I understand correctly, it would be wise to initialize a base class that shares a common denominator with all the objects I wish to inherit like for example an Actor class that initializes with a base structure of attributes that all actors within the game will have as well as a method for each common action like movement, health, and whatever else all actors would share as a base structure. The next layer a subclass would be more specific to an object that inherits everything in the super class, of course, as well as with some added features like different types of guns (which could come from a completely separate class of weapons as well. This could continue to build and even override at any level. And this is what I mean by a ‘true’ OOP. Just because everything in Python is objects, does not necessarily mean it is OOP, rather most of Python is just Object Programming; at least that is what I read in Mark Lutz book, “Learning Python 4th Edition.” For example, a function object is not really oriented; you either call upon it or not call upon it.

SolarLune
Your two part tutorial on 2D Sprites has inspired me to make a game of my own. It is working very nicely at the moment and before I continue with the main game operations, I want to acquire a good work flow for optimal performance to prevent lag time as the program keeps growing and I think classes’ for similar objects kills two birds with one stone. I like the class optimization as it naturally initializes once without having to nest a function declaration and be able to build/override upon it. I also like the idea of inheriting common attributes and actions than rewrite the same code for initializing every charter that naturally have the same attributes.

Angoose77
Although not posted on this thread; I really like your optimization tips. You are teaching me very good work flow habits. Thank you.

Andrew-101
I really like your organizational work flow. I like the way you organize your directory for a game project. I also think faking a KX_GameObject is quite brilliant and I can see that you have put a lot of thought into it. It just seems like having to rewrite an API that is already provided.

Goran
Your AI tutorial is exactly what I have been seeking. I do not know how I missed it before. I like your style. You’re not class crazy just because you know how to make classes. I hope this thread does not give the wrong impression. I don’t believe classes should be uses for everything and you use them as they should which is when needed. You have a nice work flow that keeps it simple and optimized.

Again, I am learning a lot from all you gurus. I enjoy picking all your brains of talent. Keep sharing with tutorials and forms like BlenderArtists.org because it is definitely being noticed and appreciated. If there are any other sources of reference, please let me know. I hunger for this kind of brain food every day.

I’ve carried this method across from 2.49 when a lot more things were read only (couldn’t do cont.owner = Player()) and it wasn’t possible to inherit KX_GameObject. So its great to know these things are now possible, I really like your method.

The BGE is object orientated because you are working with objects ;).

Even a class with just functions is object orientated (it just does not benefits from OOP-approach).

The whole point is a OOP class hierarchy is already present. Unfortunately with the 2.5 API Documentation it is not that easy to see. Since 2.49 it was looking like Java-Docs including the class tree. The current one looks more modern and is the same as used by Python but it is harder to use (especially as many class documentations are placed in one large page).

If you want to build your own class hierarchy I recommend you implement an internal model of your game (as in MVC). The objects provided by the BGE can build the “View”. The “Controller” part can be in both.

Thank you Monster. Am I understanding this modified version of a MVC correctly?