diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..359bb5307e8535ab7d59faf27a7377033291821e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000000000000000000000000000000000000..11a5d8e18ab71465be9424cf930c5e792c75edb7 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +main.py \ No newline at end of file diff --git a/.idea/Adapted-game-snake.iml b/.idea/Adapted-game-snake.iml new file mode 100644 index 0000000000000000000000000000000000000000..8437fe66726a74ad9e6a89ed9c73e7a4fee5e64b --- /dev/null +++ b/.idea/Adapted-game-snake.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..64daf1693b3bc4927c3201b21c769ef0a7ddff82 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc9ea4906e15825848ae951155a4381c08529eaf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..4754f78d7964e15cab9c96605b62bbc1396b4f6f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3e4731e6c1d0e144b8722666c489f0419e00465f..756072d733ea915714e08b19335822a008622e15 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ exe文件在SnakeQuest-exe里-运行SnakeQuest.exe就可以了 #### 作品名 蛇蛇闯关 -#### 项目简介 +#### 项目简介 **非常建议开音量玩,30左右即可** 独特的闯关模式,更加平滑的360度移动,炫酷的攻击动画,耐听又贴切的背景音乐 diff --git a/SE2101010.md b/SE2101010.md new file mode 100644 index 0000000000000000000000000000000000000000..1a9deeeca96350663ece5eb4d3ab8b27e11ea786 Binary files /dev/null and b/SE2101010.md differ diff --git a/__pycache__/animations.cpython-310.pyc b/__pycache__/animations.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c925710282795e5e2d47168391a345a698bb9d34 Binary files /dev/null and b/__pycache__/animations.cpython-310.pyc differ diff --git a/__pycache__/animations.cpython-39.pyc b/__pycache__/animations.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fed9a78f3033da32ade62942ce74084593c07567 Binary files /dev/null and b/__pycache__/animations.cpython-39.pyc differ diff --git a/__pycache__/chat.cpython-310.pyc b/__pycache__/chat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1cd21e14b80d0a6bf397d3390e7cef2942014544 Binary files /dev/null and b/__pycache__/chat.cpython-310.pyc differ diff --git a/__pycache__/chat.cpython-39.pyc b/__pycache__/chat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04da54dff01ce6d486c065eb18e74c24b7688fde Binary files /dev/null and b/__pycache__/chat.cpython-39.pyc differ diff --git a/__pycache__/config.cpython-310.pyc b/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0ca8a8f547b42b8069943da384fcda44c653b27 Binary files /dev/null and b/__pycache__/config.cpython-310.pyc differ diff --git a/__pycache__/config.cpython-39.pyc b/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b1d4162d3d03a444681f857e2820a7c75a4f081 Binary files /dev/null and b/__pycache__/config.cpython-39.pyc differ diff --git a/__pycache__/cycle.cpython-310.pyc b/__pycache__/cycle.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca08a799bc04431554cf026174a4d31f6ab4ed95 Binary files /dev/null and b/__pycache__/cycle.cpython-310.pyc differ diff --git a/__pycache__/cycle.cpython-39.pyc b/__pycache__/cycle.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f32cc6a3d536b8b6c5a4686e21e564594c91264f Binary files /dev/null and b/__pycache__/cycle.cpython-39.pyc differ diff --git a/__pycache__/enemy_snake.cpython-310.pyc b/__pycache__/enemy_snake.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..108bf406507bc82eb378073bd150a06c7915fd79 Binary files /dev/null and b/__pycache__/enemy_snake.cpython-310.pyc differ diff --git a/__pycache__/enemy_snake.cpython-39.pyc b/__pycache__/enemy_snake.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..478a63535f6de67f7f15a90b97239383b6861f57 Binary files /dev/null and b/__pycache__/enemy_snake.cpython-39.pyc differ diff --git a/__pycache__/fights.cpython-310.pyc b/__pycache__/fights.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ceb97d7d689a7a5bbef19f3b66731f9e5df40f3 Binary files /dev/null and b/__pycache__/fights.cpython-310.pyc differ diff --git a/__pycache__/fights.cpython-39.pyc b/__pycache__/fights.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa2d02653297a896ce88b39019c1799c1a34c98d Binary files /dev/null and b/__pycache__/fights.cpython-39.pyc differ diff --git a/__pycache__/game.cpython-310.pyc b/__pycache__/game.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92f68563b050ace8a2347f3f8a25a5586e8979d3 Binary files /dev/null and b/__pycache__/game.cpython-310.pyc differ diff --git a/__pycache__/game.cpython-39.pyc b/__pycache__/game.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ea070589242a2d97c81113b0535a85dcdbaf060 Binary files /dev/null and b/__pycache__/game.cpython-39.pyc differ diff --git a/__pycache__/hud.cpython-310.pyc b/__pycache__/hud.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dfea83fdec5958948f1fe15a50dc7242c1fd248 Binary files /dev/null and b/__pycache__/hud.cpython-310.pyc differ diff --git a/__pycache__/hud.cpython-39.pyc b/__pycache__/hud.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..721f027800dc9939cb6e23fb3b738ef473fed014 Binary files /dev/null and b/__pycache__/hud.cpython-39.pyc differ diff --git a/__pycache__/map.cpython-310.pyc b/__pycache__/map.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d52144344ae8a7f0a75c826667846c8594be5ae Binary files /dev/null and b/__pycache__/map.cpython-310.pyc differ diff --git a/__pycache__/map.cpython-39.pyc b/__pycache__/map.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cdd57975158b20b4fb4a77791c73f9f9d93792a Binary files /dev/null and b/__pycache__/map.cpython-39.pyc differ diff --git a/__pycache__/menu.cpython-310.pyc b/__pycache__/menu.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2df5936e6762188379f56c19afa827a76488c3fa Binary files /dev/null and b/__pycache__/menu.cpython-310.pyc differ diff --git a/__pycache__/menu.cpython-39.pyc b/__pycache__/menu.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a55a4af82f10ff9550b02c883a1d4865e9f55522 Binary files /dev/null and b/__pycache__/menu.cpython-39.pyc differ diff --git a/__pycache__/scene.cpython-310.pyc b/__pycache__/scene.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db823ab004f7a9cc7d0168dd796198601d3c6045 Binary files /dev/null and b/__pycache__/scene.cpython-310.pyc differ diff --git a/__pycache__/scene.cpython-39.pyc b/__pycache__/scene.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31e3a1009ddabad9c5932eb1a987eb717de5bc20 Binary files /dev/null and b/__pycache__/scene.cpython-39.pyc differ diff --git a/__pycache__/snake.cpython-310.pyc b/__pycache__/snake.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48e878005eb394954ca33bb2c2986a4ca8b7aae6 Binary files /dev/null and b/__pycache__/snake.cpython-310.pyc differ diff --git a/__pycache__/snake.cpython-39.pyc b/__pycache__/snake.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84af4a84e97a3e5996653144fc4d1a2e80709864 Binary files /dev/null and b/__pycache__/snake.cpython-39.pyc differ diff --git a/config.py b/config.py index 49e5b56696d47f3459874ec2c533f14bdf1b9279..b24ac5800df7eaaedc84763d8d4f106b65cc8b7f 100644 --- a/config.py +++ b/config.py @@ -6,7 +6,7 @@ from math import * pygame.init() # 常用环境变量,分别是鼠标角度,x位置,y位置,以及是否按下 -env = {"mouse_direction": 0, "mouse_x": 0, "mouse_y": 0, "mouse_down": False} +env = {"mouse_direction": 0, "mouse_x": 0, "mouse_y": 0, "mouse_down": False, "key": ''} # 屏幕长宽,初始化屏幕 , pygame.HWSURFACE | pygame.FULLSCREEN screen_width, screen_height = 600, 400 diff --git a/enemy_snake.py b/enemy_snake.py new file mode 100644 index 0000000000000000000000000000000000000000..0c3cbc2dd1a99f9a90f2185f8452afc8f74b825d --- /dev/null +++ b/enemy_snake.py @@ -0,0 +1,157 @@ +from animations import * +from config import * + + +class Segment: + """ + 蛇的一段,中心在center,以angle角度摆放,宽度是width + """ + + def __init__(self, center, angle, width): + self.angle = angle + pi / 2 + self.width = width + self.center = center + self.draw_displacement = [0, 0] + self.update() + + # 设置宽度 + def set_width(self, width): + self.width = width + + # 根据角度更新蛇的绘制点 + def update(self): + self.draw_displacement[0] = cos(self.angle) * self.width + self.draw_displacement[1] = sin(self.angle) * self.width + + # 获取绘制点一 + def get_point1(self, offset): + return (self.center[0] + self.draw_displacement[0] + offset[0], + self.center[1] + self.draw_displacement[1] + offset[1]) + + # 获取绘制点二 + def get_point2(self, offset): + return (self.center[0] - self.draw_displacement[0] + offset[0], + self.center[1] - self.draw_displacement[1] + offset[1]) + + +class EnemySnake: + """ + 贪吃蛇本体,由许多Segment构成 + """ + + def __init__(self, game): + self.game = game + self.width = 10 + self.speed = 3 + self.segments = [] + self.direction = 0 + self.poly_points = [] + self.length = 0 + self.seg_width = [] + self.position = [100, 10] + self.turn_limit = pi / 3 + self.outofbound = False + self.color = (255, 0, 0) + + self.dead = False + + self.hit_points = [] + + # 设置当前蛇前进角度 + def set_direction(self, angle): + d_angle = (angle - self.direction) % (2 * pi) + if d_angle < self.turn_limit or d_angle > 2 * pi - self.turn_limit: + self.direction = angle + else: + turn_amount = self.turn_limit if d_angle < pi else -self.turn_limit + self.direction = (self.direction + turn_amount) % (2 * pi) + + # 在蛇前面加一个Segment,segment的宽由一个函数生成 + def increase_length(self): + self.length += 1 + self.seg_width.append(self.width) + if self.length > 1: + a = -(self.width / ((self.length - 1) * (self.length - 1))) + for i in range(self.length): + self.seg_width[self.length - i - 1] = a * (i * i) + self.width + + # 移动蛇的位置,用于更新offset + def move(self, dx, dy): + new_x = self.position[0] + dx + new_y = self.position[1] + dy + + # 获取游戏区域边界 + left_bound = -150 # 左边界 + right_bound = self.game.width - 150 # 右边界 + top_bound = -150 # 上边界 + bottom_bound = self.game.height - 150 # 下边界 + + # 检查新位置是否超出边界,并调整位置和方向 + if new_x <= left_bound: + new_x = left_bound + self.direction = random.uniform(0, pi) # 随机选择向右的新方向 + elif new_x >= right_bound: + new_x = right_bound + self.direction = random.uniform(pi, 2 * pi) # 随机选择向左的新方向 + + if new_y <= top_bound: + new_y = top_bound + self.direction = random.uniform(-pi / 2, pi / 2) # 随机选择向下的新方向 + elif new_y >= bottom_bound: + new_y = bottom_bound + self.direction = random.uniform(pi / 2, 3 * pi / 2) # 随机选择向上的新方向 + + # 更新蛇的位置 + self.position[0] = new_x + self.position[1] = new_y + + # 如果蛇的位置被调整到边界上,将其标记为超出边界 + self.outofbound = (new_x == left_bound or new_x == right_bound or + new_y == top_bound or new_y == bottom_bound) + + # 让蛇长长一节 + def grow(self): + self.add_head_segment() + self.increase_length() + self.add_head_segment() + self.increase_length() + + # 添加一个头部Segment + def add_head_segment(self): + self.move(cos(self.direction) * self.speed, sin(self.direction) * self.speed) + self.segments.append(Segment((self.position[0], self.position[1]), self.direction, self.width)) + self.hit_points.append((self.position[0], self.position[1])) + + # 移除一个尾部Segment + def remove_tail_segment(self): + del self.segments[0] + del self.hit_points[0] + + # 让蛇往前爬一次 + def crawl(self): + self.add_head_segment() + self.remove_tail_segment() + + # 碰撞检测 + def collide_with(self, snake): + for i in range(0, len(snake.hit_points), 2): + if get_distance(snake.hit_points[i], self.position) < self.width: + self.dead = True + return True + return False # 未发生碰撞,返回 False + + # 进行更新,更新Segment宽度,当前经验升级,更新血量信息,以及碰撞点与绘制点列表 + def update(self): + for i, segment in enumerate(self.segments): + segment.set_width(self.seg_width[i]) + segment.update() + + self.poly_points = [segment.get_point1(self.game.get_offset()) for segment in self.segments] + self.poly_points.extend(segment.get_point2(self.game.get_offset()) for segment in reversed(self.segments)) + + # 使用多边形方法绘制蛇 + def draw(self): + pygame.draw.polygon(screen, self.color, self.poly_points) + pygame.draw.circle(screen, self.color, (int(self.position[0] + self.game.get_offset()[0]), + int(self.position[1] + self.game.get_offset()[1])), + self.width + 2) diff --git a/fights.py b/fights.py index 90d382b22fd6dcb3c96e96daf1dc9bffdbf03daf..e778a3aba3c90cd15a1575fe7ed1468338d96932 100644 --- a/fights.py +++ b/fights.py @@ -237,11 +237,22 @@ class ExpBall: self.pos = pos self.points = points self.cycle = Cycle(4, 6) + self.texture_types = ["food", "banana"] # 绘制经验球 +# def draw(self, offset): +# screen.blit(texture_lib["food"], (self.pos[0] + offset[0] - 22, self.pos[1] + offset[1] - 22), +# pygame.Rect(0, self.cycle.get()*45, 45, 45)) + +# def draw(self, offset): +# screen.blit(texture_lib["banana"], (self.pos[0] + offset[0] - 22, self.pos[1] + offset[1] - 22),) + def draw(self, offset): + print("Drawing food") + # 绘制"food"纹理 screen.blit(texture_lib["food"], (self.pos[0] + offset[0] - 22, self.pos[1] + offset[1] - 22), - pygame.Rect(0, self.cycle.get()*45, 45, 45)) + pygame.Rect(0, self.cycle.get() * 45, 45, 45)) + class OneCanon: diff --git a/game.py b/game.py index 53d13c6bb139255f3fd35d9ffad2eaa099081173..e5fdaffb48806641a5771c3ce72bdb53797975ea 100644 --- a/game.py +++ b/game.py @@ -4,6 +4,21 @@ from hud import * from menu import * from chat import * from scene import * +from enemy_snake import * +import random +import time + + +# 生成随机方向角度 +def generate_random_angles(num_snakes): + angles = [] + current_time = int(time.time() // 2) + for i in range(num_snakes): + seed = current_time + i # 为每条小蛇生成唯一的种子 + random.seed(seed) # 设置种子 + angle = random.uniform(0, 2 * pi) # 生成随机角度 + angles.append(angle) + return angles class Game: @@ -11,24 +26,28 @@ class Game: 游戏主题,一共有六个阶段:主菜单,关卡选择,对话场景,关卡显示场景,关卡进行,关卡结果场景 可以根据current_level来改变当前关卡,用于继续上次游戏 """ + def __init__(self, current_level=0): + self.width=300 + self.height=300 self.snake_move_cycle = Cycle(2, 1) self.current_level = current_level self.current_playing = 0 - self.map = None - self.snake = None - + self.snake2 = None # 玩家小蛇2 + self.enemy = [] # 敌人小蛇 self.scene = None - self.info_hud = None - + self.info_hud2 = None self.menu = MainMenu() - self.shaking = [False, False] self.shake_cycle = [ReCycle(15, 1), ReCycle(15, 1)] self.shake_countdown = [0, 0] + self.snake_base_speed = 7 + + # 新属性,用于追踪暂停状态 + self.paused = False # 摇晃当前屏幕,特效 def shake(self, direction, dur_t): @@ -42,16 +61,16 @@ class Game: # 获取当前渲染offset,为了让屏幕随着蛇移动 def get_offset(self): if self.shaking[0] and self.shaking[1]: - return self.shake_cycle[0].get()-int(self.snake.position[0] - screen_width/2), \ - self.shake_cycle[1].get()-int(self.snake.position[1] - screen_height/2) + return self.shake_cycle[0].get() - int(self.snake.position[0] - screen_width / 2), \ + self.shake_cycle[1].get() - int(self.snake.position[1] - screen_height / 2) elif self.shaking[0]: - return self.shake_cycle[0].get()-int(self.snake.position[0] - screen_width/2), \ - -int(self.snake.position[1] - screen_height/2) + return self.shake_cycle[0].get() - int(self.snake.position[0] - screen_width / 2), \ + -int(self.snake.position[1] - screen_height / 2) elif self.shaking[1]: - return -int(self.snake.position[0] - screen_width/2), \ - self.shake_cycle[1].get()-int(self.snake.position[1] - screen_height/2) - return -int(self.snake.position[0] - screen_width/2), \ - -int(self.snake.position[1] - screen_height/2) + return -int(self.snake.position[0] - screen_width / 2), \ + self.shake_cycle[1].get() - int(self.snake.position[1] - screen_height / 2) + return -int(self.snake.position[0] - screen_width / 2), \ + -int(self.snake.position[1] - screen_height / 2) # 开始一个场景 def start_scene(self, scene): @@ -61,9 +80,25 @@ class Game: def start(self, level=7): self.menu = None self.snake = Snake(self) + # 生成玩家小蛇2 + self.snake2 = Snake(self) + self.snake2.color = (191, 213, 255) + self.snake2.common_color = (191, 213, 255) + for i in range(5): + # 生成5条敌人小蛇 + self.enemy.append(EnemySnake(self)) for _ in range(5): self.snake.grow() + self.snake2.grow() + # 生成敌人小蛇 + for i in range(len(self.enemy)): + self.enemy[i].grow() + self.info_hud = InfoBar(self.snake) + self.info_hud2 = InfoBar(self.snake2) + self.info_hud2.level_pos = (30, 50) + self.info_hud2.exp_bar = (6, 10) + self.info_hud2.hp_bar = (150, 300) if level == 1: self.map = Level1(self) elif level == 2: @@ -81,8 +116,14 @@ class Game: elif level == 8: self.map = Level8(self) self.map.set_snake(self.snake) + # 设置玩家小蛇2 + self.map.set_snake2(self.snake2) self.update() - self.start_scene(TalkScene("snake_1", "snake_2", level_chats[level-1])) + # 设置和更新敌人小蛇 + self.map.set_enemy(self.enemy) + for i in range(5): + self.enemy[i].update() + self.start_scene(TalkScene("snake_1", "snake_2", level_chats[level - 1])) bgs[3].play_non_stop() # 绘制当前状态,菜单优先,其次场景,最后是游戏本身 @@ -92,9 +133,17 @@ class Game: elif not self.scene: self.map.draw_background(self.get_offset()) self.snake.draw() + + # 画出玩家小蛇2 + self.snake2.draw() + + # 画出敌人小蛇 + for i in range(5): + self.enemy[i].draw() self.map.draw(self.get_offset()) self.info_hud.draw() + self.info_hud2.draw() else: if self.scene.name == "text" or self.scene.name == "level": self.map.draw(self.get_offset()) @@ -102,12 +151,17 @@ class Game: # 触发成员的键盘鼠标事件,并且根据返回的值来更新自己的状态 def handle_event(self, event): + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_t: + # 切换暂停状态 + self.paused = not self.paused + if self.menu: result = self.menu.handle_event(event) if result != -1: if result >= 0: self.current_playing = result - self.start(result+1) + self.start(result + 1) else: if result == -3: self.menu = LevelSelect(self.current_level) @@ -117,43 +171,117 @@ class Game: elif not self.scene: pass else: - self.scene.handle_event(event) + if not self.paused: + self.scene.handle_event(event) + + if self.snake: + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_LSHIFT: + self.snake.speed = 5 * self.snake_base_speed + if event.key == pygame.K_q: + self.snake.hp = 100 + elif event.type == pygame.KEYUP: + if event.key == pygame.K_LSHIFT: + self.snake.speed = self.snake_base_speed + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + self.snake_move_cycle = Cycle(2, 1) + self.current_playing = 0 + self.map = None + self.snake = None + self.scene = None + self.info_hud = None + self.info_hud2 = None + self.menu = MainMenu() + self.shaking = [False, False] + self.shake_cycle = [ReCycle(15, 1), ReCycle(15, 1)] + self.shake_countdown = [0, 0] + self.snake_base_speed = 7 # 更新当前状态,菜单优先,其次场景,最后是游戏本身。同时处理屏幕摇晃,根据结束场景开始游戏或者开始另外一个场景。 def update(self): if not self.scene and self.menu: self.menu.update() elif not self.scene: - self.snake.set_direction(env["mouse_direction"]) - self.map.update() - - if self.snake_move_cycle.get() == 0: - self.snake.crawl() - self.snake.update() - - self.info_hud.update() - if self.map.is_dead(): - self.menu = LevelSelect(self.current_level) - self.scene = TextScene("lose_text") - elif self.map.is_passed() and self.current_level == self.current_playing: - self.current_level += 1 - self.menu = LevelSelect(self.current_level) - self.scene = TextScene("win_text") - elif self.map.is_passed(): - self.menu = LevelSelect(self.current_level) - self.scene = TextScene("win_text") + if not self.paused: + self.snake.set_direction(env["mouse_direction"]) + + # 玩家小蛇2设置方向 + if env["key"] == 'w': + self.snake2.direction = 3 * pi / 2 + elif env["key"] == 'd': + self.snake2.direction = 0 + elif env["key"] == 's': + self.snake2.direction = pi / 2 + elif env["key"] == 'a': + self.snake2.direction = pi + + # 为敌人小蛇设置方向,方向由generate_random_angles函数随机生成 + for i in range(5): + self.enemy[i].set_direction(generate_random_angles(len(self.enemy))[i]) + self.map.update() + + if self.snake_move_cycle.get() == 0: + self.snake.crawl() + # 移动玩家小蛇2 + self.snake2.crawl() + self.snake.update() + # 更新玩家小蛇2 + self.snake2.update() + + # 让敌人小蛇移动 + for i in range(len(self.enemy)): + if self.snake_move_cycle.get() == 0: + self.enemy[i].crawl() + self.enemy[i].update() + + self.info_hud.update() + self.info_hud2.update() + if self.map.is_dead2() != 3: + self.menu = LevelSelect(self.current_level) + if self.map.is_dead2() == 1: + self.scene = TextScene("player2_win") + else: + self.scene = TextScene("player1_win") + elif self.map.is_passed2() != 3 and self.current_level == self.current_playing: + self.current_level += 1 + self.menu = LevelSelect(self.current_level) + if self.map.is_passed2() == 1: + self.scene = TextScene("player1_win") + else: + self.scene = TextScene("player2_win") + # self.scene = TextScene("win_text") + elif self.map.is_passed2() != 3: + self.menu = LevelSelect(self.current_level) + if self.map.is_passed2() == 1: + self.scene = TextScene("player1_win") + else: + self.scene = TextScene("player2_win") + # if self.map.is_dead(): + # self.menu = LevelSelect(self.current_level) + # self.scene = TextScene("lose_text") + # elif self.map.is_passed() and self.current_level == self.current_playing: + # self.current_level += 1 + # self.menu = LevelSelect(self.current_level) + # self.scene = TextScene("win_text") + # elif self.map.is_passed(): + # self.menu = LevelSelect(self.current_level) + # self.scene = TextScene("win_text") + else: - self.scene.update() - if self.scene.is_ended(): - if self.scene.name == "chat": - m = random.randint(0, 1) - if m == 0: - bgs[1].play_non_stop() + if not self.paused: + self.scene.update() + if self.scene.is_ended(): + if self.scene.name == "chat": + m = random.randint(0, 1) + if m == 0: + bgs[1].play_non_stop() + else: + bgs[2].play_non_stop() + self.scene = LevelNum(self.current_playing + 1) else: - bgs[2].play_non_stop() - self.scene = LevelNum(self.current_playing+1) - else: - self.scene = None + self.scene = None if self.shaking[0]: self.shake_countdown[0] -= 1 @@ -163,3 +291,4 @@ class Game: self.shake_countdown[1] -= 1 if self.shake_countdown[1] <= 0: self.shaking[1] = False + diff --git a/hud.py b/hud.py index 14ae4ba7b3f1a15dd396a9cbc330672cf1f3808f..c19b831d330bc1da60b326c1a7bf482dd2a1c034 100644 --- a/hud.py +++ b/hud.py @@ -8,7 +8,10 @@ class InfoBar: def __init__(self, snake): self.snake = snake self.hp_lag = 300 - + # 设置UI位置 + self.level_pos = (30, 15) + self.exp_bar = (6, 50) + self.hp_bar = (150, 370) self.level_text = None self.update() @@ -19,13 +22,12 @@ class InfoBar: self.hp_lag -= 2 else: self.hp_lag = self.snake.hp*3 - # 将当前数值绘制出来 def draw(self): - screen.blit(self.level_text, (30, 15)) - screen.blit(texture_lib["exp_bar"], (6, 50), pygame.Rect(0, 10, self.snake.current_exp, 10)) - screen.blit(texture_lib["exp_bar"], (6, 50), pygame.Rect(0, 0, 100, 10)) - screen.fill(-1, pygame.Rect(150, 370, self.hp_lag, 20)) - screen.blit(texture_lib["hp_bar"], (150, 370), + screen.blit(self.level_text, self.level_pos) + screen.blit(texture_lib["exp_bar"], self.exp_bar, pygame.Rect(0, 10, self.snake.current_exp, 10)) + screen.blit(texture_lib["exp_bar"], self.exp_bar, pygame.Rect(0, 0, 100, 10)) + screen.fill(-1, pygame.Rect(self.hp_bar[0], self.hp_bar[1], self.hp_lag, 20)) + screen.blit(texture_lib["hp_bar"], self.hp_bar, pygame.Rect(300 - self.snake.hp * 3, 20, self.snake.hp * 3, 20)) - screen.blit(texture_lib["hp_bar"], (150, 370), pygame.Rect(0, 0, 300, 20)) + screen.blit(texture_lib["hp_bar"], self.hp_bar, pygame.Rect(0, 0, 300, 20)) diff --git a/main.py b/main.py index f16bfc0946275f8a373674e9a7e4ec4b085043f7..07d31f3f42e5f7f80c0e3ecda3b99a24bf535dc2 100644 --- a/main.py +++ b/main.py @@ -23,6 +23,18 @@ while True: f.close() pygame.quit() sys.exit() + + # 键盘事件,更新小蛇移动方向 + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_w: + env["key"] = 'w' + elif event.key == pygame.K_d: + env["key"] = 'd' + elif event.key == pygame.K_s: + env["key"] = 's' + elif event.key == pygame.K_a: + env["key"] = 'a' + # 鼠标事件,更新环境变量 if event.type == pygame.MOUSEMOTION: env["mouse_x"] = pygame.mouse.get_pos()[0] diff --git a/map.py b/map.py index 3c7c79f0034b74f967d1811f25da4667deae2c63..2521577efcd0e6d36dd30cfd64e047d37a41db05 100644 --- a/map.py +++ b/map.py @@ -5,6 +5,7 @@ class Level: """ 关卡父类 """ + def __init__(self): pass @@ -18,6 +19,7 @@ class Map(Level): 地图,存储数据有所有攻击,经验球,动画以及物品(大炮,激光炮等) per_exp为每个经验球的经验,food_count是场上经验球数量,pass_level是过关等级 """ + def __init__(self, game): Level.__init__(self) self.game = game @@ -25,6 +27,8 @@ class Map(Level): self.exp_balls = [] self.deme = [300, 300] self.snake = None + self.snake2 = None # 玩家小蛇2 + self.enemy = [] # 敌人小蛇 self.attacks = [] self.food_count = 5 self.per_exp = 10 @@ -34,10 +38,23 @@ class Map(Level): self.animations = [] + self.exp_balls = [] + self.exp_balls_count = 0 + if random.random() > 0.98: + self.hp_balls_count = random.randint(1, 3) + # 判断当前蛇是否死亡 def is_dead(self): return self.snake.hp < 0 + # 判断是否有玩家死亡 + def is_dead2(self): + if self.snake.hp < 0: + return 1 + elif self.snake2.hp < 0: + return 2 + return 3 + # 绘制四周边框,是动画 def draw_boarder(self, offset): c = self.boarder_cycle.get() @@ -94,6 +111,14 @@ class Map(Level): def set_snake(self, snake): self.snake = snake + # 设置玩家小蛇2 + def set_snake2(self, snake): + self.snake2 = snake + + # 设置敌人小蛇 + def set_enemy(self, enemy): + self.enemy = enemy + # 绘制背景底色 def draw_background(self, offset): pygame.draw.rect(screen, (70, 70, 70), @@ -102,51 +127,72 @@ class Map(Level): # 绘制地图上的所有物件 def draw(self, offset): - for i in range(len(self.exp_balls)-1, -1, -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): + 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)) + # 小蛇2危险状态 + if self.snake2.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)) + 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): + 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.exp_balls) - 1, -1, -1): + if get_distance(self.snake2.position, self.exp_balls[i].pos) < 20: + self.snake2.current_exp += self.exp_balls[i].points + ses[2].play_once() + del self.exp_balls[i] + # 敌人小蛇碰撞检测 + for i in range(len(self.enemy) - 1, -1, -1): + if self.enemy[i].collide_with(self.snake): + self.snake.hp -= 2 + if self.enemy[i].collide_with(self.snake2): + self.snake2.hp -= 2 + #玩家小蛇一与玩家小蛇二碰撞检测 + for i in range(len(self.enemy) - 1, -1, -1): + if self.snake.collide_with(self.snake2): + self.snake.hp -= 0.01 + self.snake2.hp-=0.01 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): + 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].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): + for i in range(len(self.objects) - 1, -1, -1): self.objects[i].update() if self.objects[i].dead: del self.objects[i] @@ -163,17 +209,33 @@ class Map(Level): else: self.snake.outofbound = False + if (self.snake2.position[0] < -self.deme[0] or + self.snake2.position[0] > self.deme[0] or + self.snake2.position[1] < -self.deme[1] or + self.snake2.position[1] > self.deme[1]): + self.snake2.outofbound = True + else: + self.snake2.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_passed2(self): + if self.snake.level >= self.pass_level: + return 1 + if self.snake2.level >= self.pass_level: + return 2 + return 3 + # 同父类 def is_passed(self): if self.snake.level >= self.pass_level: @@ -189,6 +251,7 @@ class Level2(Map): """ 第二关,有两个大炮 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 250 @@ -209,10 +272,10 @@ class Level2(Map): 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) + 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) + self.add_bullet((self.objects[1].pos[0] + 70, self.objects[1].pos[1] + 40), (5, 0), 15, 10) ses[5].play_once() @@ -220,6 +283,7 @@ class Level3(Map): """ 第三关,一个十字激光 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 300 @@ -247,6 +311,7 @@ class Level4(Map): """ 第四关,一个移动激光 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 350 @@ -297,6 +362,7 @@ class Level5(Map): """ 第五关,有一个旋转激光 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 400 @@ -323,6 +389,7 @@ class Level6(Map): """ 第六关,有一个巨型激光 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 300 @@ -366,6 +433,7 @@ class Level7(Map): """ 第七关,有四条随机横向或者竖向的激光 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 400 @@ -394,13 +462,13 @@ class Level7(Map): 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: + 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: + 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: + 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: @@ -423,6 +491,7 @@ class Level8(Map): """ 第八关,每吃一个果子升一级,可以(基本上)无限玩下去 """ + def __init__(self, game): Map.__init__(self, game) self.deme[0] = 400 diff --git a/scene.py b/scene.py index 02cc592e0871e7d089a1d6493fe2228b4e1a4412..9d85269a1a9dfeee70f946e495178d209bba44ce 100644 --- a/scene.py +++ b/scene.py @@ -108,6 +108,14 @@ class TalkScene: # 处理鼠标点击事件,左击可快速跳过对话 def handle_event(self, event): + if event.type == pygame.KEYUP and event.key == pygame.K_SPACE: + # 通过清空对话列表来跳过所有剩余对话 + self.chats = [] + # 如果当前存在对话框,标记为结束以继续下一个场景 + if self.current_chat: + self.current_chat.dead = True + ses[7].play_once() + if self.current_chat: if event.type == pygame.MOUSEBUTTONUP: if self.current_chat.stage == 1: @@ -123,7 +131,7 @@ class TalkScene: if not self.chats and (not self.current_chat or self.current_chat.dead): self.stage_tick = 0 self.stage += 1 - elif self.current_chat.dead: + elif self.current_chat and self.current_chat.dead: self.next_chat() else: self.stage_tick += 1 @@ -135,18 +143,22 @@ class TalkScene: def draw(self): if self.stage == 0: if self.stage_tick < 25: - screen.blit(texture_lib[self.c1], (self.stage_tick * 12 - 300, 250)) + x1 = self.stage_tick * 12 - 300 + x2 = 600 - (self.stage_tick - 25) * 12 else: - screen.blit(texture_lib[self.c1], (0, 250)) - screen.blit(texture_lib[self.c2], (600 - (self.stage_tick - 25) * 12, 250)) - + x1 = 0 + x2 = 600 + screen.blit(texture_lib[self.c1], (x1, 250)) + screen.blit(texture_lib[self.c2], (x2, 250)) elif self.stage == 1: self.current_chat.draw() screen.blit(texture_lib[self.c1], (0, 250)) screen.blit(texture_lib[self.c2], (300, 250)) elif self.stage == 2: - screen.blit(texture_lib[self.c1], (-self.stage_tick * 13, 250)) - screen.blit(texture_lib[self.c2], (300 + self.stage_tick * 13, 250)) + x1 = -self.stage_tick * 13 + x2 = 300 + self.stage_tick * 13 + screen.blit(texture_lib[self.c1], (x1, 250)) + screen.blit(texture_lib[self.c2], (x2, 250)) else: screen.blit(texture_lib[self.c1], (0, 250)) screen.blit(texture_lib[self.c2], (300, 250)) diff --git a/screenshots/enemy_snake.png b/screenshots/enemy_snake.png new file mode 100644 index 0000000000000000000000000000000000000000..fe6fca18a6281515e3fe247e0f7eb3a6d780694c Binary files /dev/null and b/screenshots/enemy_snake.png differ diff --git a/screenshots/twoplayers.png b/screenshots/twoplayers.png new file mode 100644 index 0000000000000000000000000000000000000000..5f67352f956f232689a60de19405dae4877dfb80 Binary files /dev/null and b/screenshots/twoplayers.png differ diff --git a/snake.py b/snake.py index bd9f421f76f321e09ec136ef3c8fd0809cd07c6d..c56e850f551b96a118fcc48b4f7cfda939b029f2 100644 --- a/snake.py +++ b/snake.py @@ -49,6 +49,7 @@ class Snake: self.turn_limit = pi/3 self.outofbound = False self.color = (255, 255, 255) + self.common_color = (255, 255, 255) self.level = 1 self.current_exp = 0 @@ -107,15 +108,12 @@ class Snake: # 进行更新,更新Segment宽度,当前经验升级,更新血量信息,以及碰撞点与绘制点列表 def update(self): - for i in range(self.length): - self.segments[i].set_width(self.seg_width[i]) - self.segments[i].update() + for segment, width in zip(self.segments, self.seg_width): + segment.set_width(width) + segment.update() - del self.poly_points[:] - for seg in self.segments: - self.poly_points.append(seg.get_point1(self.game.get_offset())) - for i in range(self.length - 1, -1, -1): - self.poly_points.append(self.segments[i].get_point2(self.game.get_offset())) + self.poly_points = [seg.get_point1(self.game.get_offset()) for seg in self.segments] + self.poly_points.extend(seg.get_point2(self.game.get_offset()) for seg in reversed(self.segments)) if self.current_exp > 100: ses[4].play_once() @@ -134,9 +132,15 @@ class Snake: if self.pre_hp > self.hp: self.color = (255, 100, 100) else: - self.color = (255, 255, 255) + self.color = self.common_color self.pre_hp = self.hp - + #不同玩家小蛇碰撞检测 + def collide_with(self, snake): + for i in range(0, len(snake.hit_points), 2): + if get_distance(snake.hit_points[i], self.position) < self.width: + self.dead = True + return True + return False # 未发生碰撞,返回 False # 使用多边形方法绘制蛇 def draw(self): pygame.draw.polygon(screen, self.color, self.poly_points) diff --git a/texture/banana.png b/texture/banana.png new file mode 100644 index 0000000000000000000000000000000000000000..c222b7a94abfae120da78bbf7e0eb1bc8eba32a0 Binary files /dev/null and b/texture/banana.png differ diff --git a/texture/player1_win.png b/texture/player1_win.png new file mode 100644 index 0000000000000000000000000000000000000000..64f8d818150923f71e3bc532c06154738be66aa5 Binary files /dev/null and b/texture/player1_win.png differ diff --git a/texture/player2_win.png b/texture/player2_win.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7cc5701ced6471231961832f252d6cc189a853 Binary files /dev/null and b/texture/player2_win.png differ diff --git a/~$2101010.md b/~$2101010.md new file mode 100644 index 0000000000000000000000000000000000000000..83b2c3a4b3bf39d5351e03ca18ff2f0967d140c0 Binary files /dev/null and b/~$2101010.md differ