Custom Python Classes.

This is something I’ve been wrestling with for all of the time that I’ve used the BGE.
As soon as I started to learn python I ran in to the idea of classes and wondered what they are and why I should use them.

I’m not a professional programmer, this is just my hobby, so I wanted more than just “It’s the way to do things”.

It wasn’t clear to me (and remains a mystery to some other BGE developers I know) why it’s better to use a class than another structure. So here’s an explanation of why classes are useful and why you should definitely use them if you’re not already:

***1. You are already using classes!
The KX_GameObject is an class/object. When ever you add a object in game you are adding a new instance of that class.
You can subclass it to add more functionality if you want. When you use:

own.worldPosition = [1.0,0.0,0.0]

You are using a class method.
Ditto:

own.rayCast(other)

When you set a property on an object that is similar to the way you set attributes on a class (but not exactly the same, it was changed once upon a time).

Wouldn’t it be great to make thins that behave like a gameobject? Imagine if you have a player and you can do:

player.die()

Tying a function to a class (making it a class method) makes your code much simpler and easy to understand than having all your functions floating around in your code. (and it doesn’t make them less reusable as I’ll show later).

***2. Classes can be Complex!
At first I made very simple classes:

class Player(object):

    def __init__(self):
        self.health = 4
        self.ammo = 100
        self.dead = False

And I wondered why use that if I could use a dictionary instead:

player  = {"health":4,
    "ammo":100,
    "dead":False}

The answer is that there’s no real reason to use a class instead of a dictionary or list or something else if all you’re doing is storing some data.

On the other hand if you want that player to do something, like pick up keyboard input or have an AI or move, jump, do animations etc… it’s time to use a class. Of course you could use a gameobject as your class and attach a script to it.

def player(cont):
    own = cont.owner
    if "ini" not in own:
        own['health'] = 4
        own['ammo'] = 100
        own['dead'] = False
        own['ini']= True
    
    forward = cont.sensors['forward']
    if forward.positive:
        own.worldPosition.y += 1.0

But sooner or later you’re going to run in to limitations with that. One problem is that any in-game object is rarely a single object. You usually have a collision box, skeleton, skin, other components etc… Maybe it makes sense for the collision box to be the “main” object, but it can be cleaner and more organized to contain all those objects in a custom python object. The other problem with these “hybrid” objects is they can be very messy. That’s because a large part exists as a collection of objects and logic bricks in Blender, while the other part exists as some code in a script. If you want to change something about it you have to keep both parts in mind so that things don’t get broken.

Honestly, almost everything you can do with logic bricks you can do with python with a better degree of control. Isn’t it more flexible to keep everything in once place? My Agent object in Blender consists of a collision box with an armature parented to it and a skin parented to that. That means with a skin change and a code change (which can be done on the fly) I can use that agent to be a player or an ally or an enemy.

I can also set up the agent as I create it.

enemy_1= agents.Enemy("player_object",health=50,location=[12,56,128], gun="AK47",AI_mode="Patrol")

I don’t have to add a player to the game, then move it to where I want it to be and mess around setting it up.
This is very useful when saving or loading a game.

***3. Use templates to reduce the amount of code in your project.

I can also set up variations of the basic agent by subclassing it. A subclass is a version of the main object with some changes. So if I have a base agent:

class Agent(object):

    def __init__(self,scene):
        self.scene= scene
        self.add_game_object() 
        self.skeleton = self.game_object.children[0]
        self.dead = False
        self.mode = "patrol"
        self.animation_type = "agent"

    def add_game_object(self):
        self.game_object = self.scene.addObject("agent_object")

    def set_AI_mode(self):
        do_AI(self.mode)
    def animations(self):
        self.skeleton.playAction(self.animation_type,0,20)
        ...

Then I can set up all the code for it at one time. The I make a version of it with slight differences:

class Monster(Agent):

    def __init__(self,scene):
        super().__init__(scene) 

        self.mode = "attack"
        self.animation_type = "monster"

    def add_game_object(self):
        self.game_object = self.scene.addObject("monster_object")

Now my monster will work just as I want it to with only a few lines of code. That’s surely better than copying and pasting all the code from my agent script and rewriting it for a monster script. What if something doesn’t work in the agent and I don’t notice until later? Then I have to go back and rewrite all my agents, trying to remember how monsters are different from ghosts.

1 Like

