Skip to content

Getting Started 2: Creating A GameSystem

SleepProgger edited this page Apr 23, 2017 · 21 revisions

Creating A GameSystem

In this tutorial we will learn to animate our background stars by creating a simple Python GameSystem to handle a velocity update for our entities. We are going to start with the app we created in Getting Started 1.

The content of this tutorial covers the directories:

Prerequisites: You will need to have compiled kivent_core, in addition to having kivy and all its requirements installed.

Python GameSystem

Creating a Python GameSystem is the fastest and simplest way to use KivEnt. These components are python objects and so we can enjoy all the regular duck typing of Python. To get started, we import GameSystem and override its update function to perform our own logic.

Our update method will have the following general flow. For each component in the GameSystem:

  1. Check that is not None (as that would be an inactive entity).
  2. Retrieve the entity_id from the component.
  3. Get the entity from the GameWorld.entities object.
  4. Retrieve the position component and update its values with the value of the velocity.
from kivent_core.systems.gamesystem import GameSystem

class VelocitySystem2D(GameSystem):
    
    def update(self, dt):
        entities = self.gameworld.entities
        for component in self.components:
            if component is not None:
                entity_id = component.entity_id
                entity = entities[entity_id]
                position_comp = entity.position 
                position_comp.x += component.vx * dt
                position_comp.y += component.vy * dt

We must also Factory.register our new GameSystem due to a complication in KivEnt's implementation compared to a basic Kivy widget which does this for you automatically.

from kivy.factory import Factory

Factory.register('VelocitySystem2D', cls=VelocitySystem2D)

Next we update the kv tree, adding our new GameSystem and marking it as updateable. Since the previously immobile sprites will now be moving, we also mark the Renderer as updateable, and enable double-buffering via frame_count:

    GameWorld:
        id: gameworld
        gamescreenmanager: gamescreenmanager
        size_of_gameworld: 100*1024
        size_of_entity_block: 128
        system_count: 4
        zones: {'general': 10000}
        PositionSystem2D:
            system_id: 'position'
            gameworld: gameworld
            zones: ['general']
            size_of_component_block: 128
        VelocitySystem2D:
            system_id: 'velocity'
            gameworld: gameworld
            updateable: True
        Renderer:
            gameworld: gameworld
            system_id: 'renderer'
            zones: ['general']
            frame_count: 2
            updateable: True
            size_of_batches: 512
            size_of_component_block: 128
            shader_source: 'assets/glsl/positionshader.glsl'

Finally, we modify the entity creation code to include our new GameSystem. Since our python components use duck typing we need to pass in the arguments to the new velocity component using whatever names are expected in our velocity update loop; i.e. component.vx and component.vy. The default behavior for a GameSystem is to have the keys of the initializing dict set as attributes (setattr) onto the component.

    def draw_some_stuff(self):
        init_entity = self.gameworld.init_entity
        for x in range(1000):
            pos = randint(0, Window.width), randint(0, Window.height)
            model_key = choice(['star1-4', 'star1-4-2'])
            create_dict = {
                'position': pos,
                'velocity': {'vx': randint(-75, 75), 'vy': randint(-75, 75)},
                'renderer': {'texture': 'star1', 
                    'model_key': model_key},
            }
            ent = init_entity(create_dict, ['position', 'velocity', 
                'renderer'])

Don't forget to add the name of the new GameSystem to the list arg of the GameWorld.init_entity function. Similarly, we must add our new GameSystem to the state system's systems_unpaused list:

    def setup_states(self):
        self.gameworld.add_state(state_name='main', 
            systems_added=['renderer'],
            systems_removed=[], systems_paused=[],
            systems_unpaused=['renderer', 'velocity'],
            screenmanager_screen='main')

and to the initialization function:

    def __init__(self, **kwargs):
        super(TestGame, self).__init__(**kwargs)
        self.gameworld.init_gameworld(
            ['renderer', 'position', 'velocity'],
            callback=self.init_game)

Full Python GameSystem Code

