2

I'm developing a real-time rogue-like game during my spare time, using Python and libtcod, to learn programming (and have some fun). I would like to create some sort of mouse-friendly GUI, just like in Goblin Camp.

This game is 90% mouse-driven, with menus, scrollbars, buttons etc. As a total noob with graphical interfaces, I just can't figure out how to do this. Example: How to display the name of a monster when the cursor is over it? I tried some ways, which more or less worked, but were always awful, impossible to maintain, hard to scale, and resource-consuming.

Is there a "simple" way to have something more like an object.OnClick() ?

aaaaaaaaaaaa
  • 8,892
  • 1
  • 21
  • 35
  • I'm not sure how to answer your question, but your english is quite good. I've seen much worse (sometimes from native speakers!) – thedaian Jul 06 '11 at 14:25
  • Is the problem related to the fact that you have to display text in a limited space? Or is a problem of how to organize the software so you can code entities that can react to mouse events in general? – FxIII Jul 06 '11 at 14:47
  • Organization problem. When I click on that (ascii) mob, or that button, I don't want to cycle through all objects to figure out which one is under my mouse. I want the object to tell me "you clicked on me!" – Simon Cambier Jul 06 '11 at 15:14

1 Answers1

0

If you simply need to do an Object.onSomething() probably you need to write a reactor over a object data model.

What I mean? Put every relevant objects into a container make this container available to everyone. This container will implement the method

def castEvent(self, eventName, args, kargs):

In this method you iterate the containing object looking for the method "does%s" % eventName. something like:

for item in self.items:
    f = getattr(item, "does%s" % eventName, lambda *x, **k : False)

if f evaluates True using the parameters passed to the function then you call the "do%s"%eventName with the same parameters:

for item in self.items:
    f = getattr(item, "does%s" % eventName, lambda *x, **k : False)
    if f(*args, **kargs):
        f = getattr(item, "do%s" % eventName, lambda *x, **k : False)
        f(*args, **kargs)   

Every time you need to send an event - say Click - you simply need to:

container.castEvent("Click",[],{"x":10,"y":20})

every object interested in Clicks has to provide a

def doesClick(self, x, y):

that manage the click events returning False or

def doesClick(self, x, y):
[...]
def doClick(self, x, y):

The first returning whether (x,y) hits the object and the second doing the click routine.

You can implement the first in a generic superclass and let the clickable classes to extend.

This is a very basic implementation whit a lot of room for improvements.

FxIII
  • 3,996
  • 20
  • 20
  • Thank you! That wasn't exactly what I was looking for, but its a really better written system than the one I tried. I guess I've still a lot to learn in Python... – Simon Cambier Jul 07 '11 at 04:04
  • @simcamb have you troubles with the integrationton? – FxIII Jul 07 '11 at 09:32
  • @Fxll I'm working on it right now, I understand how it works, but I don't get the use of lambda (I only know it works like a "one line function") in *args. – Simon Cambier Jul 07 '11 at 09:39
  • If a method does not exist for item, getattr(item,"method",x) returns x. In this case x is a function with a generic signature that returns false. – FxIII Jul 07 '11 at 09:51
  • @Fxll Right, that was obvious. I didn't read it right, thanks again. – Simon Cambier Jul 07 '11 at 10:02