Part 2:

  1. Classes can help you better structure your project.

Often, opening someone else’s Blender project it’s hard to know what’s what. I have to dig around in the layers, find out which scripts go with which objects, check if they’ve got files in external blends which they are importing etc…

When I start reading the code it can also be difficult to understand. There’s usually a few scripts consisting of a very long set of if/else arguments, and maybe some functions, though it’s not always clear who those functions are intended for.

If I want to rewrite how something works I have to change everything about it, like its game objects, logic, sound effects, particles, how it is controlled, how it is saved and loaded… If I want to add something new, it can be a mammoth task. I have to go through an existing thing, copy and paste bits of code (probably introducing new bugs) rewrite how other objects in the game react or interact with it. It’s a nightmare no sane person would undertake.

I recently opened one of my own old projects in blender2.49b and couldn’t make head nor tail of it. I wrote it and I don’t understand it!!

These days I try to make a modular hierarchy in my projects which makes it easy to reuse the same modules over and over again in new projects. I can have an audio system up and running in minutes, likewise particle control, AI, level building, save and load etc… and each part of that hierarchy consists of classes.

I have a GameLoop class which handles startup and calling all the various sub-parts of the project. This class has a finite state machine, so it can easily be switched to different states: Paused, menu open, loading, etc…

Within the game loop I have various other objects:
Camera control,
Player input,
The particles object,
The audio object,
The agents object,
Level builder,
Save/ load system,
Options and menus,
UI…

And within those I have all the individual objects of that type.

Game loop calls update() on each of its sub-components, and they in turn update() all their children.
All the children have a link up to the game object so they can call back down to other components.

For example if I want an agent to create a blood particle, it calls


import particles
particles.Blood(self.game_loop, self.game_object, color= [1.0,0.0,0.0])

Within the particles class the blood object creates a game object to represent itself in the game world, it might call up a “splat” sound effect in the audio manager, it will add itself to the particle managers’ list of particles via the game loop.

As long as I keep that method of calling particles I can go back and rewrite the particles class completely without having to rewrite agents or audio or anything else. Think of it like a car with modular components. I can switch out the engine for a more powerful version without touching the gas tank or tires at all. Or instead of rebuilding the whole engine I can just copy it with a few improvements or modifications for a particular game type.

***5. The main problem with classes is not a problem at all.

One question I had with classes was how to save them. You can’t just add a custom python object to global dict and save it to disk. It may contain things that can’t be marshaled. And when I want to load them back up again, how do I call new objects from a dictionary that probably consists of nothing more than strings, ints and floats?

Well, I found a solution today.
I had been considering writing a long if/else chain. But that’s not very flexible. What if later I want to add new classes, all those if/else arguments need to be rewritten.
Some people said that using eval() could be useful, but what if someone writes malicious code in to a save file? That seems like a recipe for disaster…

It turns out I can use globals() to get the classes I need:

(Stack overflow is your friend!)

So first I save an object:


def save_agents(self):
    unique_id = 0
    export_agents = {}
    for agents in self.agents:
        agent_name =  agent.__class__.__name__
        key = "{}_{}".format(agent_name,unique_id)
        unique_id += 1
        export_agents[key] = [agent_name,list(agent.game_object.worldPosition),agent.health]

The later I can load it:


def load_agents(self):
    for agent_key in importing_agents:
        agent_type,position,health = importing_agents[agent_key]
        agent_class = globals()[agent_type]        
        new_agent = agent_class(position,health)
        self.agents.append(new_agent)

There! Simple as cake!
This doesn’t just work with agents, it can be used with particles, sounds, items, weapons, bullets or anything.
There’s really no reason not to use classes, and at least 4 good reasons why you should.

***One final note:
If you ever want to move your project to another game engine you’ll find it a lot easier if you have a modular, hierarchical system like this. Rewriting your classes in another programming language shouldn’t be that big a deal, and will mostly consist of finding what game_object.rayCast() or mathutils.Vector() equates to in the new API.

Attachments


Yes, I like to reduce my logic bricks amount to a minimum, and keep all my scripting in external files, but i have read, that logic bricks run faster.

Anyways, great advice, Smoking_mirror.

Classes are very very useful, but they are only a tool and capable of being over-used. I often find it better, instead of mutating a game object, to store a reference to it. It helps keep the MVC model (which is very useful).
That said, this is a very useful resource and I haven’t come across that method of saving classes before.

