-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsprites.py
More file actions
237 lines (201 loc) · 8.79 KB
/
sprites.py
File metadata and controls
237 lines (201 loc) · 8.79 KB
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# Sprites classes for the game
import pygame as pg
from settings import *
from random import choice, randrange
vec = pg.math.Vector2
class Spritesheet:
# Utility class for loading and parsing spritesheets
def __init__(self, filename):
self.spritesheet = pg.image.load(filename).convert()
def get_image(self, x, y, width, height):
# Grab an image out of a spritesheet
image = pg.Surface((width, height))
image.blit(self.spritesheet, (0, 0), (x, y, width, height))
image = pg.transform.scale(image, (int(width / 2), int(height / 2)))
return image
class Player(pg.sprite.Sprite):
def __init__(self, game):
self._layer = PLAYER_LAYER
self.groups = game.all_sprites
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.walking = False
self.jumping = False
self.current_frame = 0
self.last_update = 0
self.load_images()
self.image = self.standing_frames[0]
self.rect = self.image.get_rect()
self.rect.center = (40, HEIGHT - 100)
self.pos = vec(40, HEIGHT - 100)
self.vel = vec(0, 0)
self.acc = vec(0, 0)
def load_images(self):
self.standing_frames = [self.game.spritesheet.get_image(614, 1063, 120, 191),
self.game.spritesheet.get_image(690, 406, 120, 201)]
for frame in self.standing_frames:
frame.set_colorkey(BLACK) # Fix transparency
self.walk_frames_r = [self.game.spritesheet.get_image(678, 860, 120, 201),
self.game.spritesheet.get_image(692, 1458, 120, 207)]
for frame in self.walk_frames_r:
frame.set_colorkey(BLACK) # Fix transparency
self.walk_frames_l = [] # Flip walking_frames_r
for frame in self.walk_frames_r:
self.walk_frames_l.append(pg.transform.flip(frame, True, False))
for frame in self.walk_frames_l:
frame.set_colorkey(BLACK) # Fix transparency
self.jump_frame = self.game.spritesheet.get_image(382, 763, 150, 181)
self.jump_frame.set_colorkey(BLACK) # Fix transparency
def jump(self):
# Jump only if stating on a platform
self.rect.x += 2
hits = pg.sprite.spritecollide(self, self.game.platforms, False)
self.rect.x -= 2
if hits and not self.jumping:
self.game.jump_sound.play()
self.jumping = True
self.vel.y = -PLAYER_JUMPPOWER
def jump_cut(self):
if self.jumping:
if self.vel.y < -3:
self.vel.y = -3
def update(self):
self.animate()
self.acc = vec(0, PLAYER_GRAVITY)
keys = pg.key.get_pressed()
if keys[pg.K_LEFT]:
self.acc.x = -PLAYER_ACC
if keys[pg.K_RIGHT]:
self.acc.x = PLAYER_ACC
# Applies friction
self.acc.x += self.vel.x * PLAYER_FRICTION
# Equation of motion
self.vel += self.acc
# Fix animation not knowing that our player stopped.
# Because of friction, our speed will never be 0.
# So we have to set a "lowest" threshold before we change to "Standing" state.
if abs(self.vel.x) < 0.5: # TODO: Move this to settings.py
self.vel.x = 0
self.pos += self.vel + 0.5 * self.acc
# Wrap around the sides of the screen
if self.pos.x > WIDTH + self.rect.width / 2:
self.pos.x = 0 - self.rect.width / 2
if self.pos.x < 0 - self.rect.width / 2:
self.pos.x = WIDTH + self.rect.width / 2
self.rect.midbottom = self.pos
def animate(self):
now = pg.time.get_ticks()
# Get movement state.
if self.vel.x != 0:
self.walking = True
else:
self.walking = False
# Show walking animation
if self.walking:
if now - self.last_update > 150: # TODO: Move this to settings.py = Worth exploring a "per sprite" implementation.
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.walk_frames_l)
bottom = self.rect.bottom
if self.vel.x > 0:
self.image = self.walk_frames_r[self.current_frame]
else:
self.image = self.walk_frames_l[self.current_frame]
self.rect = self.image.get_rect()
self.rect.bottom = bottom
# Show IDLE / Standing animation
if not self.jumping and not self.walking:
if now - self.last_update > 350: # TODO: Move this to settings.py
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.standing_frames)
bottom = self.rect.bottom
self.image = self.standing_frames[self.current_frame]
self.rect = self.image.get_rect()
self.rect.bottom = bottom
self.mask = pg.mask.from_surface(self.image) # Pixel Perfect Collision (Mark collision)
class Cloud(pg.sprite.Sprite):
def __init__(self, game):
self._layer = CLOUD_LAYER
self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = choice(self.game.cloud_images)
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
scale = randrange(50, 101) / 100
self.image = pg.transform.scale(self.image, (int(self.rect.width * scale),
int(self.rect.height * scale)))
self.rect.x = randrange(WIDTH - self.rect.width)
self.rect.y = randrange(-500, -50)
def update(self):
if self.rect.top > HEIGHT * 2:
self.kill()
class Platform(pg.sprite.Sprite):
def __init__(self, game, x, y):
self._layer = PLATFORM_LAYER
self.groups = game.all_sprites, game.platforms
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
# TODO: Move this do a SpritesDB location where I have every sprite's cords stores. Then call by name
images = [self.game.spritesheet.get_image(0, 288, 380, 94),
self.game.spritesheet.get_image(213, 1662, 201, 100)]
self.image = choice(images)
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
if randrange(100) < POWER_SPAWN_RATE:
PowerUps(self.game, self)
print("Spawned Powerup")
class PowerUps(pg.sprite.Sprite):
def __init__(self, game, platform):
self._layer = POWER_LAYER
self.groups = game.all_sprites, game.powerups
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.platform = platform
self.type = choice(['boost']) # Choose which powerup will get spawned
# TODO: Move this do a SpritesDB location where I have every sprite's cords stores. Then call by name
self.image = self.game.spritesheet.get_image(820, 1805, 71, 70)
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.centerx = self.platform.rect.centerx
self.rect.bottom = self.platform.rect.top - 5
def update(self):
self.rect.bottom = self.platform.rect.top - 5
if not self.game.platforms.has(self.platform):
self.kill()
class Mob(pg.sprite.Sprite):
def __init__(self, game):
self._layer = MOB_LAYER
self.groups = game.all_sprites, game.mobs
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image_up = self.game.spritesheet.get_image(566, 510, 122, 139)
self.image_up.set_colorkey(BLACK)
self.image_down = self.game.spritesheet.get_image(568, 1534, 122, 135)
self.image_down.set_colorkey(BLACK)
self.image = self.image_up
self.rect = self.image.get_rect()
self.rect.centerx = choice([-100, WIDTH + 100])
self.vx = randrange(1, 4)
if self.rect.centerx > WIDTH:
self.vx *= -1
self.rect.y = randrange(HEIGHT / 2)
self.vy = 0
self.dy = 0.5 # Acceleration and Deceleration
def update(self):
self.rect.x += self.vx
self.vy += self.dy
if self.vy > 3 or self.vy < -3:
self.dy *= -1
center = self.rect.center # Find the center of the sprite animations
if self.dy < 0:
self.image = self.image_up
else:
self.image = self.image_down
self.rect = self.image.get_rect()
self.mask = pg.mask.from_surface(self.image) # Pixel Perfect Collision (Mark collision)
self.rect.center = center
self.rect.y += self.vy
if self.rect.left > WIDTH + 100 or self.rect.right < -100:
self.kill()