The full code for this version of our GameSystem is here:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.core.window import Window
from random import randint, choice
import kivent_core
from kivent_core.gameworld import GameWorld
from kivent_core.systems.position_systems import PositionSystem2D
from kivent_core.systems.renderers import Renderer
from kivent_core.systems.gamesystem import GameSystem
from kivent_core.managers.resource_managers import texture_manager
from kivy.properties import StringProperty
from kivy.factory import Factory

texture_manager.load_atlas('assets/background_objects.atlas')

class VelocitySystem2D(GameSystem):
    
    def update(self, dt):
        entities = self.gameworld.entities
        for component in self.components:
            if component is not None:
                entity_id = component.entity_id
                entity = entities[entity_id]
                position_comp = entity.position 
                position_comp.x += component.vx * dt
                position_comp.y += component.vy * dt

Factory.register('VelocitySystem2D', cls=VelocitySystem2D)

class TestGame(Widget):
    def __init__(self, **kwargs):
        super(TestGame, self).__init__(**kwargs)
        self.gameworld.init_gameworld(
            ['renderer', 'position', 'velocity'],
            callback=self.init_game)

    def init_game(self):
        self.setup_states()
        self.set_state()
        self.load_models()
        self.draw_some_stuff()

    def load_models(self):
        model_manager = self.gameworld.model_manager
        model_manager.load_textured_rectangle('vertex_format_4f', 7., 7.,
            'star1', 'star1-4')
        model_manager.load_textured_rectangle('vertex_format_4f', 10., 10.,
            'star1', 'star1-4-2')

    def draw_some_stuff(self):
        init_entity = self.gameworld.init_entity
        for x in range(2000):
            pos = randint(0, Window.width), randint(0, Window.height)
            model_key = choice(['star1-4', 'star1-4-2'])
            create_dict = {
                'position': pos,
                'velocity': {'vx': randint(-75, 75), 'vy': randint(-75, 75)},
                'renderer': {'texture': 'star1', 
                    'model_key': model_key},
            }
            ent = init_entity(create_dict, ['position', 'velocity', 
                'renderer'])

    def setup_states(self):
        self.gameworld.add_state(state_name='main', 
            systems_added=['renderer'],
            systems_removed=[], systems_paused=[],
            systems_unpaused=['renderer', 'velocity'],
            screenmanager_screen='main')

    def set_state(self):
        self.gameworld.state = 'main'

class DebugPanel(Widget):
    fps = StringProperty(None)

    def __init__(self, **kwargs):
        super(DebugPanel, self).__init__(**kwargs)
        Clock.schedule_once(self.update_fps)

    def update_fps(self,dt):
        self.fps = str(int(Clock.get_fps()))
        Clock.schedule_once(self.update_fps, .05)

class YourAppNameApp(App):
    def build(self):
        Window.clearcolor = (0, 0, 0, 1.)

if __name__ == '__main__':
    YourAppNameApp().run()
#:kivy 1.9.0

TestGame:

<TestGame>:
    gameworld: gameworld
    GameWorld:
        id: gameworld
        gamescreenmanager: gamescreenmanager
        size_of_gameworld: 100*1024
        size_of_entity_block: 128
        system_count: 4
        zones: {'general': 10000}
        PositionSystem2D:
            system_id: 'position'
            gameworld: gameworld
            zones: ['general']
            size_of_component_block: 128
        VelocitySystem2D:
            system_id: 'velocity'
            gameworld: gameworld
            updateable: True
        Renderer:
            gameworld: gameworld
            system_id: 'renderer'
            zones: ['general']
            frame_count: 2
            updateable: True
            size_of_batches: 512
            size_of_component_block: 128
            shader_source: 'assets/glsl/positionshader.glsl'
    GameScreenManager:
        id: gamescreenmanager
        size: root.size
        pos: root.pos
        gameworld: gameworld

<GameScreenManager>:
    MainScreen:
        id: main_screen

<MainScreen@GameScreen>:
    name: 'main'
    FloatLayout:
        DebugPanel:
            size_hint: (.2, .1)
            pos_hint: {'x': .225, 'y': .025}

<DebugPanel>:
    Label:
        pos: root.pos
        size: root.size
        font_size: root.size[1]*.5
        halign: 'center'
        valign: 'middle'
        color: (1,1,1,1)
        text: 'FPS: ' + root.fps if root.fps != None else 'FPS:'

