1"""
2 Allegro Python port game example
3 Author: Jeroen De Busser
4"""
5import os
6from allegro import
*
7from
random import randint,
random
8
9
10class Pallet:
11 def __init__
(self, x, y, w, h, speed, color
):
12 self.__initials
= (x, y, w, h, speed, color,
0)
13 self.reset
()
14
15 def reset
(self
):
16 '''Resets this pallet to its starting values '''
17 (self.x, self.y, self.w, self.h, self.speed, self.color, self.moving
) = self.__initials
18
19 def update
(self
):
20 self.y
+= self.moving
* self.speed
21 if self.y
< 0:
22 self.y
= 0
23 elif self.y
> al_get_display_height(al_get_current_display()) - self.h:
24 self.y
= al_get_display_height(al_get_current_display()) - self.h
25
26 def draw
(self
):
27 # Fill
28 al_draw_filled_rounded_rectangle(self.x, self.y, self.x
+ self.w, self.y
+ self.h,
6,
6, self.color
)
29 # Highlight
30 al_draw_filled_rounded_rectangle(self.x
+2, self.y
+2, self.x
+ self.w
/2, self.y
+ self.h-5,
4,
4,
al_map_rgba_f(0.
2,
0.
2,
0.
2,
0.
2))
31
32
33class Player
(Pallet
):
34 def __init__
(self, x, y, h, w, speed, keyup, keydown, color
):
35 self.__initials
= (x, y, h, w, speed, keyup, keydown, color
)
36 Pallet.__init__
(self, x, y, h, w, speed, color
)
37 self.keyup, self.keydown
= keyup, keydown
38
39 def handle_event
(self, ev
):
40 if ev.type
== ALLEGRO_EVENT_KEY_DOWN:
41 if ev.keyboard.keycode
== self.keyup:
42 self.moving
= -1
43 elif ev.keyboard.keycode
== self.keydown:
44 self.moving
= 1
45 elif ev.type
== ALLEGRO_EVENT_KEY_UP:
46 if (ev.keyboard.keycode
== self.keyup
and self.moving
== -1) or (ev.keyboard.keycode
== self.keydown
and self.moving
== 1):
47 self.moving
= 0
48
49
50class AI
(Pallet
):
51 def __init__
(self, x, y, w, h, speed, color, difficulty, ball
):
52 Pallet.__init__
(self, x, y, w, h, speed, color
)
53 self.difficulty
= difficulty
54 self.ball
= ball
55
56 def handle_event
(self, ev
):
57 #Only fire on a timer event
58 if ev.type
== ALLEGRO_EVENT_TIMER:
59 #Calculate the target y location according to the difficulty level
60 if self.difficulty
== 1:
61 target_y
= self.ball.y
+ self.ball.size
/2
62 else:
63 #Higher difficulty, so we need to precalculate the position of the ball if it is closer than a certain treshold
64 if self.ball.xdir
== -1 or abs(self.x
- self.ball.x
) > al_get_display_width(al_get_current_display())*(self.difficulty-1
)/self.difficulty:
65 #If the ball is moving away, return to the center of the screen
66 target_y
= al_get_display_height(al_get_current_display())/2
67 else:
68 #The ball is moving towards this pallet within its FOV.
69 #Calculate what the y location of the ball will be when it lands at this pallets x location
70 target_y
= self.ball.y
+ (self.x
- self.ball.x
)*self.ball.ydir
71 if target_y
< 0:
72 target_y
= abs(target_y
)
73 elif target_y
> al_get_display_height(al_get_current_display()):
74 target_y
= al_get_display_height(al_get_current_display()) - target_y %
al_get_display_height(al_get_current_display())
75
76 #Set the movement
77 if target_y
> self.y
+ self.h
*3/4:
78 self.moving
= 1
79 elif target_y
< self.y
+ self.h
*1/4:
80 self.moving
= -1
81 else:
82 self.moving
= 0
83
84
85class Ball:
86 def __init__
(self, x, y, speed, size, pallets, color
):
87 self.x, self.y, self.speed, self.size, self.pallets, self.color
= x, y, speed, size, pallets, color
88 self.xdir
= randint
(0,
1)
89 self.xdir
= self.xdir
- (self.xdir
==0)
90 self.ydir
= randint
(0,
1)
91 self.ydir
= self.ydir
- (self.ydir
==0)
92
93 def update
(self
):
94 new_x
= self.x
+ self.xdir
* self.speed
95 new_y
= self.y
+ self.ydir
* self.speed
96 p
= self.pallets
[(self.xdir
==1)] #The pallet
this ball is flying to
97 if ((new_x
<= p.x
+ p.w
and self.xdir
== -1) or (new_x
+ self.size
>= p.x
and self.xdir
== 1)) and new_y
+ self.size
>= p.y
and new_y
<= p.y
+ p.h:
98 #We hit the pallet
99 self.xdir
= -self.xdir
100 self.speed
+= 0.
1
101 self.on_pallet_touch
(p
)
102 self.new_x
= self.x
103 if self.x
< 0 or self.x
> al_get_display_width(al_get_current_display()):
104 self.on_screen_exit
()
105 if new_y
< 0 or new_y
+ self.size
> al_get_display_height(al_get_current_display()):
106 #We hit a wall
107 self.ydir
= -self.ydir
108 new_y
= self.y #Reset the y value
109 self.x
= new_x
110 self.y
= new_y
111
112 def on_pallet_touch
(self, pallet
):
113 """This function should be called on hitting a pallet"""
114 pass
115
116 def on_screen_exit
(self
):
117 '''This function is called when this ball exits the screen'''
118 pass
119
120 def draw
(self
):
121 #Fill
122 al_draw_filled_circle(self.x
+ self.size
/2, self.y
+ self.size
/2, self.size
/2, self.color
)
123 #Highlight
124 al_draw_filled_circle(self.x
+ self.size
/4, self.y
+ self.size
/4, self.size
/6,
al_map_rgb_f(0.
8,
0.
9,
0.
8))
125
126
127class Upgrade
(Ball
):
128 def __init__
(self, x, y, speed, pallets, color, effect_function
):
129 Ball.__init__
(self, x, y, speed,
10, pallets, color
)
130 self.function
= effect_function
131 self.touched
= False
132
133 def on_pallet_touch
(self, pallet
):
134 self.touched
= True
135 self.function
(pallet
)
136
137 def on_screen_exit
(self
):
138 self.touched
= True
139
140
141def main
():
142 #Initialisation
143 difficulty
= int(input
("What difficulty do you want to play on? Input: 0 for two-player mode, 1-4 for AI difficulty setting.\n"))
144 al_install_system(ALLEGRO_VERSION_INT, None
)
145
146 w, h
= 800,
600
147 #Make lines draw smoother
148 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS,
1, ALLEGRO_SUGGEST
)
149 al_set_new_display_option(ALLEGRO_SAMPLES,
4, ALLEGRO_SUGGEST
)
150 display
= al_create_display(w, h
)
151
152 al_init_primitives_addon()
153 al_install_keyboard()
154 al_init_image_addon()
155 al_init_font_addon()
156
157 font = al_load_font("fixed_font.tga",
0,
0)
158
159 finished
= False
160 need_redraw
= True
161 FPS
= 60
162 pallet_w, pallet_h, pallet_speed
= 20,
80,
5
163 ball_size, ball_speed
= 30,
4.
6
164 players
= []
165 players.append
(Player
(0,h
/2-pallet_h
/2,pallet_w,pallet_h,pallet_speed,ALLEGRO_KEY_W,ALLEGRO_KEY_S,
al_map_rgb_f(1.
0,
0.
0,
0.
0)))
166 ball
= Ball
(w
/2,h
/2,ball_speed,ball_size,players,
al_map_rgb_f(0,
1.
0,
0))
167 if not difficulty:
168 players.append
(Player
(w-pallet_w,h
/2-pallet_h
/2, pallet_w, pallet_h, pallet_speed, ALLEGRO_KEY_UP,ALLEGRO_KEY_DOWN,
al_map_rgb_f(0.
0,
0.
0,
1.
0)))
169 else:
170 players.append
(AI
(w-pallet_w,h
/2-pallet_h
/2, pallet_w, pallet_h, pallet_speed,
al_map_rgb_f(0.
0,
0.
0,
1.
0),difficulty,ball
))
171
172 upgrade_types
= [(al_map_rgb_f(0.
0,
1.
0,
0.
0),lambda pallet:setattr
(pallet,
'h',pallet.h
*1.
25)),
(al_map_rgb_f(1.
0,
0.
0,
0.
0),lambda pallet:setattr
(pallet,
'h',pallet.h
* 0.
8)),
(al_map_rgb_f(1.
0,
1.
0,
1.
0),lambda pallet:setattr
(pallet,
'speed',pallet.speed
* 1.
5)),
(al_map_rgb_f(0.
3,
0.
3,
0.
3),lambda pallet:setattr
(pallet,
'speed',pallet.speed
* 2/3))]
173 upgrade_probability
= 0.
005
174
175 timer
= al_create_timer(1.
0/FPS
)
176
177 queue
= al_create_event_queue()
178 al_register_event_source(queue,
al_get_timer_event_source(timer
))
179 al_register_event_source(queue,
al_get_keyboard_event_source())
180 al_register_event_source(queue,
al_get_display_event_source(display
))
181
182 al_start_timer(timer
)
183
184 upgrades
= []
185
186 score
= [0,
0]
187
188 while True:
189 if need_redraw
and al_is_event_queue_empty(queue
):
190 al_clear_to_color(al_map_rgb_f(0,
0,
0))
191 for player in players:
192 player.draw
()
193 ball.draw
()
194 for upgrade in upgrades:
195 upgrade.draw
()
196 if not finished:
197 al_draw_text(font,
al_map_rgb_f(1,
1,
1), w
/2,
10, ALLEGRO_ALIGN_CENTRE,
"Player 1: use W and S to move, Player 2: use the up and down arrow keys.")
198 else:
199 al_draw_text(font,
al_map_rgb_f(1,
1,
1), w
/2,
10, ALLEGRO_ALIGN_CENTRE,
"Press R to reset, ESC to exit.")
200 al_draw_text(font,
al_map_rgb_f(1,
1,
1), w
/2, h
- 20, ALLEGRO_ALIGN_CENTRE,
"{0} - {1}".format
(*score
))
201 al_flip_display()
202 redraw
= False
203
204 ev
= ALLEGRO_EVENT()
205 al_wait_for_event(queue,byref
(ev
))
206
207 if ev.type
== ALLEGRO_EVENT_TIMER:
208 for player in players:
209 player.update
()
210 ball.update
()
211 if ball.x
+ ball.size
< 0 or ball.x
> w:
212 finished
= True
213 score
[ball.x
< 0] += 1
214 al_stop_timer(timer
)
215 for upgrade in upgrades:
216 upgrade.update
()
217 if upgrade.touched:
218 upgrades.remove
(upgrade
)
219 if random() < upgrade_probability:
220 i
= randint
(0,len
(upgrade_types
)-1)
221 upgrades.append
(Upgrade
(w
/2,h
/2,ball_speed,players,upgrade_types
[i
][0],upgrade_types
[i
][1]))
222 redraw
= True
223 elif
(ev.type
== ALLEGRO_EVENT_KEY_DOWN
and ev.keyboard.keycode
== ALLEGRO_KEY_ESCAPE
) or ev.type
== ALLEGRO_EVENT_DISPLAY_CLOSE:
224 break
225 elif ev.type
== ALLEGRO_EVENT_KEY_DOWN
and ev.keyboard.keycode
== ALLEGRO_KEY_R:
226 ball.x
= w
/2
227 ball.y
= h
/2
228 ball.speed
= ball_speed
229 upgrades
= []
230 for player in players:
231 player.reset
()
232 al_start_timer(timer
)
233 finished
= False
234
235 for player in players:
236 player.handle_event
(ev
)
237
238 al_uninstall_system()
239
240
241if __name__
== '__main__':
242 #Only start the game when this file is executed directly.
243 al_main
(main
)