1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
import pygame, logging
import math, random
log = logging.getLogger( 'horse.game' )
log.setLevel( logging.DEBUG )
class Game():
game_running = True
# tuple for horse location
horse_loc = (0,0)
# array of (image,location) for apple/carrot/etc locations
objects = []
# keep track of the mouse pointer
mouse_pos = (200,200)
# tuple size
screen_size = (0,0)
grass_size = (0,0)
horse_size = (0,0)
apple_size = (0,0)
# images / (type pygame Surface)
grass_image = None
horse_image = None
horse_image_l = None
moving_left = False
apple_image = None
carrot_image = None
hay_image = None
# other parameters
horse_speed = 8 # pixels per tick; at 25 ticks/second, this is approx 200 pixels per second
horse_reach = 20 # pixels from cener of horse where he can reach
target_loc = None
def setup(self,screen):
self.screen_size = screen.get_size() # tuple
# put the horse in the center of the screen
self.horse_loc = (100,100)
# load the images and convert to screen format
self.grass_image = pygame.image.load('images/grass.png','grass')
self.grass_image.convert(screen)
self.grass_size = self.grass_image.get_size()
self.horse_image = pygame.image.load('images/horse.png','horse')
self.horse_image.convert(screen)
self.horse_size = self.horse_image.get_size()
# Make a copy for the left-facing image
self.horse_image_l=pygame.transform.flip(self.horse_image,True,False)
# Make the edibles
self.apple_size = (10,10)
self.apple_image = pygame.Surface(self.apple_size,0,screen)
self.apple_image.fill((0xff,0,0))
self.carrot_size = (7,20)
self.carrot_image = pygame.Surface(self.carrot_size,0,screen)
self.carrot_image.fill((0xff,0x99,0))
self.hay_size = (20,20)
self.hay_image = pygame.Surface(self.hay_size,0,screen)
self.hay_image.fill((0x99,0x66,0x33))
self.update(screen)
def update(self,screen):
"""updates the screen image"""
self.screen_size = screen.get_size() # tuple
# paint background image
# TODO: there is probably a better way to tile the background image
# (and perhaps to tile it only once, and save the base image)
tilex=int(math.ceil(self.screen_size[0]/self.grass_size[0]))
tiley=int(math.ceil(self.screen_size[1]/self.grass_size[1]))
for x in range(0,tilex):
for y in range(0,tiley):
screen.blit(self.grass_image,(x*self.grass_size[0],y*self.grass_size[1]))
# paint horse image on screen
# TODO: flip horse image left or right, depending on the direction she is moving
#screen.blit(self.horse_image,self.horse_loc)
if self.moving_left:
self.drawObject(screen,(self.horse_image_l, self.horse_loc))
else:
self.drawObject(screen,(self.horse_image, self.horse_loc))
# draw apples and other objects
for o in self.objects:
self.drawObject(screen,o)
# flip display buffer
pygame.display.flip()
def drawObject(self,screen,object):
# unpack the object
(image, loc) = object
object_size = image.get_size()
# adjust the upper left corner so that the center of object is at the recorded location
adj_loc = (loc[0]-object_size[0]/2,loc[1]-object_size[1]/2)
screen.blit(image, adj_loc)
def placeObject(self,image,location):
#adj_loc = self.adjust_loc(location, image.get_size())
adj_loc = location
self.objects.append((image,adj_loc))
def adjust_loc(self,loc,object_size):
"""adjust the given location by half the object size. Thus the center of the object will be at loc"""
adj_loc = (loc[0]-object_size[0]/2,loc[1]-object_size[1]/2)
return adj_loc
def handleEvent(self,event):
if event.type == pygame.QUIT:
self.game_running = False
elif event.type == pygame.KEYDOWN:
#log.debug("event keydown: %s", event)
# TODO: keys are not a localized
if event.key in (27,113): # esc or q=quit
log.debug('quit key pressed')
self.game_running = False
elif event.key == 97: # a=apple
self.placeObject(self.apple_image, self.mouse_pos)
elif event.key == 99: # c=carrot
self.placeObject(self.carrot_image, self.mouse_pos)
elif event.key == 104: # h=hay
self.placeObject(self.hay_image, self.mouse_pos)
elif event.type == pygame.KEYUP:
pass
elif event.type == pygame.MOUSEBUTTONDOWN:
#log.debug("event mousedown: %s", event)
# place apples
self.placeObject(self.apple_image, self.mouse_pos)
elif event.type == pygame.MOUSEMOTION:
#log.debug("event mousemove: %s", event)
# Remember mouse location, because we need it in KEYDOWN events
self.mouse_pos = event.pos
else:
#log.debug("event other: %s", event)
pass
def tick(self,millis):
"""updates the game state for a tick"""
# millis is ignored
if len(self.objects)>0:
# move the horse toward the first object in the queue, at full speed
(target_image,target_loc) = self.objects[0]
horse_speed = self.horse_speed
else:
# the horse might feel inclined to wander slowly toward a random target
#if self.target_loc is None:
# self.target_loc = (self.screen_size[0]*random.random(), self.screen_size[1]*random.random())
#target_loc = self.target_loc
# wander toward mouse
target_loc = self.mouse_pos
horse_speed = 2
(distx, disty) = (target_loc[0] - self.horse_loc[0], target_loc[1] - self.horse_loc[1])
# TODO: there is probably a library function to scale this for me
# move the horse approx horse_speed pixels in the indicated direction
dist = math.sqrt(distx*distx+disty*disty)
(movex, movey) = (horse_speed*distx/dist, horse_speed*disty/dist)
# "eat" the object if we are close enough
# (so that we will get a new target next tick)
# TODO: perhaps colision detection would be better here
if dist < self.horse_speed*2:
if len(self.objects)>0:
self.objects.pop(0)
else:
self.target_loc = None
# dont move the horse (causes bounce)
return
# move the horse, but check that the horse has not wandered off the screen
(horsex, horsey) = (self.horse_loc[0] + movex, self.horse_loc[1] + movey)
# TODO: check for a library function to determine out of bounds
if (horsex < 0):
horsex = 0
if (horsey < 0):
horsey = 0
if (horsex > self.screen_size[0]):
horsex = self.screen_size[0]
if (horsey > self.screen_size[1]):
horsey = self.screen_size[1]
self.horse_loc = (horsex,horsey)
if movex<0 and abs(distx)>horse_speed:
self.moving_left = True
else:
self.moving_left = False
def isRunning(self):
return self.game_running
|