1import pygame 2import pygame 3import math 4import random 5import sys 6import os 7 8import PixelPerfect 9 10from pygame.locals import * 11 12from shark import Shark 13from health import Health 14from cannonball import Cannonball 15from steamboat import Steamboat 16from particles import Particles 17from mine import Mine 18from score import Score 19from water import Water 20from pirateboat import Pirateboat 21from seagull import Seagull 22from level import Level 23from titanic import Titanic 24from powerup import Powerup 25 26import cloud 27 28import util 29 30from locals import * 31 32rr=random.random 33 34def rrr(left,right): 35 return left+rr()*(right-left) 36 37class Game: 38 sky = None 39 40 41 42 43 44 def __init__(self, screen, endless = False): 45 self.screen = screen 46 47 self.sharks = [] 48 self.shark_sprites = pygame.sprite.Group() 49 50 self.player = Steamboat() 51 self.player_sprite = pygame.sprite.Group() 52 self.player_sprite.add(self.player) 53 54 self.health = Health() 55 self.health_sprite = pygame.sprite.Group() 56 self.health_sprite.add(self.health) 57 58 self.damage_count = 0 59 60 self.t = 0 61 62 self.water = Water.global_water 63 #Water.global_water = self.water 64 self.water_sprite = pygame.sprite.Group() 65 self.water_sprite.add(self.water) 66 67 if not Game.sky: 68 Game.sky = util.load_image("taivas") 69 Game.sky = pygame.transform.scale(self.sky, (SCREEN_WIDTH, SCREEN_HEIGHT)) 70 71 self.cannonballs = [] 72 self.cannonball_sprites = pygame.sprite.Group() 73 74 self.pirates = [] 75 self.pirate_sprites = pygame.sprite.Group() 76 77 self.titanic = None 78 self.titanic_sprite = pygame.sprite.Group() 79 80 self.seagulls = [] 81 self.seagull_sprites = pygame.sprite.Group() 82 83 self.particles = Particles() 84 self.particle_sprite = pygame.sprite.Group() 85 self.particle_sprite.add(self.particles) 86 87 self.mines = [] 88 self.mine_sprites = pygame.sprite.Group() 89 90 self.score = Score() 91 self.score_sprite = pygame.sprite.Group() 92 self.score_sprite.add(self.score) 93 94 self.powerups = [] 95 self.powerup_sprites = pygame.sprite.Group() 96 97 self.level = Level(endless) 98 99 self.lastshot = MIN_FIRE_DELAY + 1 100 101 self.gameover = False 102 self.gameover_image = None 103 self.gameover_rect = None 104 self.done = False 105 106 self.pause = False 107 self.pause_image = util.bigfont.render("Pause", Variables.alpha, (0,0,0)) 108 self.pause_rect = self.pause_image.get_rect() 109 self.pause_rect.center = self.screen.get_rect().center 110 111 self.spacepressed = None 112 113 def run(self): 114 while not self.done: 115 if not self.pause: 116 if not self.gameover: 117 self.spawn_enemies() 118 119 self.update_enemies() 120 self.player.update() 121 self.health.update() 122 cloud.update() 123 for cb in self.cannonballs: 124 if not cb.underwater: 125 #~ particle_point=cb.rect.left, cb.rect.top 126 particle_point = cb.tail_point() 127 self.particles.add_trace_particle(particle_point) 128 particle_point = [particle_point[i] + cb.vect[i]/2 for i in (0,1)] 129 self.particles.add_trace_particle(particle_point) 130 if cb.special and (not cb.underwater or rr()>0.6) : 131 particle_point = cb.tail_point() 132 self.particles.add_explosion_particle(particle_point) 133 und_old=cb.underwater 134 cb.update() 135 if cb.underwater and not und_old: 136 for i in range(5): 137 particle_point=cb.rect.right-4.0+rr()*8.0, cb.rect.top+rr()*2.0 138 self.particles.add_water_particle(particle_point) 139 if (cb.rect.right < 0 and cb.vect[0] < 0) or (cb.rect.left > SCREEN_WIDTH and cb.vect[0] > 0) or (cb.rect.top > SCREEN_HEIGHT): 140 self.cannonballs.remove(cb) 141 self.cannonball_sprites.remove(cb) 142 self.score.update() 143 144 # Add steam particles 145 if Variables.particles: 146 particle_point = self.player.get_point((5.0 + rr() * 9.0, 0)) 147 particle_point[0] += self.player.rect.centerx 148 particle_point[1] += self.player.rect.centery 149 if self.spacepressed and self.t > self.spacepressed + FPS * 3: 150 pass 151 #~ self.particles.add_fire_steam_particle(particle_point) 152 else: 153 self.particles.add_steam_particle(particle_point) 154 155 particle_point = self.player.get_point((19.0 + rr() * 7.0, 5.0)) 156 particle_point[0] += self.player.rect.centerx 157 particle_point[1] += self.player.rect.centery 158 if self.spacepressed and self.t > self.spacepressed + FPS * 3: 159 pass 160 #~ self.particles.add_fire_steam_particle(particle_point) 161 else: 162 self.particles.add_steam_particle(particle_point) 163 164 if self.titanic: 165 for j in range(4): 166 particle_point = self.titanic.get_point((49 + rr() * 9.0 + 28 * j, 25)) 167 particle_point[0] += self.titanic.rect.centerx 168 particle_point[1] += self.titanic.rect.centery 169 self.particles.add_steam_particle(particle_point) 170 171 self.particles.update() 172 173 self.water.update() 174 175 if self.player.splash: 176 if Variables.particles: 177 for i in range(10): 178 r = rr() 179 x = int(r * self.player.rect.left + (1.0-r) * self.player.rect.right) 180 point = (x, self.water.get_water_level(x)) 181 self.particles.add_water_particle(point) 182 183 for powerup in self.powerups: 184 powerup.update() 185 if powerup.picked: 186 self.powerups.remove(powerup) 187 self.powerup_sprites.remove(powerup) 188 189 if not self.gameover: 190 self.check_collisions() 191 192 if self.health.hearts_left == 0 and not self.player.dying: 193 self.player.die() 194 195 if self.player.dying and not self.player.dead: 196 if Variables.particles: 197 self.particles.add_explosion_particle((self.player.rect.centerx, self.player.rect.centery)) 198 self.particles.add_debris_particle((self.player.rect.centerx, self.player.rect.centery)) 199 200 if self.player.dead: 201 #self.done = True 202 self.set_gameover() 203 204 if self.damage_count > 0: 205 self.damage_count -= 1 206 self.lastshot += 1 207 self.t += 1 208 209 self.draw() 210 211 self.handle_events() 212 213 return self.score.get_score() 214 215 def damage_player(self): 216 self.health.damage() 217 for i in range(10): 218 particle_point = self.player.get_point((rr() * 26.0, rr() * 10.0)) 219 particle_point[0] += self.player.rect.centerx 220 particle_point[1] += self.player.rect.centery 221 self.particles.add_debris_particle(particle_point) 222 self.player.blinks+=12 223 224 225 def set_gameover(self, message = "Game Over"): 226 self.gameover = True 227 images = [] 228 height = 0 229 width = 0 230 for text in message.split("\n"): 231 images.append(util.bigfont.render(text, Variables.alpha, (0,0,0))) 232 height += images[-1].get_height() 233 if images[-1].get_width() > width: 234 width = images[-1].get_width() 235 self.gameover_image = pygame.Surface((width, height), SRCALPHA, 32) 236 self.gameover_image.fill((0,0,0,0)) 237 for i in range(len(images)): 238 rect = images[i].get_rect() 239 rect.top = i * images[i].get_height() 240 rect.centerx = width / 2 241 self.gameover_image.blit(images[i], rect) 242 243 self.gameover_rect = self.gameover_image.get_rect() 244 self.gameover_rect.center = self.screen.get_rect().center 245 246 def take_screenshot(self): 247 i = 1 248 filename = "sshot.tga" 249 while os.path.exists(filename): 250 i += 1 251 filename = "sshot" + str(i) + ".tga" 252 253 pygame.image.save(self.screen, filename) 254 print("Screenshot saved as " + filename) 255 256 def handle_events(self): 257 nextframe = False 258 framecount = 0 259 while not nextframe: 260 # wait until there's at least one event in the queue 261 #nextframe = True 262 pygame.event.post(pygame.event.wait()) 263 for event in pygame.event.get(): 264 #event = pygame.event.wait() 265 if event.type == QUIT or \ 266 event.type == KEYDOWN and event.key == K_ESCAPE: 267 self.done = True 268 nextframe = True 269 elif event.type == NEXTFRAME: 270 framecount += 1 271 nextframe = True 272 elif self.gameover: 273 if event.type == JOYBUTTONDOWN: 274 self.done = True 275 nextframe = True 276 elif event.type == KEYDOWN: 277 self.done = True 278 nextframe = True 279 continue 280 elif event.type == JOYAXISMOTION: 281 if event.axis == 0: 282 if event.value < -0.5: 283 self.player.move_left(True) 284 elif event.value > 0.5: 285 self.player.move_right(True) 286 else: 287 self.player.move_left(False) 288 self.player.move_right(False) 289 elif event.type == JOYBUTTONDOWN: 290 if event.button == 0: 291 if not self.pause: 292 self.player.jump() 293 elif event.button == 1: 294 if not self.pause: 295 if self.lastshot > MIN_FIRE_DELAY and not self.player.dying: 296 cb = Cannonball(self.player.rect, self.player.angle) 297 self.cannonballs.append(cb) 298 self.cannonball_sprites.add(cb) 299 particle_point = self.player.get_point((42.0,10.0)) 300 particle_point[0] += self.player.rect.centerx 301 particle_point[1] += self.player.rect.centery 302 for i in range(4): 303 self.particles.add_fire_steam_particle(particle_point) 304 self.lastshot = 0 305 self.spacepressed = self.t 306 elif event.button == 5: 307 self.take_screenshot() 308 elif event.button == 8: 309 self.set_pause() 310 elif event.type == KEYDOWN: 311 if event.key == K_LEFT: 312 self.player.move_left(True) 313 elif event.key == K_RIGHT: 314 self.player.move_right(True) 315 elif event.key == K_SPACE: 316 if not self.pause: 317 # Only 3 cannonballs at once 318 # Maximum firing rate set at the top 319 if self.lastshot > MIN_FIRE_DELAY and not self.player.dying: 320 cb = Cannonball(self.player.rect, self.player.angle) 321 self.cannonballs.append(cb) 322 self.cannonball_sprites.add(cb) 323 particle_point = self.player.get_point((42.0,10.0)) 324 particle_point[0] += self.player.rect.centerx 325 particle_point[1] += self.player.rect.centery 326 for i in range(4): 327 self.particles.add_fire_steam_particle(particle_point) 328 self.lastshot = 0 329 self.spacepressed = self.t 330 elif event.key == K_UP: 331 if not self.pause: 332 self.player.jump() 333 elif event.key == K_s: 334 self.take_screenshot() 335 elif event.key == K_p: 336 self.set_pause() 337 elif event.type == KEYUP: 338 if event.key == K_LEFT: 339 self.player.move_left(False) 340 elif event.key == K_RIGHT: 341 self.player.move_right(False) 342 elif event.key == K_SPACE: 343 if not self.pause: 344 if self.spacepressed and self.t > self.spacepressed + FPS * 3 and not self.player.dying: 345 cb = Cannonball(self.player.rect, self.player.angle, special=True) 346 self.cannonballs.append(cb) 347 self.cannonball_sprites.add(cb) 348 particle_point = self.player.get_point((42.0,10.0)) 349 particle_point[0] += self.player.rect.centerx 350 particle_point[1] += self.player.rect.centery 351 for i in range(30): 352 self.particles.add_fire_steam_particle((particle_point[0]+rrr(-4,4),particle_point[1]+rrr(-3,3))) 353 self.lastshot = 0 354 self.spacepressed = None 355 elif event.type == JOYBUTTONUP: 356 if event.button == 1: 357 if not self.pause: 358 if self.spacepressed and self.t > self.spacepressed + FPS * 3 and not self.player.dying: 359 cb = Cannonball(self.player.rect, self.player.angle, special=True) 360 self.cannonballs.append(cb) 361 self.cannonball_sprites.add(cb) 362 particle_point = self.player.get_point((42.0,10.0)) 363 particle_point[0] += self.player.rect.centerx 364 particle_point[1] += self.player.rect.centery 365 for i in range(30): 366 self.particles.add_fire_steam_particle((particle_point[0]+rrr(-4,4),particle_point[1]+rrr(-3,3))) 367 self.lastshot = 0 368 self.spacepressed = None 369 370 #if framecount > 1: 371 # print str(self.t) + ": missed " + str(framecount - 1) + " frames!" 372 373 def set_pause(self): 374 self.pause = not self.pause 375 376 #if framecount > 1: 377 # print str(self.t) + ": missed " + str(framecount - 1) + " frames!" 378 379 def set_pause(self): 380 self.pause = not self.pause 381 382 def draw(self): 383 self.screen.blit(Game.sky, self.screen.get_rect()) 384 self.health_sprite.draw(self.screen) 385 self.score_sprite.draw(self.screen) 386 self.player_sprite.draw(self.screen) 387 self.powerup_sprites.draw(self.screen) 388 self.pirate_sprites.draw(self.screen) 389 if self.titanic: 390 self.titanic_sprite.draw(self.screen) 391 self.seagull_sprites.draw(self.screen) 392 cloud.draw(self.screen) 393 self.shark_sprites.draw(self.screen) 394 self.mine_sprites.draw(self.screen) 395 self.cannonball_sprites.draw(self.screen) 396 self.water_sprite.draw(self.screen) 397 if Variables.particles: 398 self.particle_sprite.draw(self.screen) 399 400 if self.pause: 401 self.screen.blit(self.pause_image, self.pause_rect) 402 403 if self.gameover: 404 self.screen.blit(self.gameover_image, self.gameover_rect) 405 406 if self.level.t < 120: 407 image = None 408 i = 0 409 if self.level.phase < len(self.level.phase_messages): 410 for text in self.level.phase_messages[self.level.phase].split("\n"): 411 image = util.smallfont.render(text, Variables.alpha, (0,0,0)) 412 rect = image.get_rect() 413 rect.centerx = self.screen.get_rect().centerx 414 rect.top = 100 + rect.height * i 415 blit_image = pygame.Surface((image.get_width(), image.get_height())) 416 blit_image.fill((166,183,250)) 417 blit_image.set_colorkey((166,183,250)) 418 blit_image.blit(image, image.get_rect()) 419 if self.level.t > 60: 420 blit_image.set_alpha(255 - (self.level.t - 60) * 255 / 60) 421 self.screen.blit(blit_image, rect) 422 i += 1 423 424 pygame.display.flip() 425 426 427 428 def check_collisions(self): 429 collisions = PixelPerfect.spritecollide_pp(self.player, self.powerup_sprites, 0) 430 for powerup in collisions: 431 if not powerup.fading: 432 if not self.player.dying: 433 self.health.add() 434 powerup.pickup() 435 436 collisions = PixelPerfect.spritecollide_pp(self.player, self.mine_sprites, 0) 437 438 for mine in collisions: 439 if not mine.exploding: 440 if not self.player.dying: 441 self.damage_player() 442 mine.explode() 443 444 collisions = PixelPerfect.spritecollide_pp(self.player, self.shark_sprites, 0) 445 446 for shark in collisions: 447 if not shark.dying: 448 if not self.player.dying: 449 self.damage_player() 450 shark.die() 451 452 collisions = PixelPerfect.spritecollide_pp(self.player, self.cannonball_sprites, 0) 453 454 for cb in collisions: 455 if not self.player.dying: 456 self.damage_player() 457 self.cannonballs.remove(cb) 458 self.cannonball_sprites.remove(cb) 459 if (Variables.sound): 460 Mine.sound.play() # Umm... the mine has a nice explosion sound. 461 462 collisions = PixelPerfect.groupcollide_pp(self.cannonball_sprites, self.shark_sprites, 0, 0) 463 464 for cb in dict.keys(collisions): 465 for shark in collisions[cb]: 466 # The test on cb.vect is a rude hack preventing cannonballs from pirate ships from killing sharks. 467 if not shark.dying and cb.vect[0] > 0: 468 self.score.add(15) 469 shark.die() 470 # give her a part of ball's momentum: 471 shark.dx+=cb.vect[0]*0.6 472 shark.dy+=cb.vect[1]*0.4 473 if not cb.special: 474 self.cannonballs.remove(cb) 475 self.cannonball_sprites.remove(cb) 476 break 477 478 collisions = PixelPerfect.groupcollide_pp(self.cannonball_sprites, self.seagull_sprites, 0, 0) 479 480 for cb in dict.keys(collisions): 481 for seagull in collisions[cb]: 482 # cb.vect test is a rude hack preventing pirates from killing seagulls 483 if not seagull.dying and cb.vect[0] > 0: 484 self.score.add(75) 485 seagull.die() 486 # give her a part of ball's momentum: 487 seagull.vect[0]+=cb.vect[0]*0.4 488 seagull.vect[1]+=cb.vect[1]*0.4 489 if not cb.special: 490 self.cannonballs.remove(cb) 491 self.cannonball_sprites.remove(cb) 492 break 493 494 collisions = PixelPerfect.groupcollide_pp(self.cannonball_sprites, self.pirate_sprites, 0, 0) 495 496 for cb in dict.keys(collisions): 497 for pirate in collisions[cb]: 498 # cb.vect hack for preventing pirates from killing each other 499 if not pirate.dying and cb.vect[0] > 0: 500 if (Variables.sound): 501 Mine.sound.play() # Umm... the mine has a nice sound. 502 self.score.add(25) 503 pirate.damage() 504 for i in range(6): 505 self.particles.add_wood_particle((pirate.rect.centerx+rrr(-0,15), pirate.rect.centery+rrr(-10,20))) 506 if not cb.special: 507 self.cannonballs.remove(cb) 508 self.cannonball_sprites.remove(cb) 509 break 510 511 if self.titanic: 512 collisions = PixelPerfect.spritecollide_pp(self.titanic, self.cannonball_sprites, 0) 513 for cb in collisions: 514 if not self.titanic.dying and cb.vect[0] > 0: 515 if (Variables.sound): 516 Mine.sound.play() 517 if cb.special: 518 #special round is hard to fire, so lets reward our crafty player 519 self.titanic.damage(12) 520 self.score.add(100) 521 else: 522 self.score.add(7) 523 self.titanic.damage() 524 self.cannonballs.remove(cb) 525 self.cannonball_sprites.remove(cb) 526 break 527 528 def update_enemies(self): 529 self.mine_sprites.update() 530 for mine in self.mines: 531 if mine.exploding: 532 if mine.explode_frames == 0: 533 self.mines.remove(mine) 534 self.mine_sprites.remove(mine) 535 # this should really be done in the Mine class, but oh well, here's some explosion effects: 536 if Variables.particles: 537 self.particles.add_explosion_particle((mine.rect.centerx, mine.rect.top + mine.image.get_rect().centerx)) 538 self.particles.add_debris_particle((mine.rect.centerx, mine.rect.top + mine.image.get_rect().centerx)) 539 if mine.rect.right < self.screen.get_rect().left: 540 self.mines.remove(mine) 541 self.mine_sprites.remove(mine) 542 543 self.shark_sprites.update() 544 for shark in self.sharks: 545 if shark.dying: 546 if Variables.particles: 547 self.particles.add_blood_particle(shark.rect.center) 548 if shark.rect.right < self.screen.get_rect().left or shark.dead: 549 self.sharks.remove(shark) 550 self.shark_sprites.remove(shark) 551 552 self.pirate_sprites.update() 553 for pirate in self.pirates: 554 if pirate.t % 50 == 0 and not pirate.dying: 555 # Pirate shoots, this should probably be handled by the Pirateboat class 556 cb = Cannonball(pirate.rect, pirate.angle, left = True) 557 self.cannonballs.append(cb) 558 self.cannonball_sprites.add(cb) 559 particle_point = pirate.get_point((0.0,10.0)) 560 particle_point[0] += pirate.rect.centerx 561 particle_point[1] += pirate.rect.centery 562 for i in range(4): 563 self.particles.add_fire_steam_particle(particle_point) 564 565 if pirate.rect.right < self.screen.get_rect().left or pirate.dead: 566 self.pirates.remove(pirate) 567 self.pirate_sprites.remove(pirate) 568 elif pirate.dying: 569 if Variables.particles: 570 self.particles.add_explosion_particle((pirate.rect.centerx, pirate.rect.centery)) 571 self.particles.add_wood_particle((pirate.rect.centerx, pirate.rect.centery)) 572 573 if self.titanic: 574 self.titanic.update() 575 if self.titanic.t % 100 == 0 and not self.titanic.dying: 576 for i in range(3): 577 cb = Cannonball(self.titanic.rect, self.titanic.angle + (i-1)*10 - 50, left = True) 578 self.cannonballs.append(cb) 579 self.cannonball_sprites.add(cb) 580 elif self.titanic.t % 100 == 50 and not self.titanic.dying: 581 for i in range(3): 582 cb = Cannonball(self.titanic.rect, self.titanic.angle + (i-1)*10 - 52.5, left = True) 583 self.cannonballs.append(cb) 584 self.cannonball_sprites.add(cb) 585 if self.titanic.dead: 586 self.set_gameover("Congratulations!\nYou sunk Titanic!") 587 self.titanic = None 588 589 self.seagull_sprites.update() 590 for seagull in self.seagulls: 591 if seagull.rect.right < 0 or seagull.dead: 592 self.seagulls.remove(seagull) 593 self.seagull_sprites.remove(seagull) 594 595 def spawn_enemies(self): 596 spawns = self.level.get_spawns() 597 if spawns[Level.SHARKS]: 598 # Make a new shark 599 self.sharks.append(Shark()) 600 self.shark_sprites.add(self.sharks[-1]) 601 602 if spawns[Level.PIRATES]: 603 # Make a new pirate ship 604 self.pirates.append(Pirateboat()) 605 self.pirate_sprites.add(self.pirates[-1]) 606 607 if spawns[Level.MINES]: 608 self.mines.append(Mine()) 609 self.mine_sprites.add(self.mines[-1]) 610 611 if spawns[Level.SEAGULLS]: 612 self.seagulls.append(Seagull()) 613 self.seagull_sprites.add(self.seagulls[-1]) 614 615 if spawns[Level.TITANIC]: 616 self.titanic = Titanic() 617 self.titanic_sprite.add(self.titanic) 618 619 if spawns[Level.POWERUPS]: 620 self.powerups.append(Powerup()) 621 self.powerup_sprites.add(self.powerups[-1]) 622 623