Mercurial > parpg-core
comparison src/parpg/grease/impl/controls.py @ 27:09b581087d68
Added base files for grease
author | KarstenBock@gmx.net |
---|---|
date | Tue, 12 Jul 2011 10:16:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
26:5529dd5644b8 | 27:09b581087d68 |
---|---|
1 ############################################################################# | |
2 # | |
3 # Copyright (c) 2010 by Casey Duncan | |
4 # All Rights Reserved. | |
5 # | |
6 # This software is subject to the provisions of the MIT License | |
7 # A copy of the license should accompany this distribution. | |
8 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
9 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
10 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
11 # | |
12 ############################################################################# | |
13 """Control systems for binding controls to game logic""" | |
14 | |
15 import grease | |
16 from pyglet.window import key | |
17 | |
18 class KeyControls(grease.System): | |
19 """System that maps subclass-defined action methods to keys. | |
20 | |
21 Keys may be mapped in the subclass definition using decorators | |
22 defined here as class methods or at runtime using the ``bind_key_*`` | |
23 instance methods. | |
24 | |
25 See :ref:`an example implementation in the tutorial <tut-controls-example>`. | |
26 """ | |
27 MODIFIER_MASK = ~(key.MOD_NUMLOCK | key.MOD_SCROLLLOCK | key.MOD_CAPSLOCK) | |
28 """The MODIFIER_MASK allows you to filter out modifier keys that should be | |
29 ignored by the application. By default, capslock, numlock, and scrolllock | |
30 are ignored. | |
31 """ | |
32 | |
33 world = None | |
34 """:class:`grease.World` object this system is bound to""" | |
35 | |
36 def __init__(self): | |
37 self._key_press_map = {} | |
38 self._key_release_map = {} | |
39 self._key_hold_map = {} | |
40 for name in self.__class__.__dict__: | |
41 member = getattr(self, name) | |
42 if hasattr(member, '_grease_hold_key_binding'): | |
43 for binding in member._grease_hold_key_binding: | |
44 self.bind_key_hold(member, *binding) | |
45 if hasattr(member, '_grease_press_key_binding'): | |
46 for binding in member._grease_press_key_binding: | |
47 self.bind_key_press(member, *binding) | |
48 if hasattr(member, '_grease_release_key_binding'): | |
49 for binding in member._grease_release_key_binding: | |
50 self.bind_key_release(member, *binding) | |
51 self.held_keys = set() | |
52 | |
53 ## decorator methods for binding methods to key input events ## | |
54 | |
55 @classmethod | |
56 def key_hold(cls, symbol, modifiers=0): | |
57 """Decorator to bind a method to be executed where a key is held down""" | |
58 def bind(f): | |
59 if not hasattr(f, '_grease_hold_key_binding'): | |
60 f._grease_hold_key_binding = [] | |
61 f._grease_hold_key_binding.append((symbol, modifiers & cls.MODIFIER_MASK)) | |
62 return f | |
63 return bind | |
64 | |
65 @classmethod | |
66 def key_press(cls, symbol, modifiers=0): | |
67 """Decorator to bind a method to be executed where a key is initially depressed""" | |
68 def bind(f): | |
69 if not hasattr(f, '_grease_press_key_binding'): | |
70 f._grease_press_key_binding = [] | |
71 f._grease_press_key_binding.append((symbol, modifiers & cls.MODIFIER_MASK)) | |
72 return f | |
73 return bind | |
74 | |
75 @classmethod | |
76 def key_release(cls, symbol, modifiers=0): | |
77 """Decorator to bind a method to be executed where a key is released""" | |
78 def bind(f): | |
79 if not hasattr(f, '_grease_release_key_binding'): | |
80 f._grease_release_key_binding = [] | |
81 f._grease_release_key_binding.append((symbol, modifiers & cls.MODIFIER_MASK)) | |
82 return f | |
83 return bind | |
84 | |
85 ## runtime binding methods ## | |
86 | |
87 def bind_key_hold(self, method, key, modifiers=0): | |
88 """Bind a method to a key at runtime to be invoked when the key is | |
89 held down, this replaces any existing key hold binding for this key. | |
90 To unbind the key entirely, pass ``None`` for method. | |
91 """ | |
92 if method is not None: | |
93 self._key_hold_map[key, modifiers & self.MODIFIER_MASK] = method | |
94 else: | |
95 try: | |
96 del self._key_hold_map[key, modifiers & self.MODIFIER_MASK] | |
97 except KeyError: | |
98 pass | |
99 | |
100 def bind_key_press(self, method, key, modifiers=0): | |
101 """Bind a method to a key at runtime to be invoked when the key is initially | |
102 pressed, this replaces any existing key hold binding for this key. To unbind | |
103 the key entirely, pass ``None`` for method. | |
104 """ | |
105 if method is not None: | |
106 self._key_press_map[key, modifiers & self.MODIFIER_MASK] = method | |
107 else: | |
108 try: | |
109 del self._key_press_map[key, modifiers & self.MODIFIER_MASK] | |
110 except KeyError: | |
111 pass | |
112 | |
113 def bind_key_release(self, method, key, modifiers=0): | |
114 """Bind a method to a key at runtime to be invoked when the key is releaseed, | |
115 this replaces any existing key hold binding for this key. To unbind | |
116 the key entirely, pass ``None`` for method. | |
117 """ | |
118 if method is not None: | |
119 self._key_release_map[key, modifiers & self.MODIFIER_MASK] = method | |
120 else: | |
121 try: | |
122 del self._key_release_map[key, modifiers & self.MODIFIER_MASK] | |
123 except KeyError: | |
124 pass | |
125 | |
126 def step(self, dt): | |
127 """invoke held key functions""" | |
128 already_run = set() | |
129 for key in self.held_keys: | |
130 func = self._key_hold_map.get(key) | |
131 if func is not None and func not in already_run: | |
132 already_run.add(func) | |
133 func(dt) | |
134 | |
135 def on_key_press(self, key, modifiers): | |
136 """Handle pyglet key press. Invoke key press methods and | |
137 activate key hold functions | |
138 """ | |
139 key_mod = (key, modifiers & self.MODIFIER_MASK) | |
140 if key_mod in self._key_press_map: | |
141 self._key_press_map[key_mod]() | |
142 self.held_keys.add(key_mod) | |
143 | |
144 def on_key_release(self, key, modifiers): | |
145 """Handle pyglet key release. Invoke key release methods and | |
146 deactivate key hold functions | |
147 """ | |
148 key_mod = (key, modifiers & self.MODIFIER_MASK) | |
149 if key_mod in self._key_release_map: | |
150 self._key_release_map[key_mod]() | |
151 self.held_keys.discard(key_mod) | |
152 | |
153 | |
154 if __name__ == '__main__': | |
155 import pyglet | |
156 | |
157 class TestKeyControls(KeyControls): | |
158 | |
159 MODIFIER_MASK = ~(key.MOD_NUMLOCK | key.MOD_SCROLLLOCK | key.MOD_CTRL) | |
160 | |
161 remapped = False | |
162 | |
163 @KeyControls.key_hold(key.UP) | |
164 @KeyControls.key_hold(key.W) | |
165 def up(self, dt): | |
166 print 'UP!' | |
167 | |
168 @KeyControls.key_hold(key.LEFT) | |
169 @KeyControls.key_hold(key.A) | |
170 def left(self, dt): | |
171 print 'LEFT!' | |
172 | |
173 @KeyControls.key_hold(key.RIGHT) | |
174 @KeyControls.key_hold(key.D) | |
175 def right(self, dt): | |
176 print 'RIGHT!' | |
177 | |
178 @KeyControls.key_hold(key.DOWN) | |
179 @KeyControls.key_hold(key.S) | |
180 def down(self, dt): | |
181 print 'DOWN!' | |
182 | |
183 @KeyControls.key_press(key.SPACE) | |
184 def fire(self): | |
185 print 'FIRE!' | |
186 | |
187 @KeyControls.key_press(key.R) | |
188 def remap_keys(self): | |
189 if not self.remapped: | |
190 self.bind_key_hold(None, key.W) | |
191 self.bind_key_hold(None, key.A) | |
192 self.bind_key_hold(None, key.S) | |
193 self.bind_key_hold(None, key.D) | |
194 self.bind_key_hold(self.up, key.I) | |
195 self.bind_key_hold(self.left, key.J) | |
196 self.bind_key_hold(self.right, key.L) | |
197 self.bind_key_hold(self.down, key.K) | |
198 else: | |
199 self.bind_key_hold(None, key.I) | |
200 self.bind_key_hold(None, key.J) | |
201 self.bind_key_hold(None, key.K) | |
202 self.bind_key_hold(None, key.L) | |
203 self.bind_key_hold(self.up, key.W) | |
204 self.bind_key_hold(self.left, key.A) | |
205 self.bind_key_hold(self.right, key.D) | |
206 self.bind_key_hold(self.down, key.S) | |
207 self.remapped = not self.remapped | |
208 | |
209 | |
210 window = pyglet.window.Window() | |
211 window.clear() | |
212 controls = TestKeyControls() | |
213 window.push_handlers(controls) | |
214 pyglet.clock.schedule_interval(controls.step, 0.5) | |
215 pyglet.app.run() | |
216 |