On my desktop this can handle about 8000 entities with the velocity component before performance begins to rapidly fall off:

  • 6000 - 60 FPS
  • 8000 - 40 FPS
  • 9000 - 25 FPS
  • 10000 - 3 FPS

Let us see what we can do by cythonizing our new GameSystem and making the component data static.

Cython GameSystem

A cython file is a bit more complicated because we are going to have to include compilation instructions, a header file, and the actual code. This will result in us introducing more structure to our project:

  • velocity_module/__init__.py <- we must include an __init__ just like any other submodule
  • velocity_module/velocity.pyx <- the equivalent of our .py file in cython
  • velocity_module/velocity.pxd <- the header file for our new cythonized system
  • setup.py <- the instructions for compiling our new cython module

The Header (velocity.pxd)

The file declares what types and classes are exposed by this module for cimporting into other modules. Anything we want to use from other cython modules should be included here. A simple one for our GameSystem will look like:

from kivent_core.systems.staticmemgamesystem cimport (StaticMemGameSystem, 
    MemComponent)


ctypedef struct VelocityStruct2D:
    unsigned int entity_id
    float vx
    float vy


cdef class VelocityComponent2D(MemComponent):
    pass


cdef class VelocitySystem2D(StaticMemGameSystem):
    pass

Here we must declare the C struct that will hold our velocity system data. The first attribute of any component struct should always be the entity_id. This is used internally to help keep track of active components during processing. The cdefed Component that will allow python interaction with that C struct and the cdefed GameSystem. We change to inheriting from StaticMemGameSystem instead of GameSystem as we are no longer going to use the dynamic GameSystem logic.

The Implementation (velocity.pyx)

Here we will define both VelocitySystem2D and VelocityComponent2D. The component exposes the underlying VelocityStruct2D data for python manipulation:

cdef class VelocityComponent2D(MemComponent):

    property entity_id:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.entity_id

    property vx:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.vx
        def __set__(self, float value):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vx = value

    property vy:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.vy
        def __set__(self, float value):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vy = value

    property vel:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return (data.vx, data.vy)
        def __set__(self, tuple new_vel):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vx = new_vel[0]
            data.vy = new_vel[1]

Here we create properties wrapping the struct data. self.pointer is always a void* object pointing to your data in memory so we must first cast it to the appropriate type before interacting with its data. Other than you can do any python processing of data you need before setting or after getting the raw data.

For the GameSystem the implementation is a little more complicated, in addition to writing a new update function we must handle the logic for creating, clearing, and removing components.

First we declare our class:

cdef class VelocitySystem2D(StaticMemGameSystem):
    system_id = StringProperty('velocity')
    processor = BooleanProperty(True)
    type_size = NumericProperty(sizeof(VelocityStruct2D))
    component_type = ObjectProperty(VelocityComponent2D)
    system_names = ListProperty(['velocity','position'])

Here we must tell it the type of Component object that it will be using, we give our system a default name, and we set the size of our VelocityStruct2D. In addition because we will be performing update logic we set processor to True and in the system_names list we include the name of the GameSystems that processing is dependent on.

Next we handle component creation and removal:

    def init_component(self, unsigned int component_index, 
        unsigned int entity_id, str zone, args):
        cdef float vx = args[0]
        cdef float vy = args[1]
        cdef MemoryZone memory_zone = self.imz_components.memory_zone
        cdef VelocityStruct2D* component = <VelocityStruct2D*>(
            memory_zone.get_pointer(component_index))
        component.entity_id = entity_id
        component.vx = vx
        component.vy = vy
        return self.entity_components.add_entity(entity_id, zone)

    def clear_component(self, unsigned int component_index):
        cdef MemoryZone memory_zone = self.imz_components.memory_zone
        cdef VelocityStruct2D* pointer = <VelocityStruct2D*>(
            memory_zone.get_pointer(component_index))
        pointer.entity_id = -1
        pointer.vx = 0.
        pointer.vy = 0.

    def remove_component(self, unsigned int component_index):
        cdef VelocityComponent2D component = self.components[component_index]
        self.entity_components.remove_entity(component.entity_id)
        super(VelocitySystem2D, self).remove_component(component_index)

