5 (C) 2008 Gergely Imreh <imrehg@gmail.com>
7 Accelerometer code: Martin Senkerik <martinsenkerik@gmail.com>
19 import threading
, time
21 from math
import pi
, ceil
25 # Accelerometer thread
38 ## Shut down accelerometer thread when finished
41 def progress_timeout(object):
42 """ Repeated event to redraw graphics """
44 x
, y
, w
, h
= object.allocation
45 object.window
.invalidate_rect((0,0,w
,h
),False)
46 ## Every segment survived worth 1 point
47 object.score
= object.score
+1
48 ## If crashed, game over
49 return object.checkcrash()
51 class Field(gtk
.DrawingArea
):
54 gtk
.DrawingArea
.__init
__(self
)
55 self
.add_events(gtk
.gdk
.BUTTON_PRESS_MASK |
56 gtk
.gdk
.BUTTON_RELEASE_MASK |
57 gtk
.gdk
.BUTTON1_MOTION_MASK |
60 ## Implement later: Pause on touch of screen
61 # self.connect("button_press_event", self.on_button_press_event)
64 self
.connect("expose_event", self
.do_expose_event
)
65 ## Timer to redraw screen: every 170ms
66 ## Right now: go faster -> slugish graphics, go slower -> slugish everything
67 self
.timer
= gobject
.timeout_add (170, progress_timeout
, self
)
70 self
.path
= [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200]
71 self
.pwidth
= [180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180]
75 ## Probabilities of road direction changes
76 ## 0,1 : probability of UP,AHEAD, when going UP now
77 ## 2,3 : probability of UP,AHEAD, when going AHEAD now
78 ## 4,5 : probability of UP,AHEAD, when going DOWN now
79 ## (third probability is always 1-p0-p1 for them to add up to 1)
80 self
.probs
= [0.5, 0.4, 0.2, 0.6, 0.2, 0.4]
81 ## Probabilities of width changes:
82 ## 0,1 : getting NARROWER or STAYING SAME.
83 ## probability of getting WIDER is just 1-p0-p1
84 self
.wprobs
= [0.1, 0.8]
86 ## Starting by going ahead
88 ## Unit of changes in road segment UP or DOWN in any given step
90 ## Units of change in width
92 ## Defines the ship's speed: max step in one redraw either up or down.
94 ## Starting shipposition
97 ## Ratio is how much the speed changes compared to the .shipspeed
99 ## We are healthy first
105 def do_expose_event(self
, w
, event
):
106 # Handle the expose-event by drawing
108 self
.cr
= self
.window
.cairo_create()
109 except AttributeError:
110 #return self._expose_gdk(event)
112 return self
._expose
_cairo
(event
)
115 def _expose_cairo(self
, event
):
116 """ What to do on expose """
117 # Create the cairo context
118 self
.cr
= self
.window
.cairo_create()
120 # Restrict Cairo to the exposed area; avoid extra work
121 self
.cr
.rectangle(event
.area
.x
, event
.area
.y
,
122 event
.area
.width
, event
.area
.height
)
124 ## Drawing background
131 """ Refresh screen """
133 x
, y
, w
, h
= self
.allocation
134 self
.window
.invalidate_rect((0,0,w
,h
),False)
137 """ Call ship position update and draw ship - in pieces of crashed """
140 if debug
: print "DEBUG:","Draw ship at ",self
.shippos
141 ## Draw ship in pieces (with a little randomness) if crashed
143 self
.cr
.set_source_rgba(1, 0, 0, 0.6)
144 self
.cr
.arc(20+10*random
.random(), self
.shippos
+10*random
.random(), 3.0, 0, 2*pi
)
146 self
.cr
.arc(20+10*random
.random(), self
.shippos
-10*random
.random(), 4.0, 0, 2*pi
)
148 self
.cr
.arc(20-10*random
.random(), self
.shippos
-10*random
.random(), 5.0, 0, 2*pi
)
150 self
.cr
.arc(20-10*random
.random(), self
.shippos
+10*random
.random(), 5.0, 0, 2*pi
)
153 ## Draw ship in one piece still, yippie....
154 self
.cr
.set_source_rgba(1, 0.8, 0.2, 0.6)
155 self
.cr
.arc(20, self
.shippos
, 10.0, 0, 2*pi
)
158 def checkcrash(self
):
159 """ Routine to check every update, whether the ship crashed and to vibration if it did """
160 ## Check for crash - taking ship size of r=5 into account
161 if (self
.shippos
<= self
.path
[0]+5 ) or (self
.shippos
>= self
.path
[0]+self
.pwidth
[0]-5):
162 if debug
: print "DEBUG:","Crashed!!"
165 outfile
= open("/sys/class/leds/neo1973:vibrator/brightness", "w", 1)
166 outfile
.write("%s\n" % str(intensity
))
173 ## No crash, carry on
178 def updateshippos(self
):
179 """ Updating the ship position, according to tilt~ship-speed """
180 self
.shippos
= self
.shippos
+self
.shipspeed
*self
.shipratio
181 if debug
: print "DEBUG:","Updateship: Pos:",self
.shippos
,"Speed:",self
.shipratio
,"New Pos:",self
.shippos
184 def redrawfield(self
):
185 """ Drawing background, score, valley walls """
187 width
, height
= self
.window
.get_size()
188 ## Fill the background with gray
189 self
.cr
.set_source_rgb(0, 0, 0)
190 self
.cr
.rectangle(0, 0, width
, height
)
193 ## Display score: rotated, in corner
194 self
.cr
.set_source_rgb(1, 0.0, 0.0)
195 self
.scorefield
= self
.create_pango_layout(str(self
.score
))
196 self
.scorefield
.set_font_description(pango
.FontDescription("sans serif 10"))
197 self
.cr
.move_to(440,30)
198 self
.cr
.rotate( 90 / (180.0 / pi
));
199 self
.cr
.update_layout(self
.scorefield
)
200 self
.cr
.show_layout(self
.scorefield
)
201 self
.cr
.rotate( -90 / (180.0 / pi
));
203 ########## Drawing lines##########
205 ## Change probabilities: close to edges, too wide or too narrow paths
206 inprob
,inwprob
= self
.changeprob(self
.path
[-1],self
.pwidth
[-1],self
.probs
,self
.wprobs
)
207 ## Where should the road go next?
208 self
.pstate
= self
.newstate(self
.pstate
,inprob
)
211 ## Calculate position of next road segment
212 newpos
= self
._newpath
(self
.path
,self
.pstate
)
213 if debug
: print "DEBUG:","New Road segment:",newpos
214 self
.path
.append(newpos
)
216 ## Calculate new width
217 wy
= self
._newwidth
(self
.pwidth
[-1],inwprob
)
218 if debug
: print "DEBUG:","New Width :",wy
219 self
.pwidth
.append(wy
)
221 ## Set color of valley walls
222 self
.cr
.set_source_rgb(0.9, 0.9, 0.9)
224 ## Index of staring positions
226 ## length of elementary segments
227 tos
= ceil(width
/self
.maxindex
)
228 ## Loop through segments
229 for index
, item
in enumerate(self
.path
):
230 if index
< self
.maxindex
:
231 self
.cr
.move_to(to
,item
)
234 ## Curves to sloooow, using line_to only....
235 #### self.cr.curve_to(to,item,to-tos,self.path[index+1],to,self.path[index+1])
236 #### self.cr.move_to(to-tos,item+self.pwidth[index])
237 #### self.cr.curve_to(to,item+self.pwidth[index],to-tos,self.path[index+1]+self.pwidth[index+1],to,self.path[index+1]+self.pwidth[index+1])
241 self
.cr
.line_to(to
,self
.path
[index
+1])
242 self
.cr
.move_to(to
-tos
,item
+self
.pwidth
[index
])
244 self
.cr
.line_to(to
,self
.path
[index
+1]+self
.pwidth
[index
+1])
249 ## Throw away used path segments
253 ##### End of redraw()
257 def _newwidth(self
,width
,wprob
):
258 """ Use probabilities to change path width """
259 change
= random
.random()
260 if change
< wprob
[0]:
262 return width
-self
.wstep
263 elif change
< wprob
[0]+wprob
[1]:
268 return width
+self
.wstep
271 def _newpath(self
,path
,pstate
):
272 """ Change path direction according to status """
274 ## Move road up (compared to the last piece of road already generated)
275 return path
[-1]-self
.stepsize
281 return path
[-1]+self
.stepsize
285 def newstate(self
,state
,probs
):
286 """ Use Markov probabilities to change direction of path """
290 ## Now: Going straight
297 ## Choose new direction
298 change
= random
.random()
299 if change
< sprob
[0]:
302 elif change
< sprob
[0]+sprob
[1]:
309 def changeprob(self
,pos
,width
,probs
,wprobs
):
310 """ Change probabilities of directions of winding path """
311 if debug
: print "DEBUG:","Before next: Pos:",pos
,"Width:",width
313 outwprobs
= wprobs
[:]
317 if debug
: print "DEBUG:","Too HIGH"
320 elif pos
>= 470-width
:
321 if debug
: print "DEBUG:","Too LOW"
322 norm
= outprobs
[2]+outprobs
[3]
323 outprobs
[2] = outprobs
[2]/norm
324 outprobs
[3] = outprobs
[3]/norm
325 norm
= outprobs
[4]+outprobs
[5]
326 outprobs
[4] = outprobs
[4]/norm
327 outprobs
[5] = outprobs
[5]/norm
328 ## Path width: min 70, max 180
330 if debug
: print "DEBUG:","Too Narrow"
333 if debug
: print "DEBUG:","Too Wide"
334 norm
= outwprobs
[0]+outwprobs
[1]
335 outwprobs
[0] = outwprobs
[0]/norm
336 outwprobs
[1] = outwprobs
[1]/norm
338 return outprobs
,outwprobs
342 """ Form to display game area """
344 ## accelerometer thread
346 gtk
.gdk
.threads_init()
349 """ Draw window: buttons and drawing arrea """
350 self
.ready_semaphore
= threading
.Semaphore()
351 self
.ready_semaphore
.acquire()
354 self
.window
= gtk
.Window()
355 self
.window
.connect("delete-event", main_quit
)
356 self
.window
.connect('destroy', main_quit
)
357 self
.window
.set_title("DeathValleyX")
360 ## vertical box to align buttons and drawing screen
361 ## input Homogeneous, Spacing
362 box1
= gtk
.VBox(False,0)
365 button
= gtk
.Button("eXit")
366 button
.connect_object("clicked", main_quit
, self
.window
)
367 box1
.pack_start(button
,True,True,0)
371 self
.drawing_area
= Field()
372 self
.drawing_area
.set_size_request(480, 480)
373 box1
.pack_start(self
.drawing_area
, False, False, 0)
374 self
.drawing_area
.show()
376 ## Level-down and level-up buttons
377 ## All in horizontal box
378 box2
= gtk
.HBox(False,0)
379 button
= gtk
.Button("|")
381 button
.Sensitive
= False
382 #### button.connect_object("clicked", main_quit, self.window)
383 box2
.pack_start(button
,True,True,0)
386 button
= gtk
.Button("+")
388 #### button.connect_object("clicked", main_quit, self.window)
389 box2
.pack_start(button
,True,True,0)
393 box1
.pack_start(box2
,True,True,0)
395 self
.window
.add(box1
)
398 ## Finish drawing window
400 ## start accelerometer thread
401 self
.ready_semaphore
.release()
406 """ Main function - create window and accelerometer thread """
407 ## Accelerometer thread
413 ## start accelerometer
414 amthread
= accelero
.Worker(form
)
424 if __name__
== "__main__":