5
5
pymlgame - controller example
6
6
=============================
7
7
8
- This example shows how you can use a controller connected to a laptop or any
9
- other machine capable of pygame to connect to a pymlgame instance.
8
+ This example shows how you can use your notebooks keyboard to connect to a pymlgame instance.
10
9
"""
11
10
12
- __author__ = 'Ricardo Band'
13
- __copyright__ = 'Copyright 2014, Ricardo Band'
14
- __credits__ = ['Ricardo Band' ]
15
- __license__ = 'MIT'
16
- __version__ = '0.1.1'
17
- __maintainer__ = 'Ricardo Band'
18
-
19
- __status__ = 'Development'
20
-
21
11
import sys
12
+ import time
13
+ import socket
14
+ import logging
15
+ logging .basicConfig (format = '%(asctime)s | %(levelname)s | %(message)s' , datefmt = '%Y-%m-%d %H:%M:%S' )
16
+ from datetime import datetime
17
+ from threading import Thread
22
18
23
19
import pygame
24
- import jsonrpclib
25
20
21
+ # define some constants
22
+ E_UID = pygame .USEREVENT + 1
23
+ E_DOWNLOAD = pygame .USEREVENT + 2
24
+ E_PLAY = pygame .USEREVENT + 3
25
+ E_RUMBLE = pygame .USEREVENT + 4
26
26
27
- class Controller (object ):
28
- def __init__ (self , host , port ):
27
+
28
+ class ReceiverThread (Thread ):
29
+ """
30
+ This thread will listen on a UDP port for packets from the game.
31
+ """
32
+ def __init__ (self , host = '127.0.0.1' , port = 11337 ):
33
+ """
34
+ Creates the socket and binds it to the given host and port.
35
+ """
36
+ super (ReceiverThread , self ).__init__ ()
29
37
self .host = host
30
38
self .port = port
39
+ self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
40
+ self .sock .bind ((self .host , self .port ))
41
+
42
+ def run (self ):
43
+ while True :
44
+ data , addr = self .sock .recvfrom (1024 )
45
+ data = data .decode ('utf-8' )
46
+
47
+ logging .info ('example info' )
48
+ logging .warning ('example warning' )
49
+ logging .error ('example error' )
50
+ logging .critical ('example critical' )
51
+ #print(datetime.now(), '<<< {}'.format(data))
52
+ if data .startswith ('/uid/' ):
53
+ #print(datetime.now(), '### uid', data[5:], 'received')
54
+ e = pygame .event .Event (E_UID , {'uid' : int (data [5 :])})
55
+ pygame .event .post (e )
56
+ elif data .startswith ('/download/' ):
57
+ e = pygame .event .Event (E_DOWNLOAD , {'url' : str (data [10 :])})
58
+ pygame .event .post (e )
59
+ elif data .startswith ('/play/' ):
60
+ e = pygame .event .Event (E_PLAY , {'filename' : str (data [6 :])})
61
+ pygame .event .post (e )
62
+ elif data .startswith ('/rumble/' ):
63
+ e = pygame .event .Event (E_RUMBLE , {'duration' : float (data [8 :].replace (',' , '.' ))})
64
+ pygame .event .post (e )
65
+
66
+
67
+ class Controller (object ):
68
+ def __init__ (self , game_host = '127.0.0.1' , game_port = 1338 , host = '127.0.0.1' , port = 11337 ):
69
+ self .game_host = game_host # Host of Mate Light
70
+ self .game_port = game_port # Port of Mate Light
71
+ self .host = host # Host of ReceiverThread
72
+ self .port = port # Port of ReceiverThread
73
+ self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
74
+
31
75
pygame .init ()
32
- self .joysticks = [[pygame .joystick .Joystick (j ), None , None ]
33
- for j in range (pygame .joystick .get_count ())]
34
- self .screen = pygame .display .set_mode ((100 , 10 ))
35
- pygame .display .set_caption ("pymlgame_ctlr" )
36
- self .clock = pygame .time .Clock ()
37
- self .server = jsonrpclib .Server ('http://' + self .host + ':' +
38
- str (self .port ))
39
- for joy in self .joysticks :
40
- joy [0 ].init ()
41
- joy [1 ] = self .server .init ()
42
- if joy [0 ].get_name () == 'Xbox 360 Wireless Receiver' :
43
- joy [2 ] = {0 : 'A' ,
44
- 1 : 'B' ,
45
- 2 : 'X' ,
46
- 3 : 'Y' ,
47
- 4 : 'L1' ,
48
- 5 : 'R1' ,
49
- 6 : 'Select' ,
50
- 7 : 'Start' ,
51
- 11 : 'Left' ,
52
- 12 : 'Right' ,
53
- 13 : 'Up' ,
54
- 14 : 'Down' }
55
-
56
- def handle_events (self ):
76
+ self .screen = pygame .display .set_mode ((128 , 113 ), pygame .DOUBLEBUF , 32 )
77
+ bg = pygame .image .load ('kbd.png' )
78
+ self .screen .blit (bg , pygame .rect .Rect (0 , 0 , 128 , 113 ))
79
+ pygame .display .flip ()
80
+
81
+ self .keys = [0 for _ in range (14 )]
82
+ self .mapping = {pygame .K_UP : 0 , # Up
83
+ pygame .K_DOWN : 1 , # Down
84
+ pygame .K_LEFT : 2 , # Left
85
+ pygame .K_RIGHT : 3 , # Right
86
+ pygame .K_a : 4 , # A
87
+ pygame .K_w : 5 , # B
88
+ pygame .K_s : 6 , # X
89
+ pygame .K_d : 7 , # Y
90
+ pygame .K_RETURN : 8 , # Start
91
+ pygame .K_SPACE : 9 , # Select
92
+ pygame .K_q : 10 , # L1
93
+ pygame .K_1 : 11 , # L2
94
+ pygame .K_e : 12 , # R1
95
+ pygame .K_3 : 13 } # R2
96
+
97
+ self .timeout = 0 # if the controller is in idle state a ping signal will be sent
98
+ self .rumble_active = False
99
+ self .uid = None
100
+
101
+ self ._receiver = ReceiverThread (host , port )
102
+ self ._receiver .setDaemon (True )
103
+ self ._receiver .start ()
104
+
105
+ def ping (self ):
106
+ if self .uid :
107
+ msg = '/controller/{}/ping/{}' .format (self .uid , self ._receiver .port )
108
+ self .sock .sendto (msg .encode ('utf-8' ), (self .game_host , self .game_port ))
109
+ #print(datetime.now(), '>>>', msg)
110
+
111
+ def send_keys (self ):
112
+ # alternative states creation: [1 if k else 0 for k in self.keys]
113
+ states = '/controller/{}/states/{}' .format (self .uid , '' .join ([str (k ) for k in self .keys ]))
114
+ self .sock .sendto (states .encode ('utf-8' ), (self .game_host , self .game_port ))
115
+ #print(datetime.now(), '>>>' + states)
116
+ self .timeout = time .time ()
117
+
118
+ def send_message (self , msg ):
119
+ pass
120
+
121
+ def disconnect (self ):
122
+ msg = '/controller/{}/kthxbye' .format (self .uid )
123
+ self .sock .sendto (msg .encode ('utf-8' ), (self .game_host , self .game_port ))
124
+
125
+ def connect (self ):
126
+ msg = '/controller/new/{}' .format (self .port )
127
+ self .sock .sendto (msg .encode ('utf-8' ), (self .game_host , self .game_port ))
128
+
129
+ def rumble (self , duration ):
130
+ pass
131
+
132
+ def download_sound (self , url ):
133
+ pass
134
+
135
+ def play_sound (self , filename ):
136
+ pass
137
+
138
+ def handle_inputs (self ):
139
+ if time .time () > self .timeout + 30 :
140
+ self .ping ()
141
+ self .timeout = time .time ()
142
+
57
143
for event in pygame .event .get ():
58
144
if event .type == pygame .QUIT :
59
- pygame .joystick .quit ()
60
145
pygame .quit ()
61
- sys .exit ()
62
- if event .type == pygame .KEYDOWN :
63
- if event .key == pygame .K_ESCAPE :
64
- pygame .event .post (pygame .event .Event (pygame .QUIT ))
65
- if event .type == pygame .JOYBUTTONDOWN :
66
- print ('joy' , self .joysticks [event .joy ][0 ].get_name (),
67
- '(uid:' , self .joysticks [event .joy ][1 ], ')button pressed:' ,
68
- event .button )
69
- self .server .trigger_button (self .joysticks [event .joy ][1 ],
70
- 'KeyDown' ,
71
- self .joysticks [event .joy ][2 ][event .button ])
72
- if event .type == pygame .JOYBUTTONUP :
73
- print ('joy' , self .joysticks [event .joy ][0 ].get_name (),
74
- '(uid:' , self .joysticks [event .joy ][1 ], ')button released:' ,
75
- event .button )
76
- self .server .trigger_button (self .joysticks [event .joy ][1 ],
77
- 'KeyUp' ,
78
- self .joysticks [event .joy ][2 ][event .button ])
79
-
80
- def update (self ):
81
- pass
82
-
83
- def render (self ):
84
- pygame .display .update ()
85
- pygame .display .flip ()
146
+ sys .exit (0 )
147
+ elif event .type == pygame .MOUSEBUTTONUP :
148
+ pygame .event .post (pygame .event .Event (pygame .QUIT ))
149
+ elif event .type == E_UID :
150
+ #print(datetime.now(), '### UID event received', event.uid)
151
+ self .uid = event .uid
86
152
87
- def gameloop (self ):
88
- try :
89
- while True :
90
- self .handle_events ()
91
- self .update ()
92
- self .render ()
93
- except KeyboardInterrupt :
94
- pass
153
+ if self .uid is not None :
154
+ #print(datetime.now(), '### UID set. checking other events')
155
+ if event .type == E_DOWNLOAD :
156
+ self .download_sound (event .url )
157
+ elif event .type == E_PLAY :
158
+ self .play_sound (event .filename )
159
+ elif event .type == E_RUMBLE :
160
+ self .rumble (event .duration )
161
+ elif event .type == pygame .KEYDOWN or event .type == pygame .KEYUP :
162
+ try :
163
+ button = self .mapping [event .key ]
164
+ if event .type == pygame .KEYDOWN :
165
+ #print('{} | {}'.format(event.key, button))
166
+ self .keys [button ] = 1
167
+ elif event .type == pygame .KEYUP :
168
+ #print('{} | {}'.format(event.key, button))
169
+ self .keys [button ] = 0
170
+ self .send_keys ()
171
+ except KeyError :
172
+ break
173
+ else :
174
+ #print(datetime.now(), '### UID not set. connecting to game.')
175
+ self .connect ()
176
+ time .sleep (1 )
95
177
96
178
97
179
if __name__ == '__main__' :
98
- CTLR = Controller ('127.0.0.1' , 1338 )
99
- CTLR .gameloop ()
180
+ ctlr = Controller ('127.0.0.1' , 1338 , '127.0.0.1' , 11337 )
181
+ try :
182
+ while True :
183
+ ctlr .handle_inputs ()
184
+ except KeyboardInterrupt :
185
+ if ctlr .uid is not None :
186
+ ctlr .disconnect ()
187
+ pass
0 commit comments