In the init_function we must take the arguments we receive from python and convert them into the static data we are expecting for our components. In addition we must call add_entity on the entity_components object, which will aid in processing. In the clear_component function we set up the logic for clearing a component when it needs to be reused. entity_id should always be set to -1 in this step. What you set the rest of your data to is up to you. Finally in remove_component we must do the opposite of the entity_components.add_entity by calling remove_entity.

Now we can write our update function, this will be a little more verbose as we must declare the typing on some of our objects.:

    def update(self, dt):
        gameworld = self.gameworld
        cdef void** component_data = <void**>(
            self.entity_components.memory_block.data)
        cdef unsigned int component_count = self.entity_components.count
        cdef unsigned int count = self.entity_components.memory_block.count
        cdef unsigned int i, real_index
        cdef PositionStruct2D* pos_comp
        cdef VelocityStruct2D* vel_comp

        for i in range(count):
            real_index = i*component_count
            if component_data[real_index] == NULL:
                continue
            vel_comp = <VelocityStruct2D*>component_data[real_index]
            pos_comp = <PositionStruct2D*>component_data[real_index+1]
            pos_comp.x += vel_comp.vx * dt
            pos_comp.y += vel_comp.vy * dt

Here the code gets a little more complicated as we must retrieve pointers to our components from the entity_components object, we get the raw data by accessing the data object of its memory_block. We then iterate through this data. We must calculate the real_index value as there are count sets of component_count pointers contained in the pointer array. If the first value at real_index is NULL, just like when the component was found to be None we skip and continue processing. From there we retrieve and cast the actual components. Components will be stored in the order of their names declared in the system_names list. A key advantage here is that we no longer have to know about the actual entity containing the components at all.

Finally just as before, Factory.register our GameSystem:

Factory.register('VelocitySystem2D', cls=VelocitySystem2D)

Building the Velocity Module

Our setup.py looks like this:

from os import environ, remove
from os.path import dirname, join, isfile
from distutils.core import setup
from distutils.extension import Extension
try:
    from Cython.Build import cythonize
    from Cython.Distutils import build_ext
    have_cython = True
except ImportError:
    have_cython = False
import sys

platform = sys.platform
if platform == 'win32':
	cstdarg = '-std=gnu99'
else:
	cstdarg = '-std=c99'

do_clear_existing = True



velocity_modules = {
    'velocity_module.velocity': ['velocity_module/velocity.pyx',],
    }

velocity_modules_c = {
    'velocity_module.velocity': ['velocity_module/velocity.c',],
    }

check_for_removal = ['velocity_module/velocity.c',]

def build_ext(ext_name, files, include_dirs=[]):
    return Extension(ext_name, files, include_dirs,
        extra_compile_args=[cstdarg, '-ffast-math',])

extensions = []
velocity_extensions = []
cmdclass = {}

def build_extensions_for_modules_cython(ext_list, modules):
    ext_a = ext_list.append
    for module_name in modules:
        ext = build_ext(module_name, modules[module_name])
        if environ.get('READTHEDOCS', None) == 'True':
            ext.pyrex_directives = {'embedsignature': True}
        ext_a(ext)
    return cythonize(ext_list)

def build_extensions_for_modules(ext_list, modules):
    ext_a = ext_list.append
    for module_name in modules:
        ext = build_ext(module_name, modules[module_name])
        if environ.get('READTHEDOCS', None) == 'True':
            ext.pyrex_directives = {'embedsignature': True}
        ext_a(ext)
    return ext_list

if have_cython:
    if do_clear_existing:
        for file_name in check_for_removal:
            if isfile(file_name):
                remove(file_name)
    velocity_extensions = build_extensions_for_modules_cython(
        velocity_extensions, velocity_modules)
else:
    velocity_extensions = build_extensions_for_modules(velocity_extensions, 
        velocity_modules_c)

setup(
    name='KivEnt Velocity Module',
    description='''A game engine for the Kivy Framework. 
        https://github.com/Kovak/KivEnt for more info.''',
    author='Jacob Kovac',
    author_email='[email protected]',
    ext_modules=velocity_extensions,
    cmdclass=cmdclass,
    packages=[
        'velocity_module',
        ],
    package_dir={'velocity_module': 'velocity_module'})

