diff --git a/#CS2101009.md b/#CS2101009.md new file mode 100644 index 0000000000000000000000000000000000000000..c2730bfa5afff3a47873cbfa92a14fc60751fe02 --- /dev/null +++ b/#CS2101009.md @@ -0,0 +1,35 @@ +复活功能 +开发者:王亚雪 +1、设计目的:增加游戏的可玩性。 +2、设计思路:当血条为“0”时蛇死亡游戏结束,故通过更改血量从而获得复活。故而增加获得复活机会的提示文件,当玩家连续通过五关及以上获得一次复活机会,使用复活机会之后将重新记录通过关卡数。 +3、最终运行效果:请在游戏中详细体验 + +计时功能 +开发者:刘佳越 +1.设计目的:让玩家清楚地看到玩游戏的时间 +2.设计思路:进入游戏时得到一个初始时间,随后每次更新都得到当前时间,用当前时间减去初试时间得到游戏的时间,并显示在游戏界面左上角 +3.最终运行效果: + +多语言对话 +开发者:杨盼 +1.设计目的:让不同语种的人能够能好的知道游戏规则,提高玩家游戏体验 +2.设计思路:让玩家选择语种之后进入游戏,对话的语种按照玩家的选择来呈现 +3.最终运行效果: +![输入图片说明](img/AK%5DMA8MOK(~E@(%7BA_40P@VX.jpg) +![输入图片说明](img/ALE2%25IQ3_2M07_ZBO(G8HBJ.png) + +统计苹果数 +开发者:王玉 +1.设计目的:激发玩家玩游戏的动力 +2.设计思路:统计贪吃蛇吃的苹果数,并且保存最佳记录。当贪吃蛇吃到苹果时,增加本关吃到的苹果数和此次吃到的苹果总数,若全部顺利通关,则比较此次吃到的苹果总数和最佳记录,若此次吃到的苹果总数大于最佳记录,则更新最佳记录,否则最佳记录不变。 +3.最终运行效果: + +![输入图片说明](%E7%BB%9F%E8%AE%A1%E8%8B%B9%E6%9E%9C%E6%95%B0.png) + +修复的bug:mian.py和game.py不能相互调用,用language.py存储选择的语种信息。language.py文件读不出来,影响合并;将读取language.py文件时的encoding改为UTF-8即可; + +加速功能 +开发者:杜天姣 +1、设计目的:是玩家更有成就感 +2、设计思路:本次修改针对游戏中的所有关卡,在原先游戏的基础上,按下空格,玩家操纵的蛇会加速,给予玩家一种刺激感,而且若是有计时操作,加速缩短通关的时间 +3、最终运行效果:请在游戏中详细体验 \ No newline at end of file diff --git a/allnumber b/allnumber new file mode 100644 index 0000000000000000000000000000000000000000..95c8a676e9d535b85485c6a8d1ee1991c9391ad0 --- /dev/null +++ b/allnumber @@ -0,0 +1 @@ +113 \ No newline at end of file diff --git a/chat.py b/chat.py index 9b1d181f803d318e0b5c2f2ca6aaa2c03500b598..7a525e63b3468fe309d244eb88cf7cd7b76613d0 100644 --- a/chat.py +++ b/chat.py @@ -1,6 +1,6 @@ -# 所有对话信息 +# 所有对话信息英文版 -level_chats = (((1, "Hello there new challenger!"), +level1_chats = (((1, "Hello there new challenger!"), (1, "Welcome to Snake Quest, where you will face multiple challenges!"), (2, "What's the prize?"), (1, "The prize is endless food!"), @@ -85,3 +85,93 @@ level_chats = (((1, "Hello there new challenger!"), (2, "Thank you very much for playing!"), (1, "Thank you!!!")) ) + + + +# 所有对话信息英文版 + +level2_chats = (((1, "你好,新挑战者!"), + (1, "欢迎来到贪吃蛇任务,你将面临多个挑战!"), + (2, "奖品是什么?"), + (1, "奖品是无尽的食物!"), + (2, "嘿嘿,我怎么开始呢?"), + (1, "但首先我需要向你介绍一下游戏控制方式"), + (1, "蛇会跟随你的鼠标移动"), + (1, "超出边界将导致蛇死亡"), + (1, "当你的生命值降为0时,你就基本上死了"), + (1, "左上角显示的是当前关卡等级。等级越高,蛇身越长"), + (1, "在第一阶段,你只需要达到第3级"), + (2, "太容易了"), + (1, "你说得太早了:^)"), + (1, "准备好后结束对话!")), + + ((1, "恭喜你完成第一阶段!"), + (1, "真正的挑战现在开始了"), + (2, "变强太容易了"), + (1, "在第二阶段,你需要躲避炮弹"), + (1, "同样,走出边界也会导致你死亡"), + (2, "就这么简单?"), + (1, "是的,就这么简单"), + (1, "但你需要达到第5级"), + (1, "准备好后结束对话!")), + + ((1, "看起来你正在适应这个游戏"), + (1, "开始第3级"), + (2, "第3级有什么特别的?"), + (1, "激光,总共四个"), + (1, "它们会出现在中间,准备好躲避"), + (1, "你必须躲开它们!"), + (2, "这就是全部了吗?"), + (1, "不仅如此!在这个阶段,每个食物给予的经验值翻倍"), + (1, "你还需要达到第10级"), + (1, "换句话说,你会变得更长"), + (2, "明白了,我准备好了"), + (1, "准备好后结束对话!")), + + ((1, "第4阶段是我认为最难的"), + (2, "嘿嘿嘿?"), + (1, "你还记得激光吗?"), + (2, "凭借我的闪避技巧,太容易了"), + (1, "但在这个阶段,激光也会移动~"), + (2, "什么?怎么回事"), + (1, "准备好后结束对话!")), + + ((1, "我们开始第5阶段!"), + (2, "第4阶段太容易了,一点都不难"), + (1, "既然如此,第5阶段将更容易!"), + (1, "只需要一个技巧:跑圈圈"), + (2, "这是什么意思?"), + (1, "你很快就会明白的"), + (1, "提示:前两秒后不要停留在中间"), + (2, "我应该待在边缘?"), + (1, "没错~准备好后结束对话!")), + + ((1, "恭喜你完成第5级!"), + (2, "<_<那个第一个激光吓了我一跳"), + (1, "哈哈,我会让第6阶段更清楚的"), + (2, "你最好如此 <_<"), + (1, "你还会遇到激光,但是是一个超大的激光!"), + (1, "它非常大,占据了半个场地!"), + (2, "但是,我怎么躲避?"), + (1, "它充能的时间也非常长"), + (1, "趁它充能时躲开它!"), + (2, "明白了"), + (1, "祝好运,准备好后结束对话!")), + + ((1, "欢迎来到最后一关!"), + (2, "终于!"), + (1, "这是一段漫长的旅程!所以我让这一关变得容易一些"), + (2, "嘿嘿嘿?"), + (1, "你需要达到第15级,并躲避一些东西"), + (2, "好的"), + (1, "祝好运,准备好后结束对话!")), + + ((1, "恭喜!你完成了整个游戏!"), + (2, "耶!!"), + (1, "现在你可以获得无限食物!"), + (2, "耶耶 :DDDD"), + (1, "谢谢你的参与!"), + (2, "这是Jeff Yan用pygame制作的小游戏"), + (2, "非常感谢你的参与!"), + (1, "谢谢!!")) + ) \ No newline at end of file diff --git a/config.py b/config.py index 49e5b56696d47f3459874ec2c533f14bdf1b9279..b55e41971509e29ac44cbca12682b1d66eaad7f1 100644 --- a/config.py +++ b/config.py @@ -1,6 +1,9 @@ import pygame import os from math import * +from speedup import SpeedUp + +speed_up = SpeedUp() # pygame初始化 pygame.init() diff --git a/game.py b/game.py index 53d13c6bb139255f3fd35d9ffad2eaa099081173..018e64a9807fc01d0e66bf8fc314fbea9ee8e291 100644 --- a/game.py +++ b/game.py @@ -4,16 +4,20 @@ from hud import * from menu import * from chat import * from scene import * - +from language import * +from config import speed_up class Game: """ 游戏主题,一共有六个阶段:主菜单,关卡选择,对话场景,关卡显示场景,关卡进行,关卡结果场景 可以根据current_level来改变当前关卡,用于继续上次游戏 """ - def __init__(self, current_level=0): + def __init__(self, current_level=0,all_number=0): self.snake_move_cycle = Cycle(2, 1) self.current_level = current_level + self.all_number = all_number + self.current_all_number = 0 + self.current_all_number1 = 0 self.current_playing = 0 self.map = None @@ -61,6 +65,11 @@ class Game: def start(self, level=7): self.menu = None self.snake = Snake(self) + + # 创建一个名为 snake 的蛇对象,并将其作为 Game 类的属性 + # 传入 self 参数是为了在蛇对象中能够访问 Game 类的其他属性和方法 + self.snake = Snake(self, speed_up) + for _ in range(5): self.snake.grow() self.info_hud = InfoBar(self.snake) @@ -82,7 +91,11 @@ class Game: self.map = Level8(self) self.map.set_snake(self.snake) self.update() - self.start_scene(TalkScene("snake_1", "snake_2", level_chats[level-1])) + exec(open('language.py').read()) + if begin == "en": + self.start_scene(TalkScene("snake_1", "snake_2", level1_chats[level - 1])) + elif begin == "cn": + self.start_scene(TalkScene("snake_1", "snake_2", level2_chats[level - 1])) bgs[3].play_non_stop() # 绘制当前状态,菜单优先,其次场景,最后是游戏本身 @@ -92,7 +105,7 @@ class Game: elif not self.scene: self.map.draw_background(self.get_offset()) self.snake.draw() - self.map.draw(self.get_offset()) + self.map.draw(self.get_offset(),applenumber=0) self.info_hud.draw() else: diff --git a/img/.keep b/img/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/img/AK]MA8MOK(~E@({A_40P@VX.jpg b/img/AK]MA8MOK(~E@({A_40P@VX.jpg new file mode 100644 index 0000000000000000000000000000000000000000..841cd7a546cdc3a0228799735f28c08a0a3a71ff Binary files /dev/null and b/img/AK]MA8MOK(~E@({A_40P@VX.jpg differ diff --git a/img/ALE2%IQ3_2M07_ZBO(G8HBJ.png b/img/ALE2%IQ3_2M07_ZBO(G8HBJ.png new file mode 100644 index 0000000000000000000000000000000000000000..430f47c08e2e15e3729d369e64388767a782eeaf Binary files /dev/null and b/img/ALE2%IQ3_2M07_ZBO(G8HBJ.png differ diff --git a/language.py b/language.py new file mode 100644 index 0000000000000000000000000000000000000000..4cfe95b604cff271c52c625e719074f7e81d3a17 --- /dev/null +++ b/language.py @@ -0,0 +1,6 @@ + +begin = "cn" + + +#"en"或"cn" +#"en":英文版 "cn":中文版 \ No newline at end of file diff --git a/main.py b/main.py index f16bfc0946275f8a373674e9a7e4ec4b085043f7..dd0ca772943ce5a31133f0ddfb8d09fc17c3a45d 100644 --- a/main.py +++ b/main.py @@ -1,26 +1,69 @@ from game import * from scene import * import sys +import importlib +importlib.reload(sys) +c_level = 0 +all_number = 0 + +#定义选择语言的按钮 + +# from tkinter import Tk,Button +# +# root = Tk() +# +# selected_language = None +# +# def set_language(lang): +# global selected_language +# selected_language = lang +# print(lang) + +# 创建两个按钮 +# Button(root, text="English", command=lambda: set_language("en")).pack(side="left") +# Button(root, text="中文", command=lambda: set_language("cn")).pack(side="left") + + +clock = pygame.time.Clock() # 读取当前存档,如果没有的话则开始新的游戏 if os.path.exists("save"): f = open("save", "r") c_level = int(f.read()) f.close() - g = Game(c_level) -else: - g = Game() +if os.path.exists("allnumber"): + f = open("allnumber", "r") + all_number = int(f.read()) + f.close() + + +g = Game(c_level,all_number) # 主循环 while True: + # 获取运行时间的函数 + def get_running_time(): + current_time = pygame.time.get_ticks() # 获取当前的毫秒时间 + return current_time - start_time # 返回游戏运行的总时间 + # 处理事件 for event in pygame.event.get(): + speed_up.handle_event(event) + # 关闭事件,在关闭的时候存下当前关卡 + + if event.type == pygame.QUIT: f = open("save", "w") f.write(str(g.current_level)) f.close() + if g.current_all_number1>g.current_all_number: + g.current_all_number1 = g.current_all_number + if g.current_all_number1>all_number: + f = open("allnumber", "w") + f.write(str(g.current_all_number1)) + f.close() pygame.quit() sys.exit() # 鼠标事件,更新环境变量 @@ -30,14 +73,26 @@ while True: env["mouse_direction"] = atan2(env["mouse_y"] - screen_height/2, env["mouse_x"] - screen_width/2) # 让游戏处理事件 g.handle_event(event) + + + + # 游戏更新 g.update() # 清空屏幕,然后绘制一个新的屏幕 screen.fill(0) g.draw() + running_time = get_running_time() // 1000 # 毫秒转换为秒 + font = pygame.font.Font(None, 36) + text = font.render("Time: {}s".format(running_time), True, (255, 255, 255)) + screen.blit(text, (10, 10)) + + # 因为基本上每次都需要更新整个屏幕,直接使用flip来刷新整个屏幕 pygame.display.flip() # 将帧速率限制到40fps clock.tick(40) + + # root.update() \ No newline at end of file diff --git a/map.py b/map.py index 3c7c79f0034b74f967d1811f25da4667deae2c63..be7e209a024485be0baf2e5f174dd412e985fa02 100644 --- a/map.py +++ b/map.py @@ -1,438 +1,462 @@ -from fights import * - - -class Level: - """ - 关卡父类 - """ - def __init__(self): - pass - - # 判断是否过关 - def is_passed(self): - return False - - -class Map(Level): - """ - 地图,存储数据有所有攻击,经验球,动画以及物品(大炮,激光炮等) - per_exp为每个经验球的经验,food_count是场上经验球数量,pass_level是过关等级 - """ - def __init__(self, game): - Level.__init__(self) - self.game = game - self.objects = [] - self.exp_balls = [] - self.deme = [300, 300] - self.snake = None - self.attacks = [] - self.food_count = 5 - self.per_exp = 10 - self.pass_level = 1 - - self.boarder_cycle = ReCycle(6, 1) - - self.animations = [] - - # 判断当前蛇是否死亡 - def is_dead(self): - return self.snake.hp < 0 - - # 绘制四周边框,是动画 - def draw_boarder(self, offset): - c = self.boarder_cycle.get() - pygame.draw.line(screen, (255, 255, 255), - (-self.deme[0] + offset[0] + c, -self.deme[1] + offset[1]), - (-self.deme[0] + offset[0] + c, self.deme[1] + offset[1]), 2) - pygame.draw.line(screen, (255, 255, 255), - (-self.deme[0] + offset[0] - c, -self.deme[1] + offset[1]), - (-self.deme[0] + offset[0] - c, self.deme[1] + offset[1]), 2) - - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0] + c, -self.deme[1] + offset[1]), - (self.deme[0] + offset[0] + c, self.deme[1] + offset[1]), 2) - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0] - c, -self.deme[1] + offset[1]), - (self.deme[0] + offset[0] - c, self.deme[1] + offset[1]), 2) - - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0], self.deme[1] + offset[1] + c), - (-self.deme[0] + offset[0], self.deme[1] + offset[1] + c), 2) - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0], self.deme[1] + offset[1] - c), - (-self.deme[0] + offset[0], self.deme[1] + offset[1] - c), 2) - - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0], -self.deme[1] + offset[1] + c), - (-self.deme[0] + offset[0], -self.deme[1] + offset[1] + c), 2) - pygame.draw.line(screen, (255, 255, 255), - (self.deme[0] + offset[0], -self.deme[1] + offset[1] - c), - (-self.deme[0] + offset[0], -self.deme[1] + offset[1] - c), 2) - - pygame.draw.rect(screen, (255, 255, 255), - pygame.Rect(offset[0] - self.deme[0] - 15, offset[1] - self.deme[1] - 15, 30, - 30)) - pygame.draw.rect(screen, (255, 255, 255), - pygame.Rect(offset[0] + self.deme[0] - 15, offset[1] - self.deme[1] - 15, 30, - 30)) - pygame.draw.rect(screen, (255, 255, 255), - pygame.Rect(offset[0] - self.deme[0] - 15, offset[1] + self.deme[1] - 15, 30, - 30)) - pygame.draw.rect(screen, (255, 255, 255), - pygame.Rect(offset[0] + self.deme[0] - 15, offset[1] + self.deme[1] - 15, 30, - 30)) - - # 添加一个激光,具体参数清参考fights里的Beam类 - def add_beam(self, position, length, direction, width=30): - self.attacks.append(Beam(self, position, length, direction, width)) - - # 添加一个子弹,具体参数清参考fights里的Bullet类 - def add_bullet(self, position, speed, radius, damage): - self.attacks.append(Bullet(self, damage, radius, position[0], position[1], speed[0], speed[1])) - - # 设置当前蛇 - def set_snake(self, snake): - self.snake = snake - - # 绘制背景底色 - def draw_background(self, offset): - pygame.draw.rect(screen, (70, 70, 70), - pygame.Rect(offset[0] - self.deme[0], offset[1] - self.deme[1], self.deme[0] * 2, - self.deme[1] * 2)) - - # 绘制地图上的所有物件 - def draw(self, offset): - for i in range(len(self.exp_balls)-1, -1, -1): - self.exp_balls[i].draw(offset) - for i in range(len(self.attacks) - 1, -1, -1): - self.attacks[i].draw(offset) - for i in range(len(self.objects) - 1, -1, -1): - self.objects[i].draw(offset) - for i in range(len(self.animations)-1, -1, -1): - self.animations[i].draw(offset) - - if self.snake.outofbound: - screen.blit(texture_lib["danger"], (0, 0)) - - self.draw_boarder(offset) - pass_render = chat_font.render("Target:"+str(self.pass_level), False, (255, 255, 255)) - screen.blit(pass_render, (450, 30)) - - # 更新地图上的所有物品,若有物品为dead则删除物品,同时判断攻击tick,以及经验球与蛇的碰撞 - def update(self): - for i in range(len(self.exp_balls)-1, -1, -1): - if get_distance(self.snake.position, self.exp_balls[i].pos) < 20: - self.snake.current_exp += self.exp_balls[i].points - ses[2].play_once() - del self.exp_balls[i] - - for i in range(len(self.animations) - 1, -1, -1): - if self.animations[i].dead: - del self.animations[i] - else: - self.animations[i].update() - - for i in range(len(self.attacks)-1, -1, -1): - self.attacks[i].update() - if self.attacks[i].attack: - if self.attacks[i].collide_with(self.snake): - self.snake.hp -= self.attacks[i].damage - if self.attacks[i].bounded: - if self.attacks[i].pos[0] > self.deme[0] or \ - self.attacks[i].pos[0] < -self.deme[0] or \ - self.attacks[i].pos[1] > self.deme[1] or \ - self.attacks[i].pos[1] < -self.deme[1]: - self.attacks[i].dead = True - if self.attacks[i].dead: - del self.attacks[i] - - for i in range(len(self.objects)-1, -1, -1): - self.objects[i].update() - if self.objects[i].dead: - del self.objects[i] - - if len(self.exp_balls) < self.food_count: - self.exp_balls.append(ExpBall((random.randint(-self.deme[0], self.deme[0]), - random.randint(-self.deme[1], self.deme[1])), self.per_exp)) - - if (self.snake.position[0] < -self.deme[0] or - self.snake.position[0] > self.deme[0] or - self.snake.position[1] < -self.deme[1] or - self.snake.position[1] > self.deme[1]): - self.snake.outofbound = True - else: - self.snake.outofbound = False - - -class Level1(Map): - """ - 第一关,场地为200,200 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 200 - self.deme[1] = 200 - self.pass_level = 3 - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 同父类 - def update(self): - Map.update(self) - - -class Level2(Map): - """ - 第二关,有两个大炮 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 250 - self.deme[1] = 250 - self.pass_level = 5 - self.per_exp = 15 - - self.objects.append(OneCanon((-310, 100))) - self.objects.append(OneCanon((-310, -100))) - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 大炮发射炮弹 - def update(self): - Map.update(self) - if self.objects[0].cast: - self.add_bullet((self.objects[0].pos[0]+70, self.objects[0].pos[1]+40), (5, 0), 15, 10) - ses[5].play_once() - if self.objects[1].cast: - self.add_bullet((self.objects[1].pos[0]+70, self.objects[1].pos[1]+40), (5, 0), 15, 10) - ses[5].play_once() - - -class Level3(Map): - """ - 第三关,一个十字激光 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 300 - self.deme[1] = 300 - self.per_exp = 30 - self.pass_level = 10 - - self.objects.append(CrossCanon((-40, -40))) - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 发射十字激光 - def update(self): - Map.update(self) - if self.objects[0].cast: - self.add_beam((-300, 0), 600, "h") - self.add_beam((0, -300), 600, "v") - - -class Level4(Map): - """ - 第四关,一个移动激光 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 350 - self.deme[1] = 350 - self.per_exp = 30 - self.beam_cycle = Cycle(80, 0) - self.pass_level = 10 - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 一共有八种激光移动方式,随机生成一个 - def update(self): - Map.update(self) - if not self.attacks: - if self.beam_cycle.get() == 0: - generated = random.randint(0, 7) - if generated == 0: - self.objects.append(MovingBeamCannon(self, (-350, -350), "h", 1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 1: - self.objects.append(MovingBeamCannon(self, (-350, 0), "h", 1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 2: - self.objects.append(MovingBeamCannon(self, (-350, 350), "h", -1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 3: - self.objects.append(MovingBeamCannon(self, (-350, 0), "h", -1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 4: - self.objects.append(MovingBeamCannon(self, (-350, -350), "v", 1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 5: - self.objects.append(MovingBeamCannon(self, (0, -350), "v", 1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 6: - self.objects.append(MovingBeamCannon(self, (350, -350), "v", -1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - elif generated == 7: - self.objects.append(MovingBeamCannon(self, (0, -350), "v", -1, 300, 700)) - self.attacks.append(self.objects[-1].get_beam()) - - -class Level5(Map): - """ - 第五关,有一个旋转激光 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 400 - self.deme[1] = 400 - self.per_exp = 30 - self.count_down = 80 - self.pass_level = 10 - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 在最开始延时一段时间再生成激光 - def update(self): - Map.update(self) - self.count_down -= 1 - if self.count_down == 0: - self.attacks.append(CenterSlice(self, 1, 0.005, 400)) - - -class Level6(Map): - """ - 第六关,有一个巨型激光 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 300 - self.deme[1] = 300 - self.per_exp = 25 - self.attacked = True - self.current_attack_pos = (-150, -300) - self.pass_level = 10 - - self.attack_countdown = 90 - self.attack_tick = self.attack_countdown - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 在激光前摇动画结束的时候生成一个巨型激光,否则根据攻击tick来生成一个前摇 - def update(self): - Map.update(self) - - if not self.attacked and not self.animations: - self.attack_tick = self.attack_countdown - self.attacked = True - self.attacks.append(Beam(self, self.current_attack_pos, 600, "v", last_t=10, pre_t=0, width=300, damage=40)) - ses[0].play_once() - self.game.shake("v", 60) - elif not self.animations and not self.attacks: - self.attack_tick -= 1 - if self.attack_tick < 0: - self.attacked = False - if random.randint(0, 1) == 0: - self.current_attack_pos = (-150, -300) - else: - self.current_attack_pos = (150, -300) - self.animations.append(Charge(self.current_attack_pos, 150, 600, 20)) - - -class Level7(Map): - """ - 第七关,有四条随机横向或者竖向的激光 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 400 - self.deme[1] = 400 - self.per_exp = 40 - self.pass_level = 15 - - self.current_wave = ((300, -400), (100, -400), (-100, -400), (-300, -400), "v") - self.attacking = True - self.attack_tick = 0 - self.attack_speed = 20 - - self.attack_cycle = Cycle(120, 0) - - # 同父类 - def is_passed(self): - if self.snake.level >= self.pass_level: - return True - return False - - # 生成四条横向或者竖向的激光 - def update(self): - Map.update(self) - if self.attacking: - self.attack_tick += 1 - if self.attack_tick == self.attack_speed: - self.attacks.append(Beam(self, self.current_wave[0], 800, self.current_wave[4], - pre_t=80, width=50, damage=20)) - elif self.attack_tick == self.attack_speed*2: - self.attacks.append(Beam(self, self.current_wave[1], 800, self.current_wave[4], - pre_t=80, width=50, damage=20)) - elif self.attack_tick == self.attack_speed*3: - self.attacks.append(Beam(self, self.current_wave[2], 800, self.current_wave[4], - pre_t=80, width=50, damage=20)) - elif self.attack_tick == self.attack_speed*4: - self.attacks.append(Beam(self, self.current_wave[3], 800, self.current_wave[4], - pre_t=80, width=50, damage=20)) - elif self.attack_tick > self.attack_speed * 4: - self.attacking = False - self.attack_tick = 0 - elif self.attack_cycle.get() == 0: - self.attacking = True - mode = random.randint(1, 4) - if mode == 1: - self.current_wave = ((300, -400), (100, -400), (-100, -400), (-300, -400), "v") - elif mode == 2: - self.current_wave = ((-300, -400), (-100, -400), (100, -400), (300, -400), "v") - elif mode == 3: - self.current_wave = ((-400, -300), (-400, -100), (-400, 100), (-400, 300), "h") - elif mode == 4: - self.current_wave = ((-400, 300), (-400, 100), (-400, -100), (-400, -300), "h") - - -class Level8(Map): - """ - 第八关,每吃一个果子升一级,可以(基本上)无限玩下去 - """ - def __init__(self, game): - Map.__init__(self, game) - self.deme[0] = 400 - self.deme[1] = 400 - self.per_exp = 101 - self.food_count = 20 - self.pass_level = 99999 - - def is_passed(self): - return False - - def update(self): - Map.update(self) +from fights import * +from revive import * + +revive=revive() +class Level: + """ + 关卡父类 + """ + def __init__(self): + pass + + # 判断是否过关 + def is_passed(self): + return False + + +class Map(Level): + """ + 地图,存储数据有所有攻击,经验球,动画以及物品(大炮,激光炮等) + per_exp为每个经验球的经验,food_count是场上经验球数量,pass_level是过关等级 + """ + def __init__(self, game): + Level.__init__(self) + self.game = game + self.objects = [] + self.exp_balls = [] + self.deme = [300, 300] + self.snake = None + self.attacks = [] + self.food_count = 5 + self.per_exp = 10 + self.pass_level = 1 + + self.boarder_cycle = ReCycle(6, 1) + + self.animations = [] + + # 判断当前蛇是否死亡 + def is_dead(self): + if ( self.snake.hp < 0 ) : + self.game.current_all_number1 = self.game.current_all_number + self.game.current_all_number -= self.snake.current_applenumber + if (revive.revive_count>=5): + revive.judge() + self.snake.hp = 100 + revive.reset_revive_count() + return self.snake.hp < 0 + + # 绘制四周边框,是动画 + def draw_boarder(self, offset): + c = self.boarder_cycle.get() + pygame.draw.line(screen, (255, 255, 255), + (-self.deme[0] + offset[0] + c, -self.deme[1] + offset[1]), + (-self.deme[0] + offset[0] + c, self.deme[1] + offset[1]), 2) + pygame.draw.line(screen, (255, 255, 255), + (-self.deme[0] + offset[0] - c, -self.deme[1] + offset[1]), + (-self.deme[0] + offset[0] - c, self.deme[1] + offset[1]), 2) + + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0] + c, -self.deme[1] + offset[1]), + (self.deme[0] + offset[0] + c, self.deme[1] + offset[1]), 2) + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0] - c, -self.deme[1] + offset[1]), + (self.deme[0] + offset[0] - c, self.deme[1] + offset[1]), 2) + + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0], self.deme[1] + offset[1] + c), + (-self.deme[0] + offset[0], self.deme[1] + offset[1] + c), 2) + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0], self.deme[1] + offset[1] - c), + (-self.deme[0] + offset[0], self.deme[1] + offset[1] - c), 2) + + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0], -self.deme[1] + offset[1] + c), + (-self.deme[0] + offset[0], -self.deme[1] + offset[1] + c), 2) + pygame.draw.line(screen, (255, 255, 255), + (self.deme[0] + offset[0], -self.deme[1] + offset[1] - c), + (-self.deme[0] + offset[0], -self.deme[1] + offset[1] - c), 2) + + pygame.draw.rect(screen, (255, 255, 255), + pygame.Rect(offset[0] - self.deme[0] - 15, offset[1] - self.deme[1] - 15, 30, + 30)) + pygame.draw.rect(screen, (255, 255, 255), + pygame.Rect(offset[0] + self.deme[0] - 15, offset[1] - self.deme[1] - 15, 30, + 30)) + pygame.draw.rect(screen, (255, 255, 255), + pygame.Rect(offset[0] - self.deme[0] - 15, offset[1] + self.deme[1] - 15, 30, + 30)) + pygame.draw.rect(screen, (255, 255, 255), + pygame.Rect(offset[0] + self.deme[0] - 15, offset[1] + self.deme[1] - 15, 30, + 30)) + + # 添加一个激光,具体参数清参考fights里的Beam类 + def add_beam(self, position, length, direction, width=30): + self.attacks.append(Beam(self, position, length, direction, width)) + + # 添加一个子弹,具体参数清参考fights里的Bullet类 + def add_bullet(self, position, speed, radius, damage): + self.attacks.append(Bullet(self, damage, radius, position[0], position[1], speed[0], speed[1])) + + # 设置当前蛇 + def set_snake(self, snake): + self.snake = snake + + # 绘制背景底色 + def draw_background(self, offset): + pygame.draw.rect(screen, (70, 70, 70), + pygame.Rect(offset[0] - self.deme[0], offset[1] - self.deme[1], self.deme[0] * 2, + self.deme[1] * 2)) + + # 绘制地图上的所有物件 + def draw(self, offset,applenumber=-1): + for i in range(len(self.exp_balls)-1, -1, -1): + self.exp_balls[i].draw(offset) + for i in range(len(self.attacks) - 1, -1, -1): + self.attacks[i].draw(offset) + for i in range(len(self.objects) - 1, -1, -1): + self.objects[i].draw(offset) + for i in range(len(self.animations)-1, -1, -1): + self.animations[i].draw(offset) + + if self.snake.outofbound: + screen.blit(texture_lib["danger"], (0, 0)) + + self.draw_boarder(offset) + pass_render = chat_font.render("Target:"+str(self.pass_level), False, (255, 255, 255)) + screen.blit(pass_render, (450, 30)) + # if applenumber!=-1: + pass_render1 = chat_font.render("苹果数:" + str(self.snake.current_applenumber), False, (255, 255, 255)) + screen.blit(pass_render1, (450, 60)) + pass_render1 = chat_font.render("最佳记录:" + str(self.game.all_number), False, (255, 255, 255)) + screen.blit(pass_render1, (450, 90)) + pass_render1 = chat_font.render("当前记录:" + str(self.game.current_all_number), False, (255, 255, 255)) + screen.blit(pass_render1, (450, 120)) + + # 更新地图上的所有物品,若有物品为dead则删除物品,同时判断攻击tick,以及经验球与蛇的碰撞 + def update(self): + for i in range(len(self.exp_balls)-1, -1, -1): + if get_distance(self.snake.position, self.exp_balls[i].pos) < 20: + self.snake.current_exp += self.exp_balls[i].points + self.snake.current_applenumber += 1 + self.game.current_all_number += 1 + ses[2].play_once() + del self.exp_balls[i] + + for i in range(len(self.animations) - 1, -1, -1): + if self.animations[i].dead: + del self.animations[i] + else: + self.animations[i].update() + + for i in range(len(self.attacks)-1, -1, -1): + self.attacks[i].update() + if self.attacks[i].attack: + if self.attacks[i].collide_with(self.snake): + self.snake.hp -= self.attacks[i].damage + if self.attacks[i].bounded: + if self.attacks[i].pos[0] > self.deme[0] or \ + self.attacks[i].pos[0] < -self.deme[0] or \ + self.attacks[i].pos[1] > self.deme[1] or \ + self.attacks[i].pos[1] < -self.deme[1]: + self.attacks[i].dead = True + if self.attacks[i].dead: + del self.attacks[i] + + for i in range(len(self.objects)-1, -1, -1): + self.objects[i].update() + if self.objects[i].dead: + del self.objects[i] + + if len(self.exp_balls) < self.food_count: + self.exp_balls.append(ExpBall((random.randint(-self.deme[0], self.deme[0]), + random.randint(-self.deme[1], self.deme[1])), self.per_exp)) + + if (self.snake.position[0] < -self.deme[0] or + self.snake.position[0] > self.deme[0] or + self.snake.position[1] < -self.deme[1] or + self.snake.position[1] > self.deme[1]): + self.snake.outofbound = True + else: + self.snake.outofbound = False + + +class Level1(Map): + """ + 第一关,场地为200,200 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 200 + self.deme[1] = 200 + self.pass_level = 3 + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 同父类 + def update(self): + Map.update(self) + + +class Level2(Map): + """ + 第二关,有两个大炮 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 250 + self.deme[1] = 250 + self.pass_level = 5 + self.per_exp = 15 + + self.objects.append(OneCanon((-310, 100))) + self.objects.append(OneCanon((-310, -100))) + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 大炮发射炮弹 + def update(self): + Map.update(self) + if self.objects[0].cast: + self.add_bullet((self.objects[0].pos[0]+70, self.objects[0].pos[1]+40), (5, 0), 15, 10) + ses[5].play_once() + if self.objects[1].cast: + self.add_bullet((self.objects[1].pos[0]+70, self.objects[1].pos[1]+40), (5, 0), 15, 10) + ses[5].play_once() + + +class Level3(Map): + """ + 第三关,一个十字激光 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 300 + self.deme[1] = 300 + self.per_exp = 30 + self.pass_level = 10 + + self.objects.append(CrossCanon((-40, -40))) + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 发射十字激光 + def update(self): + Map.update(self) + if self.objects[0].cast: + self.add_beam((-300, 0), 600, "h") + self.add_beam((0, -300), 600, "v") + + +class Level4(Map): + """ + 第四关,一个移动激光 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 350 + self.deme[1] = 350 + self.per_exp = 30 + self.beam_cycle = Cycle(80, 0) + self.pass_level = 10 + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 一共有八种激光移动方式,随机生成一个 + def update(self): + Map.update(self) + if not self.attacks: + if self.beam_cycle.get() == 0: + generated = random.randint(0, 7) + if generated == 0: + self.objects.append(MovingBeamCannon(self, (-350, -350), "h", 1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 1: + self.objects.append(MovingBeamCannon(self, (-350, 0), "h", 1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 2: + self.objects.append(MovingBeamCannon(self, (-350, 350), "h", -1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 3: + self.objects.append(MovingBeamCannon(self, (-350, 0), "h", -1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 4: + self.objects.append(MovingBeamCannon(self, (-350, -350), "v", 1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 5: + self.objects.append(MovingBeamCannon(self, (0, -350), "v", 1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 6: + self.objects.append(MovingBeamCannon(self, (350, -350), "v", -1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + elif generated == 7: + self.objects.append(MovingBeamCannon(self, (0, -350), "v", -1, 300, 700)) + self.attacks.append(self.objects[-1].get_beam()) + + +class Level5(Map): + """ + 第五关,有一个旋转激光 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 400 + self.deme[1] = 400 + self.per_exp = 30 + self.count_down = 80 + self.pass_level = 10 + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 在最开始延时一段时间再生成激光 + def update(self): + Map.update(self) + self.count_down -= 1 + if self.count_down == 0: + self.attacks.append(CenterSlice(self, 1, 0.005, 400)) + + +class Level6(Map): + """ + 第六关,有一个巨型激光 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 300 + self.deme[1] = 300 + self.per_exp = 25 + self.attacked = True + self.current_attack_pos = (-150, -300) + self.pass_level = 10 + + self.attack_countdown = 90 + self.attack_tick = self.attack_countdown + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 在激光前摇动画结束的时候生成一个巨型激光,否则根据攻击tick来生成一个前摇 + def update(self): + Map.update(self) + + if not self.attacked and not self.animations: + self.attack_tick = self.attack_countdown + self.attacked = True + self.attacks.append(Beam(self, self.current_attack_pos, 600, "v", last_t=10, pre_t=0, width=300, damage=40)) + ses[0].play_once() + self.game.shake("v", 60) + elif not self.animations and not self.attacks: + self.attack_tick -= 1 + if self.attack_tick < 0: + self.attacked = False + if random.randint(0, 1) == 0: + self.current_attack_pos = (-150, -300) + else: + self.current_attack_pos = (150, -300) + self.animations.append(Charge(self.current_attack_pos, 150, 600, 20)) + + +class Level7(Map): + """ + 第七关,有四条随机横向或者竖向的激光 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 400 + self.deme[1] = 400 + self.per_exp = 40 + self.pass_level = 15 + + self.current_wave = ((300, -400), (100, -400), (-100, -400), (-300, -400), "v") + self.attacking = True + self.attack_tick = 0 + self.attack_speed = 20 + + self.attack_cycle = Cycle(120, 0) + + # 同父类 + def is_passed(self): + if self.snake.level >= self.pass_level: + revive.increment_revive_count() + return True + return False + + # 生成四条横向或者竖向的激光 + def update(self): + Map.update(self) + if self.attacking: + self.attack_tick += 1 + if self.attack_tick == self.attack_speed: + self.attacks.append(Beam(self, self.current_wave[0], 800, self.current_wave[4], + pre_t=80, width=50, damage=20)) + elif self.attack_tick == self.attack_speed*2: + self.attacks.append(Beam(self, self.current_wave[1], 800, self.current_wave[4], + pre_t=80, width=50, damage=20)) + elif self.attack_tick == self.attack_speed*3: + self.attacks.append(Beam(self, self.current_wave[2], 800, self.current_wave[4], + pre_t=80, width=50, damage=20)) + elif self.attack_tick == self.attack_speed*4: + self.attacks.append(Beam(self, self.current_wave[3], 800, self.current_wave[4], + pre_t=80, width=50, damage=20)) + elif self.attack_tick > self.attack_speed * 4: + self.attacking = False + self.attack_tick = 0 + elif self.attack_cycle.get() == 0: + self.attacking = True + mode = random.randint(1, 4) + if mode == 1: + self.current_wave = ((300, -400), (100, -400), (-100, -400), (-300, -400), "v") + elif mode == 2: + self.current_wave = ((-300, -400), (-100, -400), (100, -400), (300, -400), "v") + elif mode == 3: + self.current_wave = ((-400, -300), (-400, -100), (-400, 100), (-400, 300), "h") + elif mode == 4: + self.current_wave = ((-400, 300), (-400, 100), (-400, -100), (-400, -300), "h") + + +class Level8(Map): + """ + 第八关,每吃一个果子升一级,可以(基本上)无限玩下去 + """ + def __init__(self, game): + Map.__init__(self, game) + self.deme[0] = 400 + self.deme[1] = 400 + self.per_exp = 101 + self.food_count = 20 + self.pass_level = 99999 + + def is_passed(self): + return False + + def update(self): + Map.update(self) diff --git a/revive.py b/revive.py new file mode 100644 index 0000000000000000000000000000000000000000..c81fb0c9957a599ba735db090e3bb24e521db417 --- /dev/null +++ b/revive.py @@ -0,0 +1,21 @@ +from hud import * +class revive: + # 初始化复活机制所需的变量和状态 + def __init__(self): + self.revive_count = 0 + + def increment_revive_count(self): + self.revive_count += 1 + + def judge(self): + # 复活机制的逻辑 + if self.revive_count >= 5: + text = chat_font.render("你连续通过了五个及以上关卡获得了一次复活机会!", True, "white") + screen.fill((0, 0, 0)) + screen.blit(text, (screen_width // 2 - text.get_width() // 2, screen_height // 2 - text.get_height() // 2)) + pygame.display.flip() + pygame.time.wait(3000) + + def reset_revive_count(self): + # 重置复活计数 + self.revive_count = 0 \ No newline at end of file diff --git a/snake.py b/snake.py index bd9f421f76f321e09ec136ef3c8fd0809cd07c6d..052fcd8254e38e0820c8d70f34d9c4fb1a104d22 100644 --- a/snake.py +++ b/snake.py @@ -37,6 +37,7 @@ class Snake: 贪吃蛇本体,由许多Segment构成 """ def __init__(self, game): + def __init__(self, game, speed_up): self.game = game self.width = 10 self.speed = 7 @@ -57,6 +58,8 @@ class Snake: self.dead = False self.hit_points = [] + self.current_applenumber = 0 + self.speed_up =speed_up # 设置当前蛇前进角度 def set_direction(self, angle): @@ -107,6 +110,14 @@ class Snake: # 进行更新,更新Segment宽度,当前经验升级,更新血量信息,以及碰撞点与绘制点列表 def update(self): + #如果加速键被按下,应用加速 + if self.speed_up.acceleration_key_pressed: + self.speed = 14 + self.acceleration = True + else: + self.speed = 7 # 恢复正常速度 + self.acceleration = False + for i in range(self.length): self.segments[i].set_width(self.seg_width[i]) self.segments[i].update() diff --git a/speedup.py b/speedup.py new file mode 100644 index 0000000000000000000000000000000000000000..704a35f2bd45513c1ae743881bdf04d6c9ab7073 --- /dev/null +++ b/speedup.py @@ -0,0 +1,13 @@ +import pygame + +class SpeedUp: + def __init__(self): + self.acceleration_key_pressed = False + + def handle_event(self, event): + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_SPACE: + self.acceleration_key_pressed = True + elif event.type == pygame.KEYUP: + if event.key == pygame.K_SPACE: + self.acceleration_key_pressed = False \ No newline at end of file diff --git "a/\347\273\237\350\256\241\350\213\271\346\236\234\346\225\260.png" "b/\347\273\237\350\256\241\350\213\271\346\236\234\346\225\260.png" new file mode 100644 index 0000000000000000000000000000000000000000..4b9e8223568dde0f5b36ce66e9020b07b1df77f1 Binary files /dev/null and "b/\347\273\237\350\256\241\350\213\271\346\236\234\346\225\260.png" differ