1
+ #!/usr/bin/env python2.7
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ pymlgame - controller example
6
+ =============================
7
+
8
+ This example shows how you can use your notebooks keyboard to connect to a pymlgame instance.
9
+ """
10
+
11
+ __author__ = 'Ricardo Band'
12
+ __copyright__ = 'Copyright 2014, Ricardo Band'
13
+ __credits__ = ['Ricardo Band' ]
14
+ __license__ = 'MIT'
15
+ __version__ = '0.1.1'
16
+ __maintainer__ = 'Ricardo Band'
17
+
18
+ __status__ = 'Development'
19
+
20
+ import sys
21
+ import time
22
+ import socket
23
+ from threading import Thread , Timer
24
+
25
+ import pygame
26
+
27
+ # define some constants
28
+ E_UID = pygame .USEREVENT + 1
29
+ E_PLAY = pygame .USEREVENT + 2
30
+ E_RUMBLE = pygame .USEREVENT + 3
31
+
32
+
33
+ class ReceiverThread (Thread ):
34
+ """
35
+ This thread listen on a UDP port for packets from a pymlgame instance.
36
+ """
37
+ def __init__ (self , host = '127.0.0.1' , port = 11338 ):
38
+ """
39
+ Creates the socket and binds it to the given host and port.
40
+ """
41
+ super (ReceiverThread , self ).__init__ ()
42
+ self .host = host
43
+ self .port = port
44
+ self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
45
+ self .sock .bind ((self .host , self .port ))
46
+
47
+ def run (self ):
48
+ while True :
49
+ data , addr = self .sock .recvfrom (1024 )
50
+ data = data .decode ('utf-8' )
51
+
52
+ if data .startswith ('/uid/' ):
53
+ ev = pygame .event .Event (E_UID , {'uid' : int (data [5 :])})
54
+ pygame .event .post (ev )
55
+ elif data .startswith ('/play/' ):
56
+ ev = pygame .event .Event (E_PLAY , {'filename' : str (data [6 :])})
57
+ pygame .event .post (ev )
58
+ elif data .startswith ('/rumble/' ):
59
+ ev = pygame .event .Event (E_RUMBLE , {'duration' : float (data [8 :].replace (',' , '.' ))})
60
+ pygame .event .post (ev )
61
+
62
+
63
+ class Controller (object ):
64
+ def __init__ (self , host = '127.0.0.1' , port = 1337 ):
65
+ self .host = host
66
+ self .port = port
67
+ self .sock = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
68
+
69
+ pygame .init ()
70
+ self .screen = pygame .display .set_mode ((128 , 113 ), pygame .DOUBLEBUF , 32 )
71
+ bg = pygame .image .load ('kbd.png' )
72
+ self .screen .blit (bg , pygame .rect .Rect (0 , 0 , 128 , 113 ))
73
+ pygame .display .flip ()
74
+
75
+ self .keys = [0 for _ in range (14 )]
76
+ self .mapping = {pygame .K_UP : 0 , # Up
77
+ pygame .K_DOWN : 1 , # Down
78
+ pygame .K_LEFT : 2 , # Left
79
+ pygame .K_RIGHT : 3 , # Right
80
+ pygame .K_a : 4 , # A
81
+ pygame .K_w : 5 , # B
82
+ pygame .K_s : 6 , # X
83
+ pygame .K_d : 7 , # Y
84
+ pygame .K_RETURN : 8 , # Start
85
+ pygame .K_SPACE : 9 , # Select
86
+ pygame .K_q : 10 , # L1
87
+ pygame .K_1 : 11 , # L2
88
+ pygame .K_e : 12 , # R1
89
+ pygame .K_3 : 13 } # R2
90
+
91
+ self .timeout = 0
92
+ self .rumble_active = False
93
+ self .uid = None
94
+
95
+ receiver = ReceiverThread ()
96
+ receiver .setDaemon (True )
97
+ receiver .start ()
98
+
99
+ def ping (self ):
100
+ self .sock .sendto (bytes ('/ping/{}' .format (self .uid ).encode ('utf-8' )), (self .host , self .port ))
101
+
102
+ def send_keys (self ):
103
+ # alternative states creation: [1 if k else 0 for k in self.keys]
104
+ states = '/states/{}/{}' .format (self .uid , '' .join ([str (k ) for k in self .keys ]))
105
+ self .sock .sendto (states .encode ('utf-8' ), (self .host , self .port ))
106
+ self .timeout = time .time ()
107
+
108
+ def rumble (self , stop = False ):
109
+ if stop :
110
+ # stop the rumble
111
+ pass
112
+ else :
113
+ # start the rumble
114
+ pass
115
+
116
+ def play_sound (self , filename ):
117
+ pass
118
+
119
+ def handle_inputs (self ):
120
+ while True :
121
+ if time .time () > self .timeout + 30 :
122
+ self .ping ()
123
+
124
+ events = pygame .event .get ()
125
+ for event in events :
126
+ if event .type == pygame .QUIT :
127
+ pygame .quit ()
128
+ sys .exit (0 )
129
+ elif event .type == pygame .MOUSEBUTTONUP :
130
+ pygame .event .post (pygame .event .Event (pygame .QUIT ))
131
+ elif event .type == E_UID :
132
+ self .uid = event .uid
133
+ if self .uid :
134
+ if event .type == E_PLAY :
135
+ self .play_sound (event .filename )
136
+ elif event .type == E_RUMBLE :
137
+ self .rumble ()
138
+ #TODO: check if the timers get killed when they are stopped. no zombies allowed here!
139
+ t = Timer (event .duration , self .rumble , args = [True , ])
140
+ t .setDaemon (True )
141
+ t .start ()
142
+ elif event .type == pygame .KEYDOWN or event .type == pygame .KEYUP :
143
+ try :
144
+ button = self .mapping [event .key ]
145
+ if event .type == pygame .KEYDOWN :
146
+ print ('{}({}) key down' .format (event .key , button ))
147
+ self .keys [button ] = 1
148
+ elif event .type == pygame .KEYUP :
149
+ print ('{}({}) key up' .format (event .key , button ))
150
+ self .keys [button ] = 0
151
+ self .send_keys ()
152
+ except KeyError :
153
+ break
154
+
155
+
156
+ if __name__ == '__main__' :
157
+ ctlr = Controller ()
158
+ try :
159
+ while True :
160
+ ctlr .handle_inputs ()
161
+ except KeyboardInterrupt :
162
+ pass
0 commit comments