Components In Coding

Hey. I’m testing out components in a little game idea I’m messing about with. How useful is it to you Python coders? I could see it being useful for certain uses (like an FPS or TPS or something, where each individual character or object could have a wide array of uses), but for other games, like an RPG, it doesn’t seem to be that useful…?

If anyone’s wondering, my (probably poor) understanding is that instead of implementing, say, the ability to pick up items into each NPC in your game, you give them all a common “ItemPickup” component that will find a nearby item and add it to their inventory automatically. I’ve already got a pretty good framework to work with here - I’m just wondering if other people use it as well.

So does anyone have any tips or ideas of how to use components correctly? Do you use them in your games? Do you find them particularly useful?

Components are similar to an always sensor (with true pulse) connected with a python controller.

They simply can’t be used in the context of the other logic bricks. As far as I see they do not provide additional benefits to the game logic.
Let me know if I’m missing something on that.

I meant class-based components. Like:



class Component(object):

    def __init__(self, ownerobj = None):
    
        self.on = 1
        
        if ownerobj == None:
            self.owner = logic.getCurrentController().owner
        else:
            self.owner = ownerobj
            
        self.activated = 0
        self.ltr = logic.getLogicTicRate()
        
    def Init(self):
        
        """
        Stub for component initialization.
        """
        
        pass

    def Update(self):
        
        """
        Stub for component update.
        """
        
        pass
        
    def Remove(self):
        
        pass


As well as functions to add components to a list, one to update all components in that list, as well as one to remove components from the list.

So far, this has had the effect of making this my Player code:



import Components
import Sprites
import BGHelper

def Player(cont):

    obj = cont.owner

    Components.GameObject2D(cont) # Run common 2D game object code (sprite animation, for example)
    
    def Init():
        
        if not 'init' in obj:
            
            obj['init'] = 1
    
            obj['animdict'] = {
            'stand':['MainChar', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
            'walk':['MainChar', 0, 2],
            }
    
            obj['sprcomp'] = Components.Find(Components.SpriteAnimate) # Get the sprite animation component
            obj['sprcomp'].anim = ['MainCharD', 0, 2]
            
            obj['controls'] = Components.Add(Components.PlayerControl4Way()) # Create a component to handle player's controls
            obj['gravity'] = Components.Add(Components.GravityControl()) # Create a component to handle gravity

        else:
            
            return 1
            
    def SetAnim(anim, facing):
        
        a = obj['animdict'][anim][:]
        
        if facing == 'L':
            facing = 'R'
        
        a[0] = a[0] + facing
        return a
        
    def Update():
        
        walking = obj['controls'].mv.magnitude > 0
        
        if walking:
            obj['sprcomp'].anim = SetAnim('walk', obj['controls'].facing)
            obj['sprcomp'].fps = 8.0
        else:
            obj['sprcomp'].anim = SetAnim('stand', obj['controls'].facing)
            obj['sprcomp'].fps = 8.0
            
        if obj['controls'].facing == 'L':
            obj['sprcomp'].flipx = 1
        else:
            obj['sprcomp'].flipx = 0
            
        obj['controls'].ground = obj['gravity'].ground
        
    if Init():
        
        Update()


I prefer composition to convoluted OOP hierarchies, so whenever I’m doing something a little larger than your average demo, I rely on a component based architecture.

I would have an Entity, or more generally a GameObject class, which would basically serve as a component container, running each active component on every tick. The Component class is just a template for a simple state machine, running currently active states.

It’s not a magic bullet, but I think it leads to far more manageable code.

You still have to think about the interplay between Entity and Component, and how to write generic components that work well together.

Generally, it helps to keep your components completely unaware of anything but the data and methods available in the Entity base class. So, if you have a PlayerMovement component, and the ability to jump when on ground, you don’t want to encode your algorithm for detecting “ground” in the component itself. Instead, you should define the onGround method on the Entity subclass, and pass that to the component.

That way, if you want to control some other object, where the method for detecting “on ground” is slightly different, you don’t have to change anything - just pass in a new function.

Simple example, I know, but even small things like that can translate into a big win.

Whatever you decide to do, don’t over-engineer. Do what makes sense for your current needs, with some thought given to how your needs might evolve, but know that you can’t make a perfect plan from the very start.

As you work on the system, you’ll hit moments of clarity, and whenever you do, you should basically rewrite the system to fit your new insights.

I know that people are reluctant to do that, especially when they have a whole heap of code written up already (and they spent so much time planning it out), but really, “doing it right”, even if it takes a long time, is usually much faster than struggling with a system that is clearly not fit for your new circumstances (that’s a struggle that can easily stretch out into years - which ultimately turn out to be years wasted).

PS:

On this page, Michael Abrash writes about his experiences working with John Carmack, on Quake, where Carmack basically followed this “scorched earth” policy: If something doesn’t seem to fit, it’s just thrown out, no matter how long and hard it took to initially develop.

BTW: If you didn’t read “Masters Of Doom”, by David Kushner - I highly recommend it.

I have never used this method before, it sounds interesting.

However, do a lot of the components end up only being used once, such as the player controls. Would it be better to just build that straight into the player class, also should every dynamic object be affected by gravity so why not build that into the entity base class and have a component to exempt the object from gravity if need be.

I can see that composition would be most useful for AI.

I don’t know if this’ll be useful to anyone, but I thought I might post it anyway. :S

Currently my method for components revolves around running a function to update components of objects, rather than deriving the game object from a base class of a common ‘GameObject’ class that does this (which I should probably look into), but for the time being, components seem to be handled alright.

First, you create a component object from a class. All component classes are derived from a common base component class, which just gives some basics (whether the component’s on or not, what object it belongs to, etc) and stub functions.

When you add a component (that you’ve already created from a class; i.e. c = Components.PlayerControl() ) from Components.Py (where the components are stored) with the Components.Add() function, it initializes the component (runs the stub Init() function, or the overloaded Init() function). Then, it adds the component to the current (or specified) game object’s component list. Each game object can only have one of each kind of component in it (so that you can’t have, for example, two sprite animation components for the same object messing with the animations).

Once a frame, the game object (through the common GameObject function) calls each component’s Update() function, giving it a chance to influence the game object it belongs to in some way.

If you want to alter a component, you can do so by finding the component. This is done by Components.Find(), and for the argument, you provide the class type. So, if you wanted to find a gravity control component, you would just do:

gravity = Components.Find(Components.GravityControl)

And then alter the settings easily:

gravity.force = 5.0

You can also find a component in another object (other than the one calling the Find function) using a second argument after the component class type to find.

If you want to remove a component, you can call the Components.Remove() function, which will remove the component from the component list, as well as call the component’s Remove() function, allowing it to clean anything up if necessary.

That’s pretty much it from me.