They can run faster, if the code is simple and if you make good use of states to only run checks when needed, but most logic brick setups have sensors running all the time making unnecessary checks. Take an example of doing an on screen button. You have to mouse over it an press the left mouse button to trigger it.

With logic bricks you have a mouse over sensor and a mouse button sensor.

Every tic blender is checking mouse over and button presses.

But think about it, the button can only trigger if the mouse button is clicked. So in python we only check mouse status every tic (the least processor intensive check of the two) and then only do a mouse over check if the mouse button is clicked. Even then it’s best to do a screen ray to find out what’s under the mouse (one check) rather than checking each object to see if it’s under the mouse (one check per object).

I’m not a good enough programmer yet to be able to understand and implement all of this, but I am able to appreciate the beauty of the logic in these things.

Thanks for making this resource Smoking_mirror! It’s inspiring! ^ ^

Keep at it!

One thing I forgot to mention if you want to use the save/load from globals trick you should put the classes you need to use in a module and then expose them by importing:

from agents import *

Then all their names will be in the globals dictionary.

If you wanted you could build a specific dictionary instead if you wanted to avoid cluttering your code with lots of unneeded classes and functions. But using globals requires less maintenance as it’s all there automatically.

Someone made a class thread not to long ago. Well maybe its been a while, trying to break it down but it still didnt click with me. I’ll agree with john on this. I can do all kinds of things in BGE python. Functions, data manipulation, networking stuff - you name it, I can do it. So what is the benefit to me using classes. I can see you explaining why, kind of, but I dont see WHY. Sorry if that sounds confusing. I did have this problem with functions at first, then it clicked and when it did I was like “oooooooh thats convenient, more legible, and I can do it when I want, without a mess.” Of course it took forever for it to click with me because anything that could be done with functions, I could do without functions, so I couldnt get the “why”. I think its the same with classes. Me and you have discussed things before, but i cant get classes to click. I think its that I dont understand how to use them or the neccessity of them. Ill start with something thats confusing

The first problem:

def init(self,scene):

Two things with this. I see this all the time in the more complex python scripts/modules. Especially relating to classes. What does this do(init). Is this an initialisation function? How does this differ from


if not 'init' in own:
         own["init"] = 1
         do this stuff once

How would i use init, and how would it benifit me and how does it benefit me over using it the way I displayed. What are the double underscores for? what do they do? why do I use them?

Also I see “self” alot. I see it ‘called’ alot throughout the scripts. My mind makes me think of self as own(the owner of the script). Is this my head playing tricks with me or is it basically the same thing

How do I use self and whats the benefit to me? They seem alot like properties. Example:

Is?


class Player(object):

def __init__(self):
            self.health = 4
            self.ammo = 100
            self.dead = False

The same as?


own = cont.owner
def init(own):
            own["health"] = 4
            own["ammo"] = 100
            own["dead"] = False

It looks like your assigning variables(properties) to the object, Just that the object happens to be a class. I just dont see why

Are these the same, are they different? How?

I do appreciate what your trying to teach us but your going to have to break it down further so that I can understand. Im willing to learn =). Theres plenty more questions but I got to take it one step at a time.

Superflip, I am the same way,

The only reason I see to use a class is to make a ‘generic’ base, to then make subclasses of that inherited what the base class had,

however it seems to add complexity in my use case, as my enemies behaviors are defined by the pieces they are made of, Not by the class they are constructed from.

the only area I HAD to use a class was to use the collision callbacks and have access to self/own

As I said in point number 1, you are already using classes.

self.health 

is nearly the same as

own['health'] 

In fact if you go back in time a while (blender 2.4?) you’ll find that gameobjects used to use the same method for assigning properties, i.e.

own.health = 10

We are so used to using game objects that we forget that it is a kind of class/object.
But you can imagine it would be rather difficult to use BGE if there was no gameobject class. You’d have to write a script for every object you wanted in game (for example the default cube), which would control how it was handled in the game. Imagine having to handle vertex transformations every tic, manually do rendering, handle collision etc… All for a single cube.

Imagine I’m making a new game engine without classes. The first thing I do is write a script for a default cube. If I wanted to move the cube in a different way to the default behavior I’d have to open up the cube script and rewrite it. If I wanted a different cube to move differently I’d have to copy and paste all the cube script and change the parts that I wanted to be different. If I wanted a gun that fires cubes I’d have to write a new script for every bullet.