We must declare the files to be found in the velocity_module and the package structure. If you would like a more complex example that handles more modules and such take a look at the kivent_core setup.py.

Now to build the module run:

python setup.py build_ext --inplace

Using the Velocity Module

Now modify our main.py to use the cythonized module:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.core.window import Window
from random import randint, choice
import kivent_core
from kivent_core.gameworld import GameWorld
from kivent_core.systems.position_systems import PositionSystem2D
from kivent_core.systems.renderers import Renderer
from kivent_core.systems.gamesystem import GameSystem
from kivent_core.managers.resource_managers import texture_manager
from kivy.properties import StringProperty
from kivy.factory import Factory
from velocity_module.velocity import VelocitySystem2D

texture_manager.load_atlas('assets/background_objects.atlas')

class TestGame(Widget):
    def __init__(self, **kwargs):
        super(TestGame, self).__init__(**kwargs)
        self.gameworld.init_gameworld(
            ['renderer', 'position', 'velocity'],
            callback=self.init_game)

    def init_game(self):
        self.setup_states()
        self.load_models()
        self.set_state()
        self.draw_some_stuff()

    def load_models(self):
        model_manager = self.gameworld.model_manager
        model_manager.load_textured_rectangle('vertex_format_4f', 7., 7., 
            'star1', 'star1-4')
        model_manager.load_textured_rectangle('vertex_format_4f', 10., 10., 'star1', 'star1-4-2')

    def draw_some_stuff(self):
        init_entity = self.gameworld.init_entity
        for x in range(10000):
            pos = randint(0, Window.width), randint(0, Window.height)
            model_key = choice(['star1-4', 'star1-4-2'])
            create_dict = {
                'position': pos,
                'velocity': (randint(-75, 75), randint(-75, 75)),
                'renderer': {'texture': 'star1', 
                    'model_key': model_key},
            }
            ent = init_entity(create_dict, ['position', 'velocity', 
                'renderer'])


    def setup_states(self):
        self.gameworld.add_state(state_name='main', 
            systems_added=['renderer'],
            systems_removed=[], systems_paused=[],
            systems_unpaused=['renderer', 'velocity'],
            screenmanager_screen='main')

    def set_state(self):
        self.gameworld.state = 'main'


class DebugPanel(Widget):
    fps = StringProperty(None)

    def __init__(self, **kwargs):
        super(DebugPanel, self).__init__(**kwargs)
        Clock.schedule_once(self.update_fps)

    def update_fps(self,dt):
        self.fps = str(int(Clock.get_fps()))
        Clock.schedule_once(self.update_fps, .05)


class CythonVelApp(App):
    def build(self):
        Window.clearcolor = (0, 0, 0, 1.)


if __name__ == '__main__':
    CythonVelApp().run()

and the kv file (note that we must add the zones declaration to our VelocitySystem2D)

#:kivy 1.9.0

TestGame:

<TestGame>:
    gameworld: gameworld
    test: 'test'
    GameWorld:
        id: gameworld
        gamescreenmanager: gamescreenmanager
        size_of_gameworld: 100*1024
        size_of_entity_block: 128
        system_count: 4
        zones: {'general': 100000}
        PositionSystem2D:
            system_id: 'position'
            gameworld: gameworld
            zones: ['general']
            size_of_component_block: 128
        VelocitySystem2D:
            system_id: 'velocity'
            gameworld: gameworld
            zones: ['general']
            updateable: True
        Renderer:
            gameworld: gameworld
            system_id: 'renderer'
            zones: ['general']
            frame_count: 2
            updateable: True
            size_of_batches: 1024
            size_of_component_block: 128
            shader_source: 'assets/glsl/positionshader.glsl'
    GameScreenManager:
        id: gamescreenmanager
        size: root.size
        pos: root.pos
        gameworld: gameworld

<GameScreenManager>:
    MainScreen:
        id: main_screen

<MainScreen@GameScreen>:
    name: 'main'
    FloatLayout:
        DebugPanel:
            size_hint: (.2, .1)
            pos_hint: {'x': .225, 'y': .025}


