diff --git a/Sprites.py b/Sprites.py new file mode 100644 index 0000000..aa725ff --- /dev/null +++ b/Sprites.py @@ -0,0 +1,75 @@ +#Function:定义一些精灵类 +import random +import pygame + +'''墙类''' +class Wall(pygame.sprite.Sprite): + def __init__(self, x, y, width, height, color, **kwargs): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface([width, height]) + self.image.fill(color) + self.rect = self.image.get_rect() + self.rect.left = x + self.rect.top = y + +'''食物类''' +class Food(pygame.sprite.Sprite): + def __init__(self, x, y, width, height, color, bg_color, **kwargs): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface([width, height]) + self.image.fill(bg_color) + self.image.set_colorkey(bg_color) + pygame.draw.ellipse(self.image, color, [0, 0, width, height]) + self.rect = self.image.get_rect() + self.rect.left = x + self.rect.top = y + +'''角色类''' +class Player(pygame.sprite.Sprite): + def __init__(self, x, y, role_image_path): + pygame.sprite.Sprite.__init__(self) + self.role_name = role_image_path.split('/')[-1].split('.')[0] + self.base_image = pygame.image.load(role_image_path).convert() + self.image = self.base_image.copy() + self.rect = self.image.get_rect() + self.rect.left = x + self.rect.top = y + self.prev_x = x + self.prev_y = y + self.base_speed = [30, 30] + self.speed = [0, 0] + self.is_move = False + self.tracks = [] + self.tracks_loc = [0, 0] + '''改变速度方向''' + def changeSpeed(self, direction): + if direction[0] < 0: + self.image = pygame.transform.flip(self.base_image, True, False) + elif direction[0] > 0: + self.image = self.base_image.copy() + elif direction[1] < 0: + self.image = pygame.transform.rotate(self.base_image, 90) + elif direction[1] > 0: + self.image = pygame.transform.rotate(self.base_image, -90) + self.speed = [direction[0] * self.base_speed[0], direction[1] * self.base_speed[1]] + return self.speed + '''更新角色位置''' + def update(self, wall_sprites, gate_sprites): + if not self.is_move: + return False + x_prev = self.rect.left + y_prev = self.rect.top + self.rect.left += self.speed[0] + self.rect.top += self.speed[1] + is_collide = pygame.sprite.spritecollide(self, wall_sprites, False) + if gate_sprites is not None: + if not is_collide: + is_collide = pygame.sprite.spritecollide(self, gate_sprites, False) + if is_collide: + self.rect.left = x_prev + self.rect.top = y_prev + return False + return True + '''生成随机的方向''' + def randomDirection(self): + return random.choice([[-0.5, 0], [0.5, 0], [0, 0.5], [0, -0.5]]) \ No newline at end of file diff --git a/__pycache__/Levels.cpython-311.pyc b/__pycache__/Levels.cpython-311.pyc new file mode 100644 index 0000000..3b08670 Binary files /dev/null and b/__pycache__/Levels.cpython-311.pyc differ diff --git a/__pycache__/Levels.cpython-36.pyc b/__pycache__/Levels.cpython-36.pyc new file mode 100644 index 0000000..4d5ee04 Binary files /dev/null and b/__pycache__/Levels.cpython-36.pyc differ diff --git a/__pycache__/Sprites.cpython-311.pyc b/__pycache__/Sprites.cpython-311.pyc new file mode 100644 index 0000000..cfa24ca Binary files /dev/null and b/__pycache__/Sprites.cpython-311.pyc differ diff --git a/__pycache__/Sprites.cpython-36.pyc b/__pycache__/Sprites.cpython-36.pyc new file mode 100644 index 0000000..4e99ed2 Binary files /dev/null and b/__pycache__/Sprites.cpython-36.pyc differ diff --git a/__pycache__/login.cpython-311.pyc b/__pycache__/login.cpython-311.pyc new file mode 100644 index 0000000..46f6793 Binary files /dev/null and b/__pycache__/login.cpython-311.pyc differ diff --git a/__pycache__/main.cpython-311.pyc b/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..d48058c Binary files /dev/null and b/__pycache__/main.cpython-311.pyc differ diff --git a/login.py b/login.py new file mode 100644 index 0000000..2cad680 --- /dev/null +++ b/login.py @@ -0,0 +1,118 @@ +import tkinter as tk #标准GUI库 +from tkinter import messagebox #显示消息框 +from PIL import ImageTk #显示图像 + +# 存储注册成功用户名及密码 +success = [] + +# 主窗口 +window = tk.Tk() +window.title("Please Log In") +window.geometry("900x660") + +# 背景画布 +canvas = tk.Canvas(window,width=900,height=500) +image_file = ImageTk.PhotoImage(file="resources/title2.jpg") +image = canvas.create_image(0,0,anchor="nw",image=image_file) +canvas.pack() + +# 用户名,用户密码文本 +name_lable = tk.Label(window,text="UserName:",font=(15)) +password_lable = tk.Label(window,text="Password:",font=(15)) +name_lable.place(x=300,y=510) +password_lable.place(x=300,y=550) + +# 用户名,用户密码输入框 +nameval = tk.StringVar() +passwordval = tk.StringVar() +name_entry = tk.Entry(window,textvariable=nameval,font=(12)) +password_entry = tk.Entry(window,textvariable=passwordval,show="*",font=(12)) +name_entry.place(x=400,y=515) +password_entry.place(x=400,y=555) + +# 登录按钮触发函数 +def sign_in_f(): + user_si_name = name_entry.get() + user_si_pass = password_entry.get() + if user_si_name in success: + i = success.index(user_si_name) + if success[i+1] == user_si_pass: + start_game() + else: + tk.messagebox.showinfo(title="登录提示",message="密码错误") + else: + result = tk.messagebox.askquestion(title="登录提示",message="用户名不存在,是否立即注册?") + if result == "yes": + sign_up_f() + else: + pass + +def start_game(): + # 导入游戏主界面 + import main + # 关闭登录界面 + window.destroy() + # 显示游戏主界面 + main.login() + +# 注册按钮触发函数 +def sign_up_f(): + # 用户注册界面 + singn_up_w = tk.Tk() + singn_up_w.title("用户注册") + singn_up_w.geometry("600x400") + + # 拥护注册 用户名,密码,确认密码文本 + su_name_lable = tk.Label(singn_up_w,text="UserName:",font=(12)) + su_pass_lable = tk.Label(singn_up_w,text="Password:",font=(12)) + su_cpass_lable = tk.Label(singn_up_w,text="Confirm Password:",font=(12)) + su_name_lable.place(x=95,y=50) + su_pass_lable.place(x=95,y=150) + su_cpass_lable.place(x=95,y=250) + + # 用户注册 用户名,密码,确认密码输入框 + su_name_val = tk.StringVar() + su_pass_val = tk.StringVar() + su_cpass_val = tk.StringVar() + su_name_entry = tk.Entry(singn_up_w,textvariable=su_name_val,width=20,font=(12)) + su_pass_entry = tk.Entry(singn_up_w,textvariable=su_pass_val,width=20,show="*",font=(12)) + su_cpass_entry = tk.Entry(singn_up_w,textvariable=su_cpass_val,width=20,show="*",font=(12)) + su_name_entry.place(x=270,y=50) + su_pass_entry.place(x=270,y=150) + su_cpass_entry.place(x=270,y=250) + + # 用户在注册页面点击注册按钮触发的函数 + def su_conf_b(): + su_username = su_name_entry.get() + su_userpass = su_pass_entry.get() + su_usercpass = su_cpass_entry.get() + if su_userpass == su_usercpass: + tk.messagebox.showinfo(title="注册提示",message="注册成功,请登录") + success.append(su_username) + success.append(su_userpass) + singn_up_w.destroy() + else: + tk.messagebox.showinfo(title="注册提示",message="两次输入的密码不同,请重新输入") + + # 用户在注册页面点击取消按钮触发的函数 + def su_cancel_b(): + result = tk.messagebox.askquestion(title="放弃注册",message="你真的要放弃注册吗?") + if result == "yes": + singn_up_w.destroy() + else: + pass + + # 用户注册 注册,取消按钮 + su_confirm_button = tk.Button(singn_up_w,text="Confirm",command=su_conf_b) + su_cancle_button = tk.Button(singn_up_w,text="Cancel",command=su_cancel_b) + su_confirm_button.place(x=170,y=330) + su_cancle_button.place(x=370,y=330) + +# 登录,注册按钮 +sign_in_button = tk.Button(window,text="吃豆启动!",command=sign_in_f) +sign_up_button = tk.Button(window,text="注册",command=sign_up_f) +sign_in_button.place(x=350,y=600) +sign_up_button.place(x=470,y=600) + + +window.mainloop() diff --git a/main.py b/main.py new file mode 100644 index 0000000..22c5312 --- /dev/null +++ b/main.py @@ -0,0 +1,187 @@ +# Function:吃豆人小游戏 +import os #用于获取当前目录、更改目录、创建文件和目录等 +import sys #提供了有关 Python 解释器和系统的信息 +import pygame #用于创建游戏窗口、加载图像、播放声音等 +import Levels #模块包含游戏关卡的信息,例如关卡的地图、敌人的位置等 +import login +#定义一些必要的参数,每个变量代表一个颜色的RGB值 +BLACK = (0, 0, 0) +WHITE = (255, 255, 255) +BLUE = (0, 0, 255) +GREEN = (0, 255, 0) +RED = (255, 0, 0) +YELLOW = (255, 255, 0) +PURPLE = (255, 0, 255) +SKYBLUE = (0, 191, 255) +#os.path.join:将多个路径片段连接成一个完整路径 +#os.getcwd():获取当前工作目录 +BGMPATH = os.path.join(os.getcwd(), 'resources/sounds/bg.mp3') #背景音乐 +ICONPATH = os.path.join(os.getcwd(), 'resources/images/icon.png') #背景图 +FONTPATH = os.path.join(os.getcwd(), 'resources/font/ALGER.TTF') #truetype字体文件 +HEROPATH = os.path.join(os.getcwd(), 'resources/images/pacman.png') #吃豆人形象 +BlinkyPATH = os.path.join(os.getcwd(), 'resources/images/Blinky.png') #怪物形象 +ClydePATH = os.path.join(os.getcwd(), 'resources/images/Clyde.png') +InkyPATH = os.path.join(os.getcwd(), 'resources/images/Inky.png') +PinkyPATH = os.path.join(os.getcwd(), 'resources/images/Pinky.png') + +'''开始某一关游戏''' +def startLevelGame(level, screen, font): + clock = pygame.time.Clock() + SCORE = 0 + wall_sprites = level.setupWalls(SKYBLUE) #从levels读取墙壁 + gate_sprites = level.setupGate(WHITE) #门... + hero_sprites, ghost_sprites = level.setupPlayers(HEROPATH, [BlinkyPATH, ClydePATH, InkyPATH, PinkyPATH]) + food_sprites = level.setupFood(YELLOW, WHITE) + is_clearance = False #设置关卡通关标志为否 + while True: #监听方向键,更新玩家移动速度和方向 + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() #关闭pygame + sys.exit() #退出程序 + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_LEFT: + for hero in hero_sprites: + hero.changeSpeed([-1, 0]) + hero.is_move = True + elif event.key == pygame.K_RIGHT: + for hero in hero_sprites: + hero.changeSpeed([1, 0]) + hero.is_move = True + elif event.key == pygame.K_UP: + for hero in hero_sprites: + hero.changeSpeed([0, -1]) + hero.is_move = True + elif event.key == pygame.K_DOWN: + for hero in hero_sprites: + hero.changeSpeed([0, 1]) + hero.is_move = True + if event.type == pygame.KEYUP: + if (event.key == pygame.K_LEFT) or (event.key == pygame.K_RIGHT) or (event.key == pygame.K_UP) or (event.key == pygame.K_DOWN): + hero.is_move = False + screen.fill(BLACK) #清空屏幕并填充黑色背景 + for hero in hero_sprites: + hero.update(wall_sprites, gate_sprites) + hero_sprites.draw(screen) + for hero in hero_sprites: + food_eaten = pygame.sprite.spritecollide(hero, food_sprites, True) + SCORE += len(food_eaten) #检测吃豆子并更新得分 + wall_sprites.draw(screen) + gate_sprites.draw(screen) + food_sprites.draw(screen) + for ghost in ghost_sprites: + # 幽灵随机运动(效果不好且有BUG) + ''' + res = ghost.update(wall_sprites, None) + while not res: + ghost.changeSpeed(ghost.randomDirection()) + res = ghost.update(wall_sprites, None) + ''' + # 指定幽灵运动路径 + if ghost.tracks_loc[1] < ghost.tracks[ghost.tracks_loc[0]][2]: + ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2]) + ghost.tracks_loc[1] += 1 + else: + if ghost.tracks_loc[0] < len(ghost.tracks) - 1: + ghost.tracks_loc[0] += 1 + elif ghost.role_name == 'Clyde': + ghost.tracks_loc[0] = 2 + else: + ghost.tracks_loc[0] = 0 + ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2]) + ghost.tracks_loc[1] = 0 + if ghost.tracks_loc[1] < ghost.tracks[ghost.tracks_loc[0]][2]: + ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2]) + else: + if ghost.tracks_loc[0] < len(ghost.tracks) - 1: + loc0 = ghost.tracks_loc[0] + 1 + elif ghost.role_name == 'Clyde': + loc0 = 2 + else: + loc0 = 0 + ghost.changeSpeed(ghost.tracks[loc0][0: 2]) + ghost.update(wall_sprites, None) + ghost_sprites.draw(screen) + score_text = font.render("Score: %s" % SCORE, True, RED) + screen.blit(score_text, [10, 10]) + if len(food_sprites) == 0: + is_clearance = True #豆子吃完,游戏通关 + break + if pygame.sprite.groupcollide(hero_sprites, ghost_sprites, False, False): + is_clearance = False #玩家撞到幽灵,游戏结束 + break + pygame.display.flip() + clock.tick(10) + return is_clearance + +'''显示文字''' +def showText(screen, font, is_clearance, flag=False): + clock = pygame.time.Clock() + msg = 'Game Over!' if not is_clearance else 'Congratulations, you won!' + positions = [[235, 233], [65, 303], [170, 333]] if not is_clearance else [[145, 233], [65, 303], [170, 333]] + surface = pygame.Surface((400, 200)) #创建一个透明的surface稍微遮挡后面的背景 + surface.set_alpha(10) + surface.fill((128, 128, 128)) + screen.blit(surface, (100, 200)) + texts = [font.render(msg, True, WHITE), + font.render('Press ENTER to continue or play again.', True, WHITE), + font.render('Press ESCAPE to quit.', True, WHITE)] + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + pygame.quit() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_RETURN: + if is_clearance: + if not flag: + return + else: + main(initialize()) + else: + main(initialize()) + elif event.key == pygame.K_ESCAPE: + sys.exit() + pygame.quit() + for idx, (text, position) in enumerate(zip(texts, positions)): + screen.blit(text, position) + pygame.display.flip() + clock.tick(10) + +'''初始化''' +def initialize(): + pygame.init() + icon_image = pygame.image.load(ICONPATH) + pygame.display.set_icon(icon_image) + screen = pygame.display.set_mode([606, 606]) + pygame.display.set_caption('吃豆人') + return screen + +def login(): + # 导入登录界面 + import login + # 显示登录界面 + login.window.mainloop() + +'''主函数''' +def main(screen): + pygame.mixer.init() + pygame.mixer.music.load(BGMPATH) + pygame.mixer.music.play(-1, 0.0) + pygame.font.init() + font_small = pygame.font.Font(FONTPATH, 18) + font_big = pygame.font.Font(FONTPATH, 24) + for num_level in range(1, Levels.NUMLEVELS+1): + if num_level == 1: + level = Levels.Level1() + is_clearance = startLevelGame(level, screen, font_small) + if num_level == Levels.NUMLEVELS: + showText(screen, font_big, is_clearance, True) + else: + showText(screen, font_big, is_clearance) + +'''test''' +if __name__ == '__main__': + main(initialize()) + login() + if is_login_success: # type: ignore + main() \ No newline at end of file diff --git a/resources/Plan.txt b/resources/Plan.txt new file mode 100644 index 0000000..56ba536 --- /dev/null +++ b/resources/Plan.txt @@ -0,0 +1,4 @@ +第一周(4):确定课题,了解课题所要用的第三方库 +第二周(5):设计登录界面,将登录界面连接到游戏 +第三周(6):了解游戏各个部分分别代表什么含义,实现了什么功能 +第四周(7):尝试解决游戏代码中的bug,完善游戏功能(边界,障碍物,怪物出现随机、路线随机) diff --git a/resources/font/ALGER.TTF b/resources/font/ALGER.TTF new file mode 100644 index 0000000..dcc72ae Binary files /dev/null and b/resources/font/ALGER.TTF differ diff --git a/resources/images/Blinky.png b/resources/images/Blinky.png new file mode 100644 index 0000000..5c5ea84 Binary files /dev/null and b/resources/images/Blinky.png differ diff --git a/resources/images/Clyde.png b/resources/images/Clyde.png new file mode 100644 index 0000000..8db5a0a Binary files /dev/null and b/resources/images/Clyde.png differ diff --git a/resources/images/Inky.png b/resources/images/Inky.png new file mode 100644 index 0000000..c633636 Binary files /dev/null and b/resources/images/Inky.png differ diff --git a/resources/images/Pinky.png b/resources/images/Pinky.png new file mode 100644 index 0000000..9614f58 Binary files /dev/null and b/resources/images/Pinky.png differ diff --git a/resources/images/icon.png b/resources/images/icon.png new file mode 100644 index 0000000..39fe4d3 Binary files /dev/null and b/resources/images/icon.png differ diff --git a/resources/images/pacman.png b/resources/images/pacman.png new file mode 100644 index 0000000..36c612e Binary files /dev/null and b/resources/images/pacman.png differ diff --git a/resources/sounds/bg.mp3 b/resources/sounds/bg.mp3 new file mode 100644 index 0000000..487843e Binary files /dev/null and b/resources/sounds/bg.mp3 differ diff --git a/resources/title2.jpg b/resources/title2.jpg new file mode 100644 index 0000000..f24114d Binary files /dev/null and b/resources/title2.jpg differ diff --git a/work one.py b/work one.py new file mode 100644 index 0000000..312e098 --- /dev/null +++ b/work one.py @@ -0,0 +1,70 @@ +import pygame +import random + +# 初始化Pygame库 +pygame.init() + +# 游戏窗口的宽度和高度 +width = 800 +height = 600 + +# 创建游戏窗口 +window = pygame.display.set_mode((width, height)) +pygame.display.set_caption("吃豆") #游戏窗口标题 + +# 定义各种颜色 +black = (0, 0, 0) +white = (255, 255, 255) +yellow = (255, 255, 0) +red = (255, 0, 0) + +# 定义吃豆人的初始位置和速度 +pacman_x = width // 2 +pacman_y = height // 2 +pacman_speed = 5 + +# 定义豆子的数量和大小 +dot_size = 10 +dot_count = 100 + +# 创建豆子的列表 +dots = [] +for i in range(dot_count): + dot_x = random.randint(0, width - dot_size) + dot_y = random.randint(0, height - dot_size) + dots.append((dot_x, dot_y)) + +# 游戏主循环 +running = True +while running: + # 处理事件 + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # 获取按键状态 + keys = pygame.key.get_pressed() + if keys[pygame.K_LEFT]: + pacman_x -= pacman_speed + if keys[pygame.K_RIGHT]: + pacman_x += pacman_speed + if keys[pygame.K_UP]: + pacman_y -= pacman_speed + if keys[pygame.K_DOWN]: + pacman_y += pacman_speed + + # 碰撞检测 + for dot in dots: + dot_x, dot_y = dot #将(x,y)坐标解包到单独的变量 + if pacman_x < dot_x + dot_size and pacman_x + dot_size > dot_x and pacman_y < dot_y + dot_size and pacman_y + dot_size > dot_y: + dots.remove(dot) + + # 渲染画面 + window.fill(black) + pygame.draw.circle(window, yellow, (pacman_x, pacman_y), 20) + for dot in dots: + pygame.draw.rect(window, white, (dot[0], dot[1], dot_size, dot_size)) + pygame.display.flip() + +# 退出游戏 +pygame.quit() \ No newline at end of file