Kivy game design and widgets: which game objects should be widgets and which should not?

601 views
Skip to first unread message

Matthew Egbert

unread,
Nov 2, 2013, 9:09:09 AM11/2/13
to kivy-...@googlegroups.com
Hi there,

I am looking into the possibility of developing a game using kivy.  I have read through the documentation, the pong example etc., but I am still not quite sure which parts of the game should be widgets and which shouldn't be.

Say, for simplicity's sake, that it's a tower defense game.  There is a map with several towers located on it.  Should each tower be a widget, or should just the view of the map be a widget, and that widget be responsible for drawing all of the towers?

I can't really see a strong advantage to either approach.  The latter is a bit more appealing to me, because I have more experience writing applications this way.  Moreover, if there is only one widget for the whole map, rather than one for each tower, enemy, whatever on the map, it seems easier to me to include e.g. a "zoom" function, where the user could zoom into the map or zoom out.

I suppose the disadvantage would be that I have to manage the update of all the units, but if they are all likely to change every iteration of the game, then that doesn't seem like too much of a problem...?

How should this decision be made? In particular, what would the advantage be of having the towers and units also be widgets? Perhaps the MVC philosophy somehow means that including the towers and units as widgets makes for a more elegantly implemented game -- but I don't see the advantages that it would provide.

Thanks!

Alexander Taylor

unread,
Nov 2, 2013, 2:07:29 PM11/2/13
to kivy-...@googlegroups.com
I think the answer is ultimately 'it depends', but I think there are a couple of main points:

1) Making everything a widget is probably easier from an api point of view. You suggest that it might make it harder to do stuff like zooming, but this really wouldn't be the case, it's easy to bind positions etc. in a relative way. Plus as widgets you get all the normal kivy ways to position and interact with them, rather than needing to manually handle the extra layer of lower level stuff.

2) A bigger issue is that everything being a widget gets *slow*. That's not necessarily a problem, depending on how many you have and what you do with them, but widgets do carry some overhead that adds up. I think this is the single really important factor. For instance, I think all the blocks are widgets in tito's Flat Jewels game (https://play.google.com/store/apps/details?id=com.meltingrocks.flatjewels), without being a performance problem, but if there were many more blocks maybe it would become slow.

On this basis, kovak has been creating a nice game engine for kivy, which you can see at https://github.com/Kovak/KivEnt . It's a work in progress and I don't know the current status, but it's definitely usable...I don't know if kovak reads this list, but you can find him on irc sometimes. The engine *doesn't* use widgets for everything, so that it can scale well beyond where widgets become a problem, plus it builds in lots of other useful stuff like physics and particle effects. If you're interested, I suggest contacting kovak on the kivy irc channel (#kivy on freenode).

If you're new to kivy, in the short term I'd suggest just trying something and seeing what happens. Widgets might work fine for you, and if they don't at least you get an appreciation for why, when and how - and also for what you lose when switching to managing everything more manually.

Kovak

unread,
Nov 2, 2013, 6:22:36 PM11/2/13
to kivy-...@googlegroups.com
Thanks for the intro Alexander!

Ya'll have gotten right to the heart of the matter in the sense that one of the biggest design decisions when it comes to building a game with kivy is what is or isn't a widget. In KivEnt, I have settled upon using widgets as 'layers'. All of my game entities are really just dictionaries of data. They are then assigned to various Widgets that can handle a variety of tasks, including rendering. This way I can organize which rendering widget is on top of the others to determine the drawing order of various parts of my game.

Why did I end up going in this direction? 2 reasons really: 1. Early on when I was experimenting with kivy, I was using widgets per game object, but one of the issues here is that for every pos object, every time you update, any bound functions are called twice once for x and once for y. This can very quickly balloon into a large number of updates and then subsequent event calls. This is nice when you are building a UI and are expecting random inputs and updating, however, I build 2d games running a physics world which means I expect to update the pos on nearly every game object every frame 60 times a second. The whole overhead of binding/observing just doesn't seem to make the most sense under these conditions. 2. Being based on physics objects, many of my game objects no longer really live inside the kivy framework in terms of who is doing their collisions and movement and so on. They are passed to kivy only in order to draw their texture at a location on canvas. KivEnt also has a fancy camera going on with its renderers, so that only entities that are actually currently visible are ever being rendered, and it easy to setup gameworlds that have simple 2d scrolling. There are several types of spatial indexes being used depending on the type of entity, Chipmunk's spatial hash is used if your entity is represented as a physics object, a Cython-code QuadTree is used if you would like, or I believe I have a renderer that does the brute force bounding box check as well, although I don't use that one often.


The biggest thing with using KivEnt is that it uses an Entity-Component Architecture where entities are merely dictionaries of data, corresponding to a variety of Systems, which contain all the code that operates on the data. If you have never used something like this, it does represent an extra layer of abstraction to building your game, however it gives you an incredible amount of flexibility and ability to rapidly make changes to your game, as well as maximizing the ability to reuse functionality in any combination imaginable. The engine has a long way to go before it is entirely done, but it is fully functional for many uses at the moment. The basic engine code has all be profiled and cythonized where it was slow. It should save a lot of time if you are planning on building a 2d game that uses physics at all, requires a scrolling camera, or you suspect might be a bit much for the property and widget system with each game object a widget.

There are several tutorials in the root directory of the KivEnt repository that will introduce you to some of the main methods of using KivEnt, as well as a larger sample application that shows a more holistic look at how using the engine would work. Plus as Alexander said, I'm around in IRC for questions


Niko Skrypnik

unread,
Nov 3, 2013, 5:34:32 AM11/3/13
to kivy-...@googlegroups.com
Well, according to my experience of making game with Kivy I may agree with Alexander, that it really depends, but for you case Tower Defense clone I don't see reasons to use widget for game objects like tower or even enemy, as you may use for it just subclass of Rectangle graphical instruction. But whole map may be represented by Scatter widget(or it's subclass) for easy scaling and relative position of Rectangles(i.e. you have map and place all objects accordingly to offset of coordinate system (0,0) and then forget about object positions at all as while scaling scrolling scatter widget cares about it). One case I've used widget per game object was physical emulation when I tried to change angle of the box object while simulation. Easiest way to rotate it in right way was to create scatter widget for it and then change the rotate property. But I did it only cause I didn't realize how to rotate texture in right way on the canvas(for some cases center of texture was shifted and object rotated around some point out of object shape), but I think it's not a problem to figure out how to do it without widgets at all.