The Game object class makes things easy by containing everything in an object which can be duplicated, modified and deleted. It’s easy to see the benefit of using classes, even though you might not realize you are using them.

However, rather than have just one class, the KX_gameObject, it can be much more useful to have other classes for other things.

***I might seem normal to do:

if not 'init' in own:
         own["init"] = 1
         do this stuff once

But this is a kind of workaround to get class type behavior from non class code. The game object already has an initiation step, this extra step is needed if we don’t have access to that initiation routine.

def __init__(self):

This is a very powerful tool, because as well as doing what the above workaround does, it can act as a function, able to receive extra startup parameters. Imagine you’re adding a cube but you want it to be purple. Then you can include that in the initiation:


class Cube(Object):
    def __init__(self, color):
        self.color = color

cube = Cube(color=[1.0,0.0,1.0])

Now the cube will be added and will be purple.
You can do this to add objects which are customized just how you want them. If you want to add a monster who is partially damaged already you can do it.

***Being able to add objects, and customize them is great, but the real usefulness of classes comes from being able to keep data local to the object which needs it.

Remember, a class doesn’t have to be a physically real thing in the game engine. I think a good example could be a Jump class.

Imagine I want my player to jump. I want him to be able to double jump in fact.

So I create a jump object:

class Jump(object):
    
    def __init__(self,game_object):
        self.triggered = False
        self.timer = 0
        self.double_triggered =False
        self.game_object = game_object
        self.upforce = mathutils.Vector([0.0,0.5,1.0])
        self.falloff = 0.95
    
    def trigger(self):
        if not self.triggered:
            self.triggered = True
        elif not self.double_triggered:
            self.double_triggered = True
            self.timer = 0    
    
    def update(self):
        if self.triggered:
            self.timer += 1
            
            jump_force = self.upforce.copy()
            for t in range(self.timer):
                jump_force.length *= self.falloff ## the power of the jump is scaled by the time it has been active
            
            self.game_object.applyImpulse(jump_force)

### not tested!!! :)

Now I add a jump object to my player:

own['jump'] = Jump(own)

And if I want my player to jump I trigger the jump:

own['jump'].trigger()

If my player lands back on the ground I can just add a new jump object and all the attributes of the jump will be reset to default ready to be triggered again.

own['jump'] = Jump(own)

If I don’t do this I have to write a function for jumping, I have to keep track of that in my game object script, I have to reset the jump every time I land on the ground again and so on. If I want a monster to jump higher than the player I could write a subclass of Jump with a bigger upforce value:

class MonsterJump(Jump):
    
    def __init__(self,game_object):
        super().__init__(game_object) 
        self.upforce = mathutils.Vector([0.0,1.5,2.0]) 

If you have a lot of functions for my player the ini section can become very cluttered. Here’s an example from an old BGMC entry of mine:

def player(cont):
    own = cont.owner
    scene = own.scene
        
    if 'ini' not in own:
        own['player_state'] = "IDLE"
        own['weapon_state'] = "IDLE"
                                
        own['jet_fuel'] = 200
        own['max_jet_fuel'] = 200  
        own['jump_timer'] = 0.0  
        own['jump_speed'] = 0.0
        own['jet_flame_pulse'] = 0
        
        own['max_armor'] = 100  
        own['max_health'] = 100
        
        own['movement'] = 0.0
                                
        own['turning'] = True
        own['turning_timer'] = 0.0
        own['wall_blocked'] = False
        own['jump_triggered'] = False
        own['on_ground'] = True
        own['on_right_edge'] = False
        own['on_left_edge'] = False
        own['scrabbling'] = False
        own['scrabble_count'] = 0
        own['scrabbled_once'] = False
        own['on_elevator'] = False
               
        own['facing'] = "right"
        own['crouching'] = False 
        own['running'] = False
        own['walking'] = False
        own['aiming'] = False
                
        own['current_weapon_mesh'] = "starting"
        own['weapon_cycle'] = 0
        own['weapon_burst'] = 0
        own['max_weapon_ammo'] = 100
                
        own['falling_count'] = 0
        own['damage_recycle'] = 0
        own['being_hit'] = False
        own['dying'] = False
        own['game_over_count'] = 0
        own['game_over'] = False
        own['restart'] = False
                             
        own.addDebugProperty("player_state")
        own.addDebugProperty("on_ground")
                
        own['main_control_object'] = [ob for ob in scene.objects if ob.get("main_control")][0]
        own['hook_object'] = [ob for ob in own.children if ob.get("agent_hook")][0]
        own['skeleton_object'] = [ob for ob in own.childrenRecursive if ob.get("skeleton")][0]
                
        own['weapon_object'] = [ob for ob in own.childrenRecursive if ob.get("weapon_mesh")][0]
        own['armor_object'] = [ob for ob in own.childrenRecursive if ob.get("armor_mesh")][0]
        own['jetpack_object'] = [ob for ob in own.childrenRecursive if ob.get("back_pack_mesh")][0]
        own['bullet_adder_standing'] = [ob for ob in own.childrenRecursive if ob.get("bullet_adder") =="standing"][0]
        own['bullet_adder_jumping'] = [ob for ob in own.childrenRecursive if ob.get("bullet_adder") =="jumping"][0]
        own['bullet_adder_crouching'] = [ob for ob in own.childrenRecursive if ob.get("bullet_adder") =="crouching"][0]
        
        own['upper_hitbox'] = [ob for ob in own.childrenRecursive if ob.get("upper")][0]
        own['lower_hitbox'] = [ob for ob in own.childrenRecursive if ob.get("lower")][0]
        
        own['ini'] = True  