<DebugPanel>:
    Label:
        pos: root.pos
        size: root.size
        font_size: root.size[1]*.5
        halign: 'center'
        valign: 'middle'
        color: (1,1,1,1)
        text: 'FPS: ' + root.fps if root.fps != None else 'FPS:'

Now some FPS numbers for the cythonized version

  • 10000 - 60 FPS
  • 20000 - 60 FPS
  • 30000 - 40 FPS
  • 40000 - 30 FPS
  • 100000 - 1-5 FPS

Full Cython Module

velocity.pxd

from kivent_core.systems.staticmemgamesystem cimport (StaticMemGameSystem, 
    MemComponent)


ctypedef struct VelocityStruct2D:
    unsigned int entity_id
    float vx
    float vy


cdef class VelocityComponent2D(MemComponent):
    pass


cdef class VelocitySystem2D(StaticMemGameSystem):
    pass

velocity.pyx

from kivent_core.systems.staticmemgamesystem cimport (StaticMemGameSystem, 
    MemComponent)
from kivent_core.memory_handlers.zone cimport MemoryZone
from kivy.factory import Factory
from kivy.properties import (ObjectProperty, NumericProperty, ListProperty, 
    BooleanProperty, StringProperty)
from kivent_core.systems.position_systems cimport PositionStruct2D


cdef class VelocityComponent2D(MemComponent):

    property entity_id:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.entity_id

    property vx:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.vx
        def __set__(self, float value):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vx = value

    property vy:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return data.vy
        def __set__(self, float value):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vy = value

    property vel:
        def __get__(self):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            return (data.vx, data.vy)
        def __set__(self, tuple new_vel):
            cdef VelocityStruct2D* data = <VelocityStruct2D*>self.pointer
            data.vx = new_vel[0]
            data.vy = new_vel[1]


cdef class VelocitySystem2D(StaticMemGameSystem):
    system_id = StringProperty('velocity')
    processor = BooleanProperty(True)
    type_size = NumericProperty(sizeof(VelocityStruct2D))
    component_type = ObjectProperty(VelocityComponent2D)
    system_names = ListProperty(['velocity','position'])
        
    def init_component(self, unsigned int component_index, 
        unsigned int entity_id, str zone, args):
        cdef float vx = args[0]
        cdef float vy = args[1]
        cdef MemoryZone memory_zone = self.imz_components.memory_zone
        cdef VelocityStruct2D* component = <VelocityStruct2D*>(
            memory_zone.get_pointer(component_index))
        component.entity_id = entity_id
        component.vx = vx
        component.vy = vy
        return self.entity_components.add_entity(entity_id, zone)

    def clear_component(self, unsigned int component_index):
        cdef MemoryZone memory_zone = self.imz_components.memory_zone
        cdef VelocityStruct2D* pointer = <VelocityStruct2D*>(
            memory_zone.get_pointer(component_index))
        pointer.entity_id = -1
        pointer.vx = 0.
        pointer.vy = 0.

    def remove_component(self, unsigned int component_index):
        cdef VelocityComponent2D component = self.components[component_index]
        self.entity_components.remove_entity(component.entity_id)
        super(VelocitySystem2D, self).remove_component(component_index)

    def update(self, dt):
        gameworld = self.gameworld
        cdef void** component_data = <void**>(
            self.entity_components.memory_block.data)
        cdef unsigned int component_count = self.entity_components.count
        cdef unsigned int count = self.entity_components.memory_block.count
        cdef unsigned int i, real_index
        cdef PositionStruct2D* pos_comp
        cdef VelocityStruct2D* vel_comp

        for i in range(count):
            real_index = i*component_count
            if component_data[real_index] == NULL:
                continue
            vel_comp = <VelocityStruct2D*>component_data[real_index]
            pos_comp = <PositionStruct2D*>component_data[real_index+1]
            pos_comp.x += vel_comp.vx * dt
            pos_comp.y += vel_comp.vy * dt
 

Factory.register('VelocitySystem2D', cls=VelocitySystem2D)
__init__.py
import velocity

Continue to Getting Started 3: Adding the Physics System