免费网站打包app,怎样建立自己的网站,石景山网站seo优化排名,wordpress中文手册导语
你是否想过用Python开发一款可玩性高的双人合作游戏#xff1f;本文将分享如何从零开始实现一款类《吸血鬼幸存者》的生存射击游戏#xff01;包含完整源码解析、角色系统设计、敌人AI逻辑等核心技术点#xff0c;文末提供完整代码包下载#xff01; 哈…导语
你是否想过用Python开发一款可玩性高的双人合作游戏本文将分享如何从零开始实现一款类《吸血鬼幸存者》的生存射击游戏包含完整源码解析、角色系统设计、敌人AI逻辑等核心技术点文末提供完整代码包下载 哈哈怪物可以换成同学 的qq头像
游戏内容如下 一、游戏展示 核心功能 游戏截图/GIF动图 建议添加游戏实际运行画面展示双人操作、敌人生成、技能特效等 核心玩法特性 双人本地合作模式WASD vs 方向键控制两种可选角色四方向攻击 vs 对角线攻击动态敌人系统普通敌人 精英Boss角色成长体系经验值升级/属性强化时间限制生存模式5分钟倒计时 二、技术实现亮点 技术栈 语言Python 3.x核心库PyGame开发周期约10小时 关键技术点 - 精灵(Sprite)系统玩家/敌人/子弹的统一管理
- 基于三角函数的子弹轨迹计算8方向射击
- 敌人AI自动追踪玩家 精英怪弹幕攻击
- 动态难度系统敌人生成速度随玩家等级提升
- 经验球漂浮动画正弦函数实现
- 多菜单系统主菜单/角色选择/游戏内HUD 三、代码结构解析
python
# 代码模块示意图
├── Assets/ # 资源文件夹
│ ├── image/ # 游戏素材角色/敌人/背景图
├── main.py # 主程序入口
│ ├── 核心类
│ │ - Player # 玩家角色移动/攻击/成长
│ │ - Enemy # 基础敌人AI
│ │ - EliteEnemy # 精英Boss弹幕攻击
│ │ - Bullet # 子弹物理系统
│ │ - Button # 交互式GUI按钮
│ ├── 游戏流程
│ │ - main_menu() # 主菜单
│ │ - role_selection() # 角色选择
│ │ - game_loop() # 核心游戏循环 四、关键代码解读 角色控制系统 python class Player(pygame.sprite.Sprite):def get_attack_directions(self):# 角色1四方向射击 | 角色2对角线射击return [up, down, left, right] if self.role_type 1 else [up_left, up_right, ...] 精英敌人弹幕算法 python class EliteEnemy(Enemy):def shoot(self, target):# 45度间隔的8方向弹幕for angle in range(0, 360, 45):rad math.radians(angle)bullet EliteBullet(..., math.cos(rad)*speed, math.sin(rad)*speed) 动态难度机制 python # 敌人生成速度随玩家等级提升
enemy_spawn_interval 60 - (sum(p.level for p in players) * 2) 五、如何运行游戏 环境准备 bash pip install pygame 文件结构要求 project/
├── main.py
└── image/├── role1.png # 角色1素材├── enemy.png # 敌人素材└── ... 启动命令 bash python main.py 六、开发心得 优化方向 踩坑经验 PyGame精灵组的碰撞检测优化双人模式下的事件冲突处理游戏节奏平衡性调试 待优化项 添加音效系统实现网络联机功能增加更多角色/技能树开发关卡编辑器 七、完整代码获取
关注私信回复【生存游戏】获取完整代码包和素材资源
骗你的代码就在这复制就能用
# -*- coding: utf-8 -*-
import os
import pygame
import random
import math# 初始化配置
BASE_DIR os.path.dirname(os.path.abspath(__file__))
IMAGE_DIR os.path.join(BASE_DIR, image)RESOURCES {role1: os.path.join(IMAGE_DIR, role1.png),role2: os.path.join(IMAGE_DIR, role2.png),enemy: os.path.join(IMAGE_DIR, enemy.png),elite: os.path.join(IMAGE_DIR, elite.png),bullet: os.path.join(IMAGE_DIR, bullet.png),exp_orb: os.path.join(IMAGE_DIR, exp_orb.png),background: os.path.join(IMAGE_DIR, background.png)
}pygame.init()
WIDTH, HEIGHT 800, 600
screen pygame.display.set_mode((WIDTH, HEIGHT))
clock pygame.time.Clock()# 颜色定义
WHITE (255, 255, 255)
GRAY (100, 100, 100)
BUTTON_COLOR (50, 150, 50)
HOVER_COLOR (70, 170, 70)
RED (255, 0, 0)
YELLOW (255, 255, 0)
ELITE_BULLET_COLOR (255, 165, 0)font pygame.font.Font(None, 24)def load_image(path, default_size(30, 30)):try:image pygame.image.load(path).convert_alpha()return pygame.transform.scale(image, default_size)except:surf pygame.Surface(default_size)surf.fill(RED)return surfGAME_IMAGES {role1: load_image(RESOURCES[role1]),role2: load_image(RESOURCES[role2]),enemy: load_image(RESOURCES[enemy], (20, 20)),elite: load_image(RESOURCES[elite], (40, 40)),bullet: load_image(RESOURCES[bullet], (10, 10)),exp_orb: load_image(RESOURCES[exp_orb], (10, 10)),background: load_image(RESOURCES[background], (WIDTH, HEIGHT))
}class Button:def __init__(self, text, x, y, w, h):self.rect pygame.Rect(x, y, w, h)self.text textself.color BUTTON_COLORself.hover Falsedef draw(self, surface):color HOVER_COLOR if self.hover else BUTTON_COLORpygame.draw.rect(surface, color, self.rect, border_radius5)text_surf font.render(self.text, True, WHITE)text_rect text_surf.get_rect(centerself.rect.center)surface.blit(text_surf, text_rect)def check_hover(self, mouse_pos):self.hover self.rect.collidepoint(mouse_pos)class Player(pygame.sprite.Sprite):def __init__(self, controls, role_type, pos_offset0, is_player2False):super().__init__()self.role_type role_typeself.image GAME_IMAGES[role2 if role_type 2 else role1]self.rect self.image.get_rect(center(WIDTH // 2 pos_offset, HEIGHT // 2))self.speed 5self.health 100self.exp 0self.level 1self.max_exp 100self.kills 0self.controls controlsdef update(self, keys):if keys[self.controls[up]]: self.rect.y - self.speedif keys[self.controls[down]]: self.rect.y self.speedif keys[self.controls[left]]: self.rect.x - self.speedif keys[self.controls[right]]: self.rect.x self.speedself.rect.clamp_ip(screen.get_rect())def get_attack_directions(self):return [up, down, left, right] if self.role_type 1 else [up_left, up_right, down_left,down_right]class Bullet(pygame.sprite.Sprite):def __init__(self, x, y, direction):super().__init__()self.image GAME_IMAGES[bullet]self.rect self.image.get_rect(center(x, y))self.speed 8self.start_pos (x, y)self.max_distance 300self.penetration 2dir_mapping {up: (0, -1), down: (0, 1),left: (-1, 0), right: (1, 0),up_left: (-math.sqrt(0.5), -math.sqrt(0.5)),up_right: (math.sqrt(0.5), -math.sqrt(0.5)),down_left: (-math.sqrt(0.5), math.sqrt(0.5)),down_right: (math.sqrt(0.5), math.sqrt(0.5))}dx_mult, dy_mult dir_mapping[direction]self.dx dx_mult * self.speedself.dy dy_mult * self.speeddef update(self):self.rect.x self.dxself.rect.y self.dyif math.hypot(self.rect.x - self.start_pos[0], self.rect.y - self.start_pos[1]) self.max_distance:self.kill()class Enemy(pygame.sprite.Sprite):def __init__(self):super().__init__()self.image GAME_IMAGES[enemy]self.rect self.image.get_rect(center(random.choice([-100, WIDTH 100]), random.randint(0, HEIGHT)))self.speed 2def update(self, targets):if not targets: returnnearest min(targets, keylambda t: math.hypot(t.rect.x - self.rect.x, t.rect.y - self.rect.y))dx nearest.rect.x - self.rect.xdy nearest.rect.y - self.rect.ydist math.hypot(dx, dy)if dist ! 0:self.rect.x dx / dist * self.speedself.rect.y dy / dist * self.speedclass EliteEnemy(pygame.sprite.Sprite):def __init__(self):super().__init__()self.image GAME_IMAGES[elite]self.rect self.image.get_rect(center(random.choice([-100, WIDTH 100]), random.randint(0, HEIGHT)))self.speed 1.5self.health 50self.max_health 50self.shoot_timer 0self.bullet_speed 5def update(self, targets):if not targets: returnnearest min(targets, keylambda t: math.hypot(t.rect.x - self.rect.x, t.rect.y - self.rect.y))dx nearest.rect.x - self.rect.xdy nearest.rect.y - self.rect.ydist math.hypot(dx, dy)if dist ! 0:self.rect.x dx / dist * self.speedself.rect.y dy / dist * self.speedself.shoot_timer 1if self.shoot_timer 60:self.shoot(nearest)self.shoot_timer 0def shoot(self, target):for angle in range(0, 360, 45):rad math.radians(angle)bullet EliteBullet(self.rect.centerx,self.rect.centery,math.cos(rad) * self.bullet_speed,math.sin(rad) * self.bullet_speed)bullets.add(bullet)all_sprites.add(bullet)class EliteBullet(pygame.sprite.Sprite):def __init__(self, x, y, dx, dy):super().__init__()self.image pygame.Surface((15, 15))self.image.fill(ELITE_BULLET_COLOR)self.rect self.image.get_rect(center(x, y))self.dx dxself.dy dyself.max_distance 400self.start_pos (x, y)def update(self):self.rect.x self.dxself.rect.y self.dyif math.hypot(self.rect.x - self.start_pos[0], self.rect.y - self.start_pos[1]) self.max_distance:self.kill()class ExpOrb(pygame.sprite.Sprite):def __init__(self, x, y):super().__init__()self.image GAME_IMAGES[exp_orb]self.rect self.image.get_rect(center(x, y))self.float_timer 0def update(self):self.float_timer 1self.rect.y math.sin(self.float_timer * 0.1) * 0.5def draw_hud(surface, players, time_left):time_text font.render(fTime: {time_left // 60:02}:{time_left % 60:02}, True, WHITE)surface.blit(time_text, (WIDTH // 2 - 60, 10))for i, player in enumerate(players):y_offset 40 i * 80pygame.draw.rect(surface, GRAY, (10, y_offset, 100, 10))health_width int((player.health / 100.0) * 100)pygame.draw.rect(surface, RED, (10, y_offset, health_width, 10))pygame.draw.rect(surface, GRAY, (10, y_offset 20, 100, 10))exp_width int((player.exp / float(player.max_exp)) * 100)pygame.draw.rect(surface, YELLOW, (10, y_offset 20, exp_width, 10))info_text font.render(fP{i 1} Lv{player.level} K{player.kills}, True, WHITE)surface.blit(info_text, (10, y_offset 40))def role_selection_menu(player_count):roles []buttons []descriptions [Role 1: 4-Direction Attack,Role 2: Diagonal Attack]for i in range(player_count):y_base 150 i * 150buttons.append([Button(fPlayer{i 1} Role1, WIDTH // 2 - 250, y_base, 200, 50),Button(fPlayer{i 1} Role2, WIDTH // 2 50, y_base, 200, 50)])confirm_btn Button(Start Game, WIDTH // 2 - 100, HEIGHT - 100, 200, 50)while True:screen.fill((30, 30, 30))mouse_pos pygame.mouse.get_pos()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()return []if event.type pygame.MOUSEBUTTONDOWN:for i, pair in enumerate(buttons):for j, btn in enumerate(pair):if btn.rect.collidepoint(mouse_pos):roles roles[:i] [j 1] roles[i 1:] if len(roles) i else roles [j 1]if confirm_btn.rect.collidepoint(mouse_pos) and len(roles) player_count:return rolesdesc_y 100for desc in descriptions:text font.render(desc, True, WHITE)screen.blit(text, (WIDTH // 2 - text.get_width() // 2, desc_y))desc_y 30for i, pair in enumerate(buttons):for j, btn in enumerate(pair):btn.check_hover(mouse_pos)btn.draw(screen)if i len(roles) and roles[i] j 1:pygame.draw.rect(screen, YELLOW, btn.rect.inflate(10, 10), 3, border_radius7)confirm_btn.check_hover(mouse_pos)confirm_btn.draw(screen)pygame.display.flip()clock.tick(30)def main_menu():buttons [Button(1 Player, WIDTH // 2 - 100, HEIGHT // 2 - 50, 200, 50),Button(2 Players, WIDTH // 2 - 100, HEIGHT // 2 20, 200, 50)]while True:screen.fill((30, 30, 30))mouse_pos pygame.mouse.get_pos()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()return (0, [])if event.type pygame.MOUSEBUTTONDOWN:for i, btn in enumerate(buttons):if btn.rect.collidepoint(mouse_pos):roles role_selection_menu(i 1)if roles:return (i 1, roles)title font.render(Vampire Survivors, True, WHITE)screen.blit(title, (WIDTH // 2 - title.get_width() // 2, 100))for btn in buttons:btn.check_hover(mouse_pos)btn.draw(screen)pygame.display.flip()clock.tick(30)def game_loop(player_count, roles):background GAME_IMAGES[background]controls [{up: pygame.K_w, down: pygame.K_s, left: pygame.K_a, right: pygame.K_d},{up: pygame.K_UP, down: pygame.K_DOWN, left: pygame.K_LEFT, right: pygame.K_RIGHT}]players pygame.sprite.Group()for i in range(player_count):player Player(controlscontrols[i],role_typeroles[i],pos_offset-50 i * 100,is_player2(i 1))players.add(player)all_sprites pygame.sprite.Group(players)enemies pygame.sprite.Group()bullets pygame.sprite.Group()exp_orbs pygame.sprite.Group()enemy_spawn_timer 0attack_timer 0start_ticks pygame.time.get_ticks()time_limit 300running Truewhile running:screen.blit(background, (0, 0))keys pygame.key.get_pressed()elapsed_seconds (pygame.time.get_ticks() - start_ticks) // 1000time_left max(time_limit - elapsed_seconds, 0)if time_left 0:running Falsefor event in pygame.event.get():if event.type pygame.QUIT:running Falseenemy_spawn_timer 1if enemy_spawn_timer 60 - (sum(p.level for p in players) * 2):if random.random() 0.1:enemy EliteEnemy()else:enemy Enemy()enemies.add(enemy)all_sprites.add(enemy)enemy_spawn_timer 0attack_timer 1if attack_timer 30:for player in players:for direction in player.get_attack_directions():bullet Bullet(player.rect.centerx, player.rect.centery, direction)bullets.add(bullet)all_sprites.add(bullet)attack_timer 0for player in players:player.update(keys)enemies.update(players)bullets.update()exp_orbs.update()for bullet in bullets:hits pygame.sprite.spritecollide(bullet, enemies, False)if hits:bullet.penetration - 1for enemy in hits:if isinstance(enemy, EliteEnemy):enemy.health - 2if enemy.health 0:enemy.kill()for _ in range(5):exp_orb ExpOrb(enemy.rect.centerx, enemy.rect.centery)exp_orbs.add(exp_orb)all_sprites.add(exp_orb)else:enemy.kill()exp_orb ExpOrb(enemy.rect.centerx, enemy.rect.centery)exp_orbs.add(exp_orb)all_sprites.add(exp_orb)for player in players:if math.hypot(player.rect.x - enemy.rect.x, player.rect.y - enemy.rect.y) 100:player.kills 1if bullet.penetration 0:bullet.kill()for player in players:hits pygame.sprite.spritecollide(player, exp_orbs, True)if hits:player.exp 10 * len(hits)if player.exp player.max_exp:player.level 1player.exp - player.max_expplayer.max_exp int(player.max_exp * 1.5)player.speed 0.5if pygame.sprite.spritecollide(player, enemies, True):player.health - 10bullet_hits pygame.sprite.spritecollide(player, bullets, True)if bullet_hits:player.health - 5alive_players [p for p in players if p.health 0]if not alive_players or time_left 0:running Falseall_sprites.draw(screen)draw_hud(screen, players, time_left)pygame.display.flip()clock.tick(30)pygame.quit()if __name__ __main__:player_count, roles main_menu()if player_count 0:game_loop(player_count, roles) 下面是python2的代码。方便不同环境的兄弟们运行
# -*- coding: utf-8 -*-
import os
import pygame
import random
import math
from datetime import datetime# 初始化路径
BASE_DIR os.path.dirname(os.path.abspath(__file__))
IMAGE_DIR os.path.join(BASE_DIR, image)RESOURCES {role1: os.path.join(IMAGE_DIR, role1.png),role2: os.path.join(IMAGE_DIR, role2.png),enemy: os.path.join(IMAGE_DIR, enemy.png),bullet: os.path.join(IMAGE_DIR, bullet.png),exp_orb: os.path.join(IMAGE_DIR, exp_orb.png),background: os.path.join(IMAGE_DIR, background.png)
}pygame.init()
WIDTH, HEIGHT 800, 600
screen pygame.display.set_mode((WIDTH, HEIGHT))
clock pygame.time.Clock()# 颜色定义
WHITE (255, 255, 255)
GRAY (100, 100, 100)
BUTTON_COLOR (50, 150, 50)
HOVER_COLOR (70, 170, 70)
RED (255, 0, 0)
YELLOW (255, 255, 0)font pygame.font.Font(None, 24)def load_image(path, default_size(30, 30)):try:image pygame.image.load(path).convert_alpha()return pygame.transform.scale(image, default_size)except:surf pygame.Surface(default_size)surf.fill(RED)return surfGAME_IMAGES {role1: load_image(RESOURCES[role1]),role2: load_image(RESOURCES[role2]),enemy: load_image(RESOURCES[enemy], (20, 20)),bullet: load_image(RESOURCES[bullet], (10, 10)),exp_orb: load_image(RESOURCES[exp_orb], (10, 10)),background: load_image(RESOURCES[background], (WIDTH, HEIGHT))
}class Button:def __init__(self, text, x, y, w, h):self.rect pygame.Rect(x, y, w, h)self.text textself.color BUTTON_COLORself.hover Falsedef draw(self, surface):color HOVER_COLOR if self.hover else BUTTON_COLORpygame.draw.rect(surface, color, self.rect, border_radius5)text_surf font.render(self.text, True, WHITE)text_rect text_surf.get_rect(centerself.rect.center)surface.blit(text_surf, text_rect)def check_hover(self, mouse_pos):self.hover self.rect.collidepoint(mouse_pos)class Player(pygame.sprite.Sprite):def __init__(self, controls, role_type, pos_offset0, is_player2False):pygame.sprite.Sprite.__init__(self)self.role_type role_typeself.image GAME_IMAGES[role2 if role_type 2 else role1]self.rect self.image.get_rect(center(WIDTH//2 pos_offset, HEIGHT//2))self.speed 5self.health 100self.exp 0self.level 1self.max_exp 100self.kills 0self.controls controlsdef update(self, keys):if keys[self.controls[up]]:self.rect.y - self.speedif keys[self.controls[down]]:self.rect.y self.speedif keys[self.controls[left]]:self.rect.x - self.speedif keys[self.controls[right]]:self.rect.x self.speedself.rect.clamp_ip(screen.get_rect())def get_attack_directions(self):if self.role_type 1:return [up, down, left, right]else:return [up_left, up_right, down_left, down_right]class Bullet(pygame.sprite.Sprite):def __init__(self, x, y, direction):pygame.sprite.Sprite.__init__(self)self.image GAME_IMAGES[bullet]self.rect self.image.get_rect(center(x, y))self.speed 8self.start_pos (x, y)self.max_distance 300self.penetration 2self.dx, self.dy 0, 0dir_mapping {up: (0, -1),down: (0, 1),left: (-1, 0),right: (1, 0),up_left: (-math.sqrt(0.5), -math.sqrt(0.5)),up_right: (math.sqrt(0.5), -math.sqrt(0.5)),down_left: (-math.sqrt(0.5), math.sqrt(0.5)),down_right: (math.sqrt(0.5), math.sqrt(0.5))}dx_mult, dy_mult dir_mapping[direction]self.dx dx_mult * self.speedself.dy dy_mult * self.speeddef update(self):self.rect.x self.dxself.rect.y self.dyif math.hypot(self.rect.x - self.start_pos[0], self.rect.y - self.start_pos[1]) self.max_distance:self.kill()class Enemy(pygame.sprite.Sprite):def __init__(self):pygame.sprite.Sprite.__init__(self)self.image GAME_IMAGES[enemy]self.rect self.image.get_rect(center(random.choice([-100, WIDTH100]), random.randint(0, HEIGHT)))self.speed 2def update(self, targets):if not targets: returnnearest min(targets, keylambda t: math.hypot(t.rect.x-self.rect.x, t.rect.y-self.rect.y))dx nearest.rect.x - self.rect.xdy nearest.rect.y - self.rect.ydist math.hypot(dx, dy)if dist ! 0:self.rect.x dx / dist * self.speedself.rect.y dy / dist * self.speedclass ExpOrb(pygame.sprite.Sprite):def __init__(self, x, y):pygame.sprite.Sprite.__init__(self)self.image GAME_IMAGES[exp_orb]self.rect self.image.get_rect(center(x, y))self.float_timer 0def update(self):self.float_timer 1self.rect.y math.sin(self.float_timer * 0.1) * 0.5def draw_hud(surface, players, time_left):time_text font.render(Time: {:02}:{:02}.format(time_left//60, time_left%60), True, WHITE)surface.blit(time_text, (WIDTH//2 - 60, 10))for i, player in enumerate(players):y_offset 40 i*80pygame.draw.rect(surface, GRAY, (10, y_offset, 100, 10))health_width int((player.health / 100.0) * 100)pygame.draw.rect(surface, RED, (10, y_offset, health_width, 10))pygame.draw.rect(surface, GRAY, (10, y_offset20, 100, 10))exp_width int((player.exp / float(player.max_exp)) * 100)pygame.draw.rect(surface, YELLOW, (10, y_offset20, exp_width, 10))info_text font.render(P{} Lv{} K{}.format(i1, player.level, player.kills), True, WHITE)surface.blit(info_text, (10, y_offset40))def role_selection_menu(player_count):roles []buttons []descriptions [Role 1: 4-Direction Attack,Role 2: Diagonal Attack]for i in range(player_count):y_base 150 i*150buttons.append([Button(Player{} Role1.format(i1), WIDTH//2-250, y_base, 200, 50),Button(Player{} Role2.format(i1), WIDTH//250, y_base, 200, 50)])confirm_btn Button(Start Game, WIDTH//2-100, HEIGHT-100, 200, 50)while True:screen.fill((30, 30, 30))mouse_pos pygame.mouse.get_pos()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()return []if event.type pygame.MOUSEBUTTONDOWN:for i, pair in enumerate(buttons):for j, btn in enumerate(pair):if btn.rect.collidepoint(mouse_pos):if len(roles) i:roles.append(j1)else:roles[i] j1if confirm_btn.rect.collidepoint(mouse_pos) and len(roles) player_count:return rolesdesc_y 100for desc in descriptions:text font.render(desc, True, WHITE)screen.blit(text, (WIDTH//2 - text.get_width()//2, desc_y))desc_y 30for i, pair in enumerate(buttons):for j, btn in enumerate(pair):btn.check_hover(mouse_pos)btn.draw(screen)if i len(roles) and roles[i] j1:pygame.draw.rect(screen, YELLOW, btn.rect.inflate(10,10), 3, border_radius7)confirm_btn.check_hover(mouse_pos)confirm_btn.draw(screen)pygame.display.flip()clock.tick(30)def main_menu():buttons [Button(1 Player, WIDTH//2-100, HEIGHT//2-50, 200, 50),Button(2 Players, WIDTH//2-100, HEIGHT//220, 200, 50)]while True:screen.fill((30, 30, 30))mouse_pos pygame.mouse.get_pos()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()return (0, [])if event.type pygame.MOUSEBUTTONDOWN:for i, btn in enumerate(buttons):if btn.rect.collidepoint(mouse_pos):selected i1roles role_selection_menu(selected)if roles:return (selected, roles)title font.render(Vampire Survivors, True, WHITE)screen.blit(title, (WIDTH//2 - title.get_width()//2, 100))for btn in buttons:btn.check_hover(mouse_pos)btn.draw(screen)pygame.display.flip()clock.tick(30)def game_loop(player_count, roles):background GAME_IMAGES[background]controls [{up: pygame.K_w, down: pygame.K_s, left: pygame.K_a, right: pygame.K_d},{up: pygame.K_UP, down: pygame.K_DOWN, left: pygame.K_LEFT, right: pygame.K_RIGHT}]players pygame.sprite.Group()for i in range(player_count):player Player(controlscontrols[i],role_typeroles[i],pos_offset-50 i*100,is_player2(i1))players.add(player)all_sprites pygame.sprite.Group(players)enemies pygame.sprite.Group()bullets pygame.sprite.Group()exp_orbs pygame.sprite.Group()enemy_spawn_timer 0attack_timer 0start_ticks pygame.time.get_ticks()time_limit 300running Truewhile running:screen.blit(background, (0, 0))keys pygame.key.get_pressed()elapsed_seconds (pygame.time.get_ticks() - start_ticks) // 1000time_left max(time_limit - elapsed_seconds, 0)if time_left 0:running Falsefor event in pygame.event.get():if event.type pygame.QUIT:running Falseenemy_spawn_timer 1if enemy_spawn_timer 60 - (sum(p.level for p in players)*2):enemy Enemy()enemies.add(enemy)all_sprites.add(enemy)enemy_spawn_timer 0attack_timer 1if attack_timer 30:for player in players:directions player.get_attack_directions()for direction in directions:bullet Bullet(player.rect.centerx, player.rect.centery, direction)bullets.add(bullet)all_sprites.add(bullet)attack_timer 0for player in players:player.update(keys)enemies.update(players)bullets.update()exp_orbs.update()for bullet in bullets:hits pygame.sprite.spritecollide(bullet, enemies, False)if hits:bullet.penetration - 1for enemy in hits:enemy.kill()exp_orb ExpOrb(enemy.rect.centerx, enemy.rect.centery)exp_orbs.add(exp_orb)all_sprites.add(exp_orb)for player in players:if math.hypot(player.rect.x-enemy.rect.x, player.rect.y-enemy.rect.y) 100:player.kills 1if bullet.penetration 0:bullet.kill()for player in players:hits pygame.sprite.spritecollide(player, exp_orbs, True)if hits:player.exp 10 * len(hits)if player.exp player.max_exp:player.level 1player.exp - player.max_expplayer.max_exp int(player.max_exp * 1.5)player.speed 0.5alive_players [p for p in players if p.health 0]for player in alive_players:if pygame.sprite.spritecollide(player, enemies, True):player.health - 10if len(alive_players) 0 or time_left 0:running Falseall_sprites.draw(screen)draw_hud(screen, players, time_left)pygame.display.flip()clock.tick(30)pygame.quit()if __name__ __main__:player_count, roles main_menu()if player_count 0:game_loop(player_count, roles) 互动引导 投票 如果让你添加新功能你会选择 A) 联机对战 B) 技能组合 C) BOSS战 D) 自定义角色 讨论 你在用Python开发游戏时遇到过哪些难题欢迎评论区交流 版权声明
本项目为开源学习作品遵循MIT协议欢迎二次开发但需保留原作者信息