That’s 68 lines just for initiation! It would be far better for much of that to be localized in to a few classes.
All the stuff about jumping and jet fuel should be contained in a single class so I don’t have to worry about resetting it every time. Things like own[‘scrabbled_once’] are there because I have to tell the script that it has been reset. With a class you wouldn’t need to do that. Just recreate the class and it’s back to square one.

property changed----------python

property not zero----------python

property less then zero------python

can save you a ton of logic time, by only executing python you really need*

can we bind our own events to the property in the format of

own.timer ?

Well it’s not so much about saving time but about being more organized. It’s like having a robot that puts itself away when it’s finished instead of you having to tell it to go back in the cupboard.

If you write a project for someome you can tell them “this is a jump object. Trigger it to jump and re-instance it to set it back to normal.” They don’t need to know how it jumps, just that it does. You can create a character and give it methods like character.walk(“forward”) so it is easy for other people to use it. They don’t need to understand it in order to get it working in their games.

You can bind functions to a class so they become methods of that class. No one else can use that method. The method has access to all the self.stuff without having to pass it as arguments of the function. That makes things cleaner and simpler righg there.

Are there any good examples of how to call init(self, scene) or init(self, owner)? Sometimes I can get this to work and sometimes I get “TypeError: init() takes 1 positional argument but 2 were given.”

ALSO, I am especially interested in examples of calling init(self) from logic bricks. I gather that a separate

def init(cont):

function needs to be called in each case but I am only working from one example.

Don’t call init from your script. When you create the object init is called automatically.

The class has a special argument “object” which needs to be in the class definition.
In the init part you need self to be the first argument then any other things you want to feed it.
When you create an instance of a class you don’t pass self. Only the other things you want to give it. Look at the Jump(own) example above. Init has (self,game_object) as arguments but I only send the game object.

EXAMPLE:

import bge

### here we declare the class, it won't run any of 
### the methods in the class at this 
### point though
class CubeRotate(object):
    
    def __init__(self,cube,speed):
        
        self.cube = cube
        self.speed = speed
    
    ### this is a class method, 
    ### you can run it from outside, see (a) below
    def reverse(self):
        self.speed *= -1
    
    ### this is an update method, (b)
    ### you run it each tic to make the class do something.        
    def update(self):
        self.cube.applyRotation([0.0,0.0,self.speed])       

### declare the cont, own as normal
cont = bge.logic.getCurrentController()
own = cont.owner

### this is a kind of init cheat for blender python scripts
if "cube_controller" not in own:
    ### here we create the instance of the class
    ### see how I pass it own and a speed
    own["cube_controller"] = CubeRotate(own,0.02)
    ### notice that I don't run init from outside, 
    ### it is run automatically by the class when the instance is created

### a keyboard sensor
switch = cont.sensors['switch']

if switch.positive:
    ### (a) here we run the class method by calling 
    ### it from our instance which is stored as a property of own
    own["cube_controller"].reverse()

### (b) and we have to update every tic, 
### but don't worry this doesn't drain your resources much
### unless you ahve hundreds of instances running comples updates
own["cube_controller"].update()  


