Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/elements/callbacks.py
blob: 5402869d3a4f8705af529220ff74d3817d85ec65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""
This file is part of the 'Elements' Project
Elements is a 2D Physics API for Python (supporting Box2D2)

Copyright (C) 2008, The Elements Team, <elements@linuxuser.at>

Home:  http://elements.linuxuser.at
IRC:   #elements on irc.freenode.org

Code:  http://www.assembla.com/wiki/show/elements
       svn co http://svn2.assembla.com/svn/elements                     

License:  GPLv3 | See LICENSE for the full text
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.              
"""
from locals import *
from elements import box2d

class CallbackHandler:
    # List of contact callbacks and shapes to start them - sorted by type for quicker access  
    # Callbacks are saved as callbacks[callback_type][[function, parameters], ...]
    callbacks = {}   
    
    def __init__(self, parent):
        self.parent = parent
        
        # init callback dict to avoid those slow try 
        # (especially for self.get, as it is called *often*)
        for i in xrange(10):
            self.callbacks[i] = []
         
    def add(self, callback_type, callback_handler, *args):
            """ Users can add callbacks for certain (or all) collisions
               
               Parameters:
                 callback_type ......... CALLBACK_CONTACT (nothing else for now)
                 callback_handler ...... a callback function
                 args (optional) ....... a list of parameters which can be used with callbacks.get
               
               Return:
                 callback_id ... used to remove a callback later (int)
            """
            # Create contact listener if required
            if callback_type in [CALLBACK_CONTACT_ADD, CALLBACK_CONTACT_PERSIST, CALLBACK_CONTACT_REMOVE]:
                if self.parent.klistener == None:
                    self.parent.klistener = kContactListener(self.get)
                    self.parent.world.SetContactListener( self.parent.klistener )
                    print "* kContactListener added"
            
            # Get callback dict for this callback_type
            c = self.callbacks[callback_type]
                        
            # Append to the Callback Dictionary
            c.append([callback_handler, args])
            self.callbacks[callback_type] = c
            
            # Return Callback ID
            # ID = callback_type.callback_index (1...n)
            return "%i.%i" % (callback_type, len(c))
        
    def get(self, callback_type):
        return self.callbacks[callback_type]
            
    def start(self, callback_type, *args):
        callbacks = self.get(callback_type)
        for c in callbacks:
            callback, params = c
            callback()

class kContactListener(box2d.b2ContactListener):
    def __init__(self, get_callbacks): 
        # Init the Box2D b2ContactListener
        box2d.b2ContactListener.__init__(self)

        # Function to get the current callbacks
        self.get_callbacks = get_callbacks
        
    def check_contact(self, contact_type, point):
        # Checks if a callback should be started with this contact point
        contacts = self.get_callbacks(contact_type)

        # Step through all callbacks for this type (eg ADD, PERSIST, REMOVE)
        for c in contacts:
            callback, bodylist = c
            if len(bodylist) == 0:
                # Without bodylist it's a universal callback (for all bodies) 
                callback(point)
                
            else:
                # This is a callback with specified bodies
                # See if this contact involves one of the specified
                b1 = str(point.shape1.GetBody())
                b2 = str(point.shape2.GetBody())
                for s in bodylist:
                    s = str(s)
                    if b1 == s or b2 == s: 
                        # Yes, that's the one :)
                        callback(point)
         
    def Add(self, point):
        """Called when a contact point is created"""
        self.check_contact(CALLBACK_CONTACT_ADD, point)
        
    def Persist(self, point):
        """Called when a contact point persists for more than a time step"""
        self.check_contact(CALLBACK_CONTACT_PERSIST, point)
                        
    def Remove(self, point):
        """Called when a contact point is removed"""
        self.check_contact(CALLBACK_CONTACT_REMOVE, point)