Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/horse/game.py
blob: 6e2d5f6460fe71e14e6a8e688b6813e8b2ea65e5 (plain)
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('horse/grass.png','grass')
        self.grass_image.convert(screen)
        self.grass_size = self.grass_image.get_size()
        self.horse_image = pygame.image.load('horse/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