from math import sin, cos, radians, degrees, atan2
import os
import random
import pygame
import pygame.font
##################################################################
#玩家設置
class Player(object):
# 初始化資料
def __init__(self):
#self.rect 為玩家本身的圖塊
self.rect = pygame.Rect(32, 32, 16, 16) #玩家圖格大小
def move(self, dx, dy):
# 確保在單一軸上移動. 兩個if是為了同時檢查兩者
if dx != 0:
self.move_single_axis(dx, 0)
if dy != 0:
self.move_single_axis(0, dy)
def move_single_axis(self, dx, dy): #設定函數:在單一軸上移動
# 移動單位
self.rect.x += dx
self.rect.y += dy
# 如果你碰到了牆壁,玩家的圖格會被卡住(讓你不要跨越牆壁)
for wall in walls:
if self.rect.colliderect(wall.rect): #如果玩家撞到了牆壁
if dx > 0: # 當你撞到左邊的牆壁,使你的圖格右邊變成牆壁的左邊。
self.rect.right = wall.rect.left
if dx < 0: # 當你撞到右邊的牆壁,使你的圖格左邊變成牆壁的右邊。
self.rect.left = wall.rect.right
if dy > 0: # 當你撞到上方的牆壁,使你的圖格下邊變成牆壁的上邊。
self.rect.bottom = wall.rect.top
if dy < 0: # 當你撞到下方的牆壁,使你的圖格上邊變成牆壁的下邊。
self.rect.top = wall.rect.bottom
#第一部分牆壁設置
class Wall(object):
# 初始化資料
def __init__(self, pos):
walls.append(self)
self.rect = pygame.Rect(pos[0], pos[1], 16, 16)
#第一部分怪物設置
class Monster(object):
# 初始化資料
def __init__(self, pos):
monsters.append(self)
self.rect = pygame.Rect(pos[0], pos[1], 16, 16)
#第一部分通關門設置
class Winblock(object):
# 初始化資料
def __init__(self):
self.rect = pygame.Rect(384, 384, 16, 32)
##############################################################
##################################################################
#第二部分射擊器設置
class Shooter(object):
# 初始化資料
def __init__(self):
self.rect = pygame.Rect(376, 600, 16, 16)
self.bullets = []
self.direction = radians(3.14*1.5)
# 如果沒有子彈,就建立新子彈
def shoot(self):
if not self.bullets:
shooter.bullets.append(Bullet(self.rect.center, self.direction)) # 建立新的子彈
global bullet_count
bullet_count -= 1
global all_bullets
all_bullets += 1
# 變更射擊器角度
def change_direction(self, angle):
self.direction = radians(angle)
#第二部分計量條設置
class Square(object):
# 初始化資料
def __init__(self):
self.rect = pygame.Rect(376, 704, 16, 16)
#第二部分子彈設置
class Bullet(object):
# 初始化資料
def __init__(self, pos, angle):
self.rect = pygame.Rect(pos[0]-4, pos[1]-4, 16, 16) # 建立子彈的矩形
self.speed = 10 # 子彈的速度
self.angle = angle # 子彈的飛行角度
def update(self):
# 子彈的移動
self.rect.x += self.speed * cos(self.angle)
self.rect.y += self.speed * sin(self.angle)
# 如果子彈撞到屏障,消除子彈
for barrier in barriers:
if self.rect.colliderect(barrier.rect):
shooter.bullets.remove(self)
return
# 如果子彈碰到BOSS,消除BOSS並重新創建BOSS
for boss in bosses:
if self.rect.colliderect(boss.rect):
bosses.remove(boss)
boss = Boss()
global Boss_HP
Boss_HP -= 1
shooter.bullets.remove(self)
return
#第二部分屏障設置
class Barrier(object): #地圖設置
# 初始化資料
def __init__(self, pos):
barriers.append(self)
self.rect = pygame.Rect(pos[0], pos[1], 16, 16)
#第二部分怪物設置
class Boss(object):
# 初始化資料
def __init__(self):
bosses.append(self)
self.rect = pygame.Rect(random.randint(100,600), 150, 100, 100)
##################################################################
#初始化pygame
os.environ["SDL_VIDEO_CENTERED"] = "1" #設置pygame視窗居中顯示
pygame.init()
# 設置地圖的視窗大小
pygame.display.set_caption("Gotcha")
screen = pygame.display.set_mode((1024, 768))
screen_rect = screen.get_rect()
clock = pygame.time.Clock()
#設置字體
font = pygame.font.Font(None,50)
font2 = pygame.font.Font(None,100)
##################################################################
# 右邊螢幕資訊與結束畫面資訊
monster_number = int(3)
Win_number = int(0)
Fail_number =int(0)
bullet_count = int()
Boss_HP = int()
all_bullets =int()
#第一部分的元素
walls = [] # 保存牆壁的陣列
monsters = [] #保存怪物的陣列
player = Player() # 創建玩家
############################
#第二部分的元素
square_speed_x = 3
angle = float(270)
angle_change = float(1.46)
barriers = [] # 保存屏障的陣列
bosses = [] #保存怪物的陣列
square = Square() #創建計量條
shooter = Shooter() #創建發射器
boss = Boss() #創建怪物
##################################################################
# 將地圖資訊以字串保存在level中
#第一部分地圖設置
level1 = [
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W D W",
"W WWW WPW W",
"W WPPPMAAAAAAAWPW W",
"W WPWWAAAAAAAAAWPW W",
"W WPWAAAAAAAAAAWPW W",
"W WPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"W WPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"W WPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"W WPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAAWPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAAWPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAAWPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAAWPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAWPPWAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAWWWWWWWWWPWAAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WWWWWWWPPPPPPPPWAAAAAAAAAAAAWPWAAAAAAAAAAAAAAAAW",
"PPPPPPPPPWWWWWWPWAAAAAAAAAAAWPWAAAAAAAAAAAAAAAAW",
"WWWWWWWWWAAAAWPWAAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAAAAAAAWPWAAAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAWWMWAAAWPPPWAAAAAAAAAWPWAAAAAAAAAAAAAAAAAW",
"WAAAAAAWPPWAAAAWPWAAAAAAAAAWPWWAAAAAAAAAAAAAAAAW",
"WAAAAAAAWPWAAAAWPWAAAAAAAAWPPPWWAAAAAAAAAAAAAAAW",
"WAAAAAAAWPWAAAAWPWAAAAAAAAWPWWPPWAAAAAAAAAAAAAAW",
"WAAAAAAAWPWAAAAWPWAAAAAAAAWPWAWPPWWWAAAAAAAAAAAW",
"WAAAAAAAWPWAAAAWPWAAAAAAAAWPWAAWPPPPWWWWMAAAAAAW",
"WAAAAAAAWPWWWWWWPWWWWWWWWWWPWAAAWWWPPPPPPWAAAAAW",
"WAAAAAAAWPPPPPPPPPPPPPPPPPPPWAAAAAAAWWWWWWAAAAAW",
"WAAAAAAAWWWWWWWWWWWWWWWWWWWAAAAAAAAAAAAAAAAAAAAW",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
]
# 將level中的文字縮寫. W = 牆壁, M = 怪物
x = y = 0
for row in level1:
for col in row:
if col == "W":
Wall((x, y)) #帶入上面的class Wall
if col == "M":
Monster((x, y)) #設置怪物的圖格
x += 16
y += 16
x = 0
##################################################################
#第二部分地圖
level2 = [
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W W",
"W WWWWWWWWWWWWWWWWWWWWWWWWWW W",
"W W W W",
"W WWWWWWWWWWWWWWWWWWWWWWWWWW W",
"W W",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
]
# 將level中的文字縮寫. W = 牆壁 = Barrier, B = 怪物
x = y = 0
for row in level2:
for col in row:
if col == "W":
Barrier((x, y)) #帶入上面的class barrier
if col == "B":
Boss((x, y)) #設置怪物的圖格
x += 16
y += 16
x = 0
##################################################################
#遊戲執行
running = True
#設置第一畫面到第三畫面的背景
first_surface = pygame.Surface(screen.get_size())
second_surface =pygame.Surface(screen.get_size())
third_surface = pygame.Surface(screen.get_size())
first_surface.fill((0, 0, 0))
second_surface.fill((0, 0, 0))
third_surface.fill((0, 0, 0))
current_surface = first_surface
while running:
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE:
running = False
########################################################################################
# 第一部分程式
# 進入第一部分時,重置第二部分的資料
if current_surface == first_surface:
bullet_count = int(10) #設定子彈數量
Boss_HP = random.randint(1, 3) #設定怪物血量
# 如果玩家按下方向鍵,就使玩家移動
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
player.move(-2, 0)
if key[pygame.K_RIGHT]:
player.move(2, 0)
if key[pygame.K_UP]:
player.move(0, -2)
if key[pygame.K_DOWN]:
player.move(0, 2)
# 如果玩家碰撞怪物,消除怪物並減少怪物數量,同時進入第二部分
for monster in monsters:
if player.rect.colliderect(monster.rect):
monsters.remove(monster)
monster_number -= 1
current_surface = second_surface
first_surface.fill((0, 0, 0)) #將背景塗成黑色
for wall in walls:
pygame.draw.rect(first_surface, (255, 255, 255), wall.rect) #為牆壁塗上顏色
for monster in monsters:
pygame.draw.rect(first_surface, (255, 0, 0), monster.rect) # 為怪物塗上顏色
pygame.draw.rect(first_surface, (255, 200, 0), player.rect) #為玩家塗上顏色
#第一部分文本設置
text_monster = font.render("Monsters: {}".format(monster_number), True, (255, 255, 255))
first_surface.blit(text_monster, (800, 200))
text_Win = font.render("Win: {}".format(Win_number), True, (255, 255, 255))
first_surface.blit(text_Win, (820, 300))
text_Fail = font.render("Fail: {}".format(Fail_number), True, (255, 255, 255))
first_surface.blit(text_Fail, (820, 400))
#如果清除怪物達X隻,將文本顯示並建立通關門
if Win_number >= 2:
winblock = Winblock()
pygame.draw.rect(first_surface, (255, 255, 255), (winblock.rect.x, winblock.rect.y, 16 ,32 ),5)
text_Door1 = font.render(("The door is"), True, (255, 255, 255))
first_surface.blit(text_Door1, (800, 500))
text_Door2 = font.render(("OPEN!!!!!!!"), True, (255, 255, 255))
first_surface.blit(text_Door2, (800, 550))
text_go = font.render(("You can leave"), True, (255, 255, 255))
first_surface.blit(text_go, (780, 600))
text_fight = font.render(("or fighting"), True, (255, 255, 255))
first_surface.blit(text_fight, (800, 650))
# 如過碰到通關門,進入結束畫面
if player.rect.colliderect(winblock.rect):
current_surface = third_surface
########################################################################################
# 第二部分程式
elif current_surface == second_surface:
square.rect.x -= square_speed_x
for barrier in barriers:
if square.rect.colliderect(barrier.rect):
square_speed_x *= -1 # 如果量條的方塊撞到了牆壁
key = pygame.key.get_pressed()
# 如果王的血量歸零或是子彈歸零,就無法射擊
if not Boss_HP ==0:
if not bullet_count ==0:
if key[pygame.K_SPACE]:
shooter.shoot()
#控制發射器的角度,使隨時間變化
angle -= angle_change
if angle < 180:
angle_change *= -1
elif angle > 360:
angle_change *= -1
shooter.change_direction(angle)
second_surface.fill((0, 0, 0)) # 將背景塗成黑色
for barrier in barriers:
pygame.draw.rect(second_surface, (255, 255, 255), barrier.rect) # 為牆壁塗上顏色
for boss in bosses:
pygame.draw.rect(second_surface, (255, 0, 0), boss.rect) # 為怪物塗上顏色
pygame.draw.circle(second_surface, (255, 255, 0), (shooter.rect.x, shooter.rect.y), 16, 0)
pygame.draw.rect(second_surface, (255, 0, 255), square.rect)
pygame.draw.rect(first_surface, (255, 200, 0), player.rect) # 為玩家塗上顏色
#第二部分文本設置
text_Boss_HP = font.render("Boss HP: {}".format(Boss_HP), True, (255, 255, 255))
second_surface.blit(text_Boss_HP, (800, 200))
text_bullets = font.render("bullets: {}".format(bullet_count), True, (255, 255, 255))
second_surface.blit(text_bullets, (800, 300))
#如果怪物血量歸零,清除怪物並顯示文本
if Boss_HP == 0:
for boss in bosses:
bosses.remove(boss)
text_PASS = font2.render(("PASS"), True, (255, 255, 255))
second_surface.blit(text_PASS, (290, 300))
text_Next = font.render("press c to continue", True, (255, 255, 255))
second_surface.blit(text_Next, (220, 400))
#按下C回到第一部分
if key[pygame.K_c]:
current_surface = first_surface
Boss()
Win_number += 1
#如果子彈歸零,清除怪物並顯示文本
if bullet_count == 0:
for boss in bosses:
bosses.remove(boss)
text_FAIL = font2.render(("FAIL"), True, (255, 255, 255))
second_surface.blit(text_FAIL, (290, 300))
text_Next = font.render("press c to continue", True, (255, 255, 255))
second_surface.blit(text_Next, (210, 400))
if key[pygame.K_c]:
current_surface = first_surface
Boss()
Fail_number +=1
#繪畫子彈
for bullet in shooter.bullets:
bullet.update()
pygame.draw.circle(second_surface, (255, 255, 0), (bullet.rect.x, bullet.rect.y), 16, 0)
########################################################################################
# 結束畫面
else:
text_congratulation = font2.render(("congratulation"), True, (255, 255, 255))
third_surface.blit(text_congratulation, (270, 250))
text_kill_monster = font.render("Kill Monster: {}".format(Win_number), True, (255, 255, 255))
third_surface.blit(text_kill_monster, (290, 400))
text_escape_monster = font.render("Escape Monster: {}".format(Fail_number), True, (255, 255, 255))
third_surface.blit(text_escape_monster, (290, 500))
text_All_bullet = font.render("Bullets use: {}".format(all_bullets), True, (255, 255, 255))
third_surface.blit(text_All_bullet, (290, 600))
screen.blit((current_surface), (0, 0))
pygame.display.flip() #畫面更新
clock.tick(60)
pygame.quit()