But still widgets may be widely used for UI elements and I use it for this purposes.

By the way I'm wondering - are you going to make some commercial product or just for fun. I think that it would be cool to create open source engine for Tower Defense game I think that some people may help you even with coding in this case. 

Matthew Egbert

unread,
Nov 8, 2013, 4:36:20 AM11/8/13
to kivy-...@googlegroups.com
Many thanks to everyone for their input.  Given the advice, I have decided that drawing of the game state will be handled by a single widget, and user-interface elements (buttons, sliders, etc.) will be additional separate widgets.

But (!) I am having a nightmare of a time trying to get the GameMap widget to regularly redraw itself.  I assure I have poured over the documentation!  And tried everything I can think of, but always what seems to happen is that the canvas is ever only drawn in one way -- the first way that I have asked for it to be drawn.  The canvas is never updated despite my various ways of trying to call ask_update() etc.  Help!

Here is a minimal program that I think should draw a square that changes color 60 time a second.  Instead it just draws a square of fixed color.  I know that the draw fn is being called, but it appears to be having no affect.

Any advice would be much appreciated!

class Game(FloatLayout):
    def __init__(self,*args, **kwargs) :
        super(Game, self).__init__(*args, **kwargs)
        self.size=[500,500]
        map_generator = MapGenerator()
        self.gameMap = map_generator.randomMap()
        self.add_widget(self.gameMap)
        
    def update(self,dt) :
        self.gameMap.update(dt)
        self.gameMap.canvas.ask_update()

class GameApp(App):
    def build(self):
        game = Game()        
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return Game()

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





class GameMap(Widget) :
    def __init__(self) :
        super(GameMap, self).__init__()
            pass

    def draw(self) :
        print('GameMap DRAW()')

        self.canvas.clear()
        with self.canvas :
            Color(np.random.rand(), np.random.rand(), np.random.rand())
            Rectangle(pos=(0,0),size=(50,50))

    def update(self,dt) :
        self.draw()        
        self.canvas.ask_update()





On Saturday, 2 November 2013 13:09:09 UTC, Matthew Egbert wrote:

Brendon Higgins

unread,
Nov 8, 2013, 8:36:32 AM11/8/13
to kivy-...@googlegroups.com
On Fri November 8, 2013 01:36:20 Matthew Egbert wrote:
> class GameApp(App):
> def build(self):
> game = Game()
> Clock.schedule_interval(game.update, 1.0 / 60.0)
> return Game()

You create a Game instance and assign it to the game local variable, set up a
clock schedule for it, then return a completely new Game instance. So I think
the root widget, the one you see on screen, is not the one that the clock is
updating. Try returning game rather than Game().

Peace,
Brendon

Matthew Egbert

unread,
Nov 8, 2013, 8:44:32 AM11/8/13
to kivy-...@googlegroups.com
Oh my god.  I'm such an idiot! Thank you!



--
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/g2RHt4nzyVQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Alexander Taylor

unread,
Nov 8, 2013, 8:47:24 AM11/8/13
to kivy-...@googlegroups.com
As another minor point, you don't need to clear and redraw the canvas
every time - instead you can just change properties of existing
Instructions.

For instance, here's a GameMap that draws the canvas only once then
updates the colour:

class GameMap(Widget) :
def __init__(self, **kwargs):
super(GameMap, self).__init__(**kwargs)
with self.canvas:
self.col = Color(np.random.rand(), np.random.rand(),
np.random.rand())
self.rec = Rectangle(pos=(0,0),size=(50,50))
self.draw()

def draw(self):
print 'GameMap DRAW()'
self.col.rgb = tuple(np.random.rand(3))

def update(self,dt):
self.draw()
Reply all
Reply to author
Forward
0 new messages