I’ll attach the blend file for you to take a look at.
cube_rotate.blend (435 KB)

This tutorial might help you understand, why you don’t need to pass self there.

Let’s not forget about object mutation :slight_smile:

You can use inheritance to mutate/change the builtin classes.


from bge import types

class Player(types.KX_GameObject):
    def __init__(self, own):
        self.health = 100


By passing a KX_GameObject (aka any kind of object) as parameter of Player, you automatically mutate it. So it isn’t a KX_GameObject anymore.

If you do this:


def main(cont):
    owner = cont.owner
    print(isinstance(owner, types.KX_GameObject))
    owner = Player(owner)
    print(isinstance(owner, types.KX_GameObject))

It will print:


True
False

The most awesome advantage of using this is that you can access any property/method from the original object:


from bge import types

class Player(types.KX_GameObject):
    def __init__(self, own):
        self.health = 100
        print(self.name)
        self.playAction("someAction", 1, 100)

def main(cont):
    owner = cont.owner
    owner = Player(owner)
    

Extra: UPBGE

By UPBGE v0.0.6 we added a Component system. It’s a completely new way of programming the game logic and It makes 100% use of classes:
(http://doc.upbge.fr/releases.php?id=0.0.6)


<b>import</b> bge
<b>from</b> collections <b>import</b> OrderedDict


<b>class</b> <b>ThirdPerson</b>(bge.types.KX_PythonComponent):
    """Basic third person controls

    W: move forward
    A: turn left
    S: move backward
    D: turn right

    """
    # Arguments for the GUI
    args = OrderedDict([
        ("Move Speed", 0.1),
        ("Turn Speed", 0.04),
    ])

    <b>def</b> <b>start</b>(self, args):
        self.move_speed = args['Move Speed']
        self.turn_speed = args['Turn Speed']

    <b>def</b> <b>update</b>(self):
        keyboard = bge.logic.keyboard.events
        move = 0
        rotate = 0

        <b>if</b> keyboard[bge.events.WKEY]:
            move += self.move_speed

        <b>if</b> keyboard[bge.events.SKEY]:
            move -= self.move_speed

        <b>if</b> keyboard[bge.events.AKEY]:
            rotate += self.turn_speed

        <b>if</b> keyboard[bge.events.DKEY]:
            rotate -= self.turn_speed

        self.object.applyMovement((0, move, 0), <b>True</b>)
        self.object.applyRotation((0, 0, rotate), <b>True</b>)

You just add the component class to the Component List then you’re done. No logic bricks needed.

I don’t usually like to subclass the KX_gameobject for the simple reason that it already has a lot of properties and methods.
If I want to give my new object a localRotation property or a debug property or an applyRotation method I could be in trouble since it already has those. In fact it’s reasonable to argue that the KX_gameobject class is a little overloaded already. It has too many methods and properties, so it’s become a kind of super class. Almost everything is made up of game objects or sub-classes of the game object class.

I prefer to create a container, like a Player which contains a mesh, hit-box, armature, etc… as well as components like AI or animation control.

Some things I’ve been using classes for recently:
A pathfinder object.
You give it a start end and map and it will find and return an A* route through the map. It has the advantage that it can be run in a thread to reduce drain on logic and return a path once it has found one, instead of pausing the whole game while it looks for one.

A rotator object.
It uses lerp and smooth step to rotate to a set angle in a set period of time so that it avoids the usual zeno’s Paradox behavior of lerped rotation.

An Equipment manager.
Instead of making a character’s equipment part of the player’s mesh and rigging it through the player’s armature, this keeps track of the position and rotation of certain bones in the player’s armature and matches the equipment objects (such as a sword) to that bone’s transform. it can be asked to holster a weapon too, so it goes to a holster bone instead of the hands. This would allow a player to pick up an object from the floor, hold it in his hand, then place it in a pocket or holster or on his back. The objects themselves can be rigged and animated too, and then synchronized to the player’s current animation (so you could draw back a bow or reload a gun).

Thanks for your explanation. What’s with abstract classes and abstract methods (abc module)? Maybe that’s an interesting point to add(?)

Have you finished glsl wind shader?

This question is a little bit off topic and have nothing to do with the quote but I can say that I’m still working on it occasionally but when I publish it, you can see it here on blender artists. :wink:

Sorry for off topic…