前言
halo,包子们晚上好
很久没有更新啦,主要是小编这边最近有点小忙
今天给大家整一个简易版本的王者荣耀
有法师,射手,坦克,辅助
支持双人游戏哟
快跟你的小伙伴一起玩耍吧
相关文件
关注小编,私信小编领取哟!
当然别忘了一件三连哟~~
源码点击蓝色字体领取
开发工具
Python版本:3.7.8
相关模块:
pygame模块;
setting模块;
re模块;
以及一些python自带的模块。
环境搭建
安装Python并添加到环境变量,pip安装需要的相关模块即可。
模块介绍
- main.py 程序入口,进行游戏内容的初始化及主循环。
- game_event.py 处理输入事件,生成和更新物体状态的方法。
- live.py 玩家操控人物的属性和行为。
- enemy.py 游戏中的敌人的属性和行为。
- gameui.py 游戏过程中的信息的显示。
- startupui.py 游戏启动界面的按钮等组件的显示。
- rigidbody.py 模拟物体碰撞产生的位移。
- effect.py包含人物和敌人产生的攻击物体的更新和显示。
- setting.py 从外部加载图片,汇总游戏中各类属性的定义。
效果展示
游戏主页
三个模式,四大人物选择,大家不要看这个玩意不咋好看,小编只有这个能力画出这个玩意
游戏中
我们选择了法师,妲己,可能有点潦草的妲己,希望大家不要喷我,哈哈哈
游戏结束
四大人物
辅助:孙斌
射手:后羿
上单:猴子
法师:妲己
可以认出来就行啦,哈哈哈哈
部分代码展示
游戏初始化和主函数
源码领取加群:494958217
'''
程序主函数,汇总其它模块输出游戏窗口
'''
import pygame
import os.path
import csv
import setting as set
import live
import game_event
import gameui as gi
import startupui as si
#程序主函数
def run_game():
#初始化pygame库
pygame.init()
#创建时钟对象(控制帧率)
clock=pygame.time.Clock()
#实例化设置类,用于导入游戏设置
setting=set.Setting()
#设置游戏窗口
screen=pygame.display.set_mode((setting.screen_width,setting.screen_height))
pygame.display.set_caption(setting.screen_caption)
#设置不同的组,用于分别处理各种物品间的关系
#玩家组
group_player=pygame.sprite.Group()
#玩家的攻击组
group_attack=pygame.sprite.Group()
#敌人组
group_enemy=pygame.sprite.Group()
#敌人的攻击组
group_enemy_attack=pygame.sprite.Group()
#实例化ui对象
#showinfo用于在游戏内显示人物血条等信息
showinfo=gi.Info(setting,screen)
#人物选择按钮
yi_button=si.MonkeyKingButton(screen,setting)
monkey_button=si.YiButton(screen,setting)
fox_button=si.FoxButton(screen,setting)
bin_button=si.BinButton(screen,setting)
#游戏开始界面的按钮
pve_button=si.PVEButton(screen,setting)
pvp_button=si.PVPButton(screen,setting)
endless_button=si.EndlessButton(screen,setting)
control_button=si.ControlButton(screen,setting)
memory_button=si.RecordButton(screen,setting)
cooling_button=si.CoolingButton(screen,setting)
#游戏背景
select_button=si.SelectButton(screen,setting)
win_button=si.WinButton(screen,setting)
dead_button=si.DeadButton(screen,setting)
#玩家当前选择的人物标记
player_button_1=si.PlayerButton1(screen,setting)
player_button_2=si.PlayerButton2(screen,setting)
#空白按钮
none_button=si.NoneButton(screen,setting)
#空白图像
none_info=gi.ExInfo(screen,none_button,setting.introduce_none)
#介绍按钮作用的图像
pve_info=gi.ExInfo(screen,pve_button,setting.introduce_pve)
pvp_info=gi.ExInfo(screen,pvp_button,setting.introduce_pvp)
endless_info=gi.ExInfo(screen,endless_button,setting.introduce_endless)
control_info=gi.ExInfo(screen,control_button,setting.introduce_control)
record_info=gi.ExInfo(screen,memory_button,setting.introduce_record)
cooling_info=gi.ExInfo(screen,cooling_button,setting.introduce_cooling)
#按钮组(绘制时,在前的按钮会被在后的按钮覆盖)
buttons=[select_button,yi_button,monkey_button,fox_button,bin_button,
pve_button,pvp_button,endless_button,
cooling_button,control_button,memory_button,
dead_button,win_button]
#标签按钮组
choose_buttons=[player_button_1,player_button_2]
#介绍按钮作用的图像组
button_info_dict={none_button:none_info,pve_button:pve_info,pvp_button:pvp_info,
endless_button:endless_info,control_button:control_info,
memory_button:record_info,cooling_button:cooling_info}
#当前显示的图像列表
info_label=[]
#存储模拟刚体运动的列表
rigidbody_list=[]
#玩家实例,初始化为战士
player_1=live.MonkeyKing(setting,screen)
player_2=live.MonkeyKing(setting,screen)
if not os.path.exists(setting.record_path):
#如果游戏记录文件不存在就新创建一个
with open(setting.record_path,'w',newline="") as f:
writer=csv.writer(f)
header=["Time","Mode","Winner","1st Score","2st Score","Duration(s)","1st Player","2nd Player","isCooling"]
writer.writerow(header)
#游戏主循环
while True:
#绘制背景
screen.blit(setting.screen_surface_background,(0,0))
#设置游戏帧率
clock.tick(setting.fps)
#检测键盘鼠标事件
game_event.check_event(setting,screen,group_player,group_attack,group_enemy,
group_enemy_attack,buttons,showinfo,button_info_dict,info_label)
#更新当前选择人物的标签
game_event.update_choose(setting,buttons,choose_buttons)
#游戏运行,非玩家对抗模式
if (setting.game_active and (setting.game_mode==0 or setting.game_mode==2)):
#人物初始化
if(not setting.isinit):
if setting.player_1!=None:
player_1=setting.player_1
group_player.add(player_1)
if setting.player_2!=None:
player_2=setting.player_2
group_player.add(player_2)
setting.isinit=True
#游戏计时器
setting.timer+=1
#更新玩家
group_player.update()
#生成敌人
game_event.generate_enemies(setting,group_enemy,screen)
#更新敌人,玩家的攻击,敌人的攻击,玩家状态等
game_event.update_enemies(setting,showinfo,screen,group_player,group_enemy,group_attack,group_enemy_attack)
game_event.update_attacks(setting,screen,group_attack,group_enemy,rigidbody_list)
game_event.update_enemy_attacks(setting,screen,group_player,group_enemy_attack,rigidbody_list)
game_event.update_state(setting,showinfo)
game_event.update_rigidbody(setting,rigidbody_list)
#胜利条件
if setting.timer>=60*setting.fps and not group_enemy.spritedict and setting.game_mode==0:
game_event.game_win(setting,showinfo,group_enemy,group_attack,group_enemy_attack)
setting.timer=0
#失败条件
if setting.isinit and ((setting.player_1!=None and setting.health_1<=0) or (setting.player_2!=None and setting.health_2<=0)):
game_event.game_dead(setting,showinfo,group_enemy,group_attack,group_enemy_attack)
setting.timer=0
#玩家对抗模式
elif setting.game_active and setting.game_mode==1:
#人物初始化
if(not setting.isinit):
if setting.player_1!=None and setting.player_2!=None:
player_1=setting.player_1
group_player.add(player_1)
player_2=setting.player_2
group_player.add(player_2)
setting.isinit=True
#游戏计时器
setting.timer+=1
#更新玩家
player_1.update()
player_2.update()
#更新玩家的攻击,信息显示和物理模拟
game_event.update_attacks_pvp(setting,screen,group_attack,rigidbody_list)
game_event.update_state(setting,showinfo)
game_event.update_rigidbody(setting,rigidbody_list)
#玩家1胜利条件
if setting.isinit and setting.health_2<=0:
setting.score_1+=1
game_event.game_win(setting,showinfo,group_enemy,group_attack,group_enemy_attack)
setting.timer=0
#玩家2胜利条件
if setting.isinit and setting.health_1<=0:
setting.score_2+=1
game_event.game_win(setting,showinfo,group_enemy,group_attack,group_enemy_attack)
setting.timer=0
#根据上述更新的结果绘制整个游戏窗口
game_event.update_screen(setting,screen,group_player,group_attack,group_enemy,group_enemy_attack,
showinfo,buttons,info_label,choose_buttons)
#运行游戏
run_game()
游戏启动界面的按钮等组件的显示。
源码领取加群:494958217
'''
startupui模块定义了在游戏启动界面的各类ui组件外观
Button类为模块中其它类的父类,虽然叫button但不包括事件处理,只定义了图像和布局(点击事件的处理在game_event模块中)
Button类提供一个draw()实例方法绘制自身
子类 SelectButton WinButton DeadButton 作为界面背景(选人、胜利、失败)
子类 MonkeyKingButton YiButton FoxButton BinButton 作为选人按钮
其它子类为启动界面的各类功能按钮,包括开始特定模式的游戏,开关冷却等
'''
import pygame.font
import pygame.draw
class Button():
"""按钮基类"""
def __init__(self,screen,setting):
#窗口和设置属性
self.screen=screen
self.screen_rect=screen.get_rect()
self.setting=setting
#按钮的长宽
self.width = 120
self.height = 50
#按钮背景和字体颜色
self.button_color = (40, 200, 0)
self.text_color = (255, 255, 255)
#默认字体
self.font = pygame.font.SysFont(None, 50)
#布局
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
def draw(self):
"""渲染方法"""
self.screen.blit(self.surface, self.rect)
class MonkeyKingButton(Button):
"""战士按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.surface_none
self.rect = pygame.Rect((0,0),(200,380))
class FoxButton(Button):
"""法师按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.surface_none
self.rect = pygame.Rect((200,0),(200,380))
class BinButton(Button):
"""辅助按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.surface_none
self.rect = pygame.Rect((400,0),(200,380))
class YiButton(Button):
"""射手按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.surface_none
self.rect = pygame.Rect((600,0),(200,380))
class SelectButton(Button):
"""人物选择界面"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.screen_surface_select
self.rect = self.surface.get_rect()
class WinButton(Button):
"""胜利界面"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=self.setting.screen_surface_win
self.rect = self.surface.get_rect()
class DeadButton(Button):
"""失败界面"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.screen_surface_dead
self.rect = self.surface.get_rect()
class PVEButton(Button):
"""普通模式按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_pve_surface
self.rect=self.surface.get_rect()
self.rect.center=(400,100)
class PVPButton(Button):
"""玩家对抗按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_pvp_surface
self.rect=self.surface.get_rect()
self.rect.center=(400,200)
class EndlessButton(Button):
"""无尽模式按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_endless_surface
self.rect=self.surface.get_rect()
self.rect.center=(400,300)
class PlayerButton1(Button):
"""玩家1人物选择标记"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.player_1_surface
self.rect=self.surface.get_rect()
self.rect.center=(1000,1000)
class PlayerButton2(Button):
"""玩家2人物选择标记"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.player_2_surface
self.rect=self.surface.get_rect()
self.rect.center=(1000,1000)
class NoneButton(Button):
"""空白按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.surface_none
self.rect=self.surface.get_rect()
self.rect.center=(1000,1000)
self.rect.size=(1,1)
class CoolingButton(Button):
"""技能冷却按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_cooling_surface_0
self.surface_=setting.button_cooling_surface_1
self.rect=self.surface.get_rect()
self.rect.center=(70,360)
def draw(self):
"""根据技能状态绘制按钮"""
if self.setting.iscooling:
self.screen.blit(self.surface, self.rect)
else:
self.screen.blit(self.surface_, self.rect)
class ControlButton(Button):
"""控制按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_control_surface
self.rect=self.surface.get_rect()
self.rect.center=(740,390)
class RecordButton(Button):
"""记录按钮"""
def __init__(self,screen,setting):
super().__init__(screen,setting)
self.surface=setting.button_memory_surface
self.rect=self.surface.get_rect()
self.rect.center=(70,420)
游戏中的敌人的属性和行为。
源码领取加群:494958217
import pygame
import random
import effect
from pygame.sprite import Sprite
class Enemy(Sprite):
"""敌人的基类"""
def __init__(self,setting,screen,surface,generate_point,health,speed,action_interval,attack_interval,weight,score):
super().__init__()
#基本变量
self.screen=screen
self.setting=setting
self.screen_rect=screen.get_rect()
#移动速度
self.speed=speed
#重设移动方向间隔
self.action_interval=action_interval
#攻击间隔
self.attack_interval=attack_interval
#重量
self.weight=weight
#死亡后玩家获取的得分
self.score=score
#选择一名玩家人物作为目标
if setting.player_1!=None and setting.player_2!=None:
target=[setting.player_1,setting.player_2]
self.player=random.choice(target)
elif setting.player_1!=None:
self.player=setting.player_1
else:
self.player=setting.player_2
#以一个随机时刻开始移动和攻击计时器
self.action_timer=random.randint(0,int(action_interval))
self.attack_timer=random.randint(0,int(attack_interval))
#是否还存活
self.isalive=True
#是否是近战
self.ismelee=False
#近战攻击生成次数
self.melee_count=1
#朝向(-1朝左,1朝右)
self.forward=-1
#图像
self.surface=surface
self.surface_flip=pygame.transform.flip(self.surface,True,False)
#布局
self.rect=self.surface.get_rect()
#出生位置
self.rect.center=generate_point
#生命属性
self.max_health=health
self.health=self.max_health
#生命条布局
self.health_rect_background=pygame.Rect(self.rect.centerx-10,self.rect.centery-30,50,20)
self.health_rect=pygame.Rect(self.rect.centerx-10,self.rect.centery-30,self.health/self.max_health*50,20)
#移动方向
self.direction_x=0.0
self.direction_y=0.0
def update(self):
"""更新状态"""
self.flip()
self.auto_move()
self.update_health_ui()
def draw(self):
"""绘制图像"""
if self.forward==-1:
self.screen.blit(self.surface,self.rect)
else:
self.screen.blit(self.surface_flip,self.rect)
#绘制生命条
pygame.draw.rect(self.screen,(200,200,200),self.health_rect_background)
pygame.draw.rect(self.screen,(30,30,30),self.health_rect)
def flip(self):
"""更新当前朝向"""
if (self.rect.centerx-self.player.rect.centerx)>=0:
self.forward=-1
else:
self.forward=1
def update_health_ui(self,x=-25,y=-40,width=50,height=10):
"""更新血量ui"""
self.health_rect_background=pygame.Rect(self.rect.centerx+x,self.rect.centery+y,width,height)
self.health_rect=pygame.Rect(self.rect.centerx+x,self.rect.centery+y,self.health/self.max_health*width,height)
def auto_move(self):
"""自主更新位置"""
pass
class Mage(Enemy):
"""小法师"""
def __init__(self,setting,screen):
super().__init__(setting,screen,setting.enemy_mage_surface,setting.enemy_genrate_point,
setting.enemy_mage_health,setting.enemy_mage_move_speed,setting.enemy_mage_action_interval,
setting.enemy_mage_attack_interval,setting.enemy_mage_weight,setting.enemy_mage_score)
self.rect.centery+=random.randint(-150,150)
def auto_move(self):
"""上下随机移动"""
if(self.action_timer<=0):
self.direction_x=0
self.direction_y=random.uniform(-2,2)
#重置计时器
self.action_timer=self.action_interval
elif(self.action_timer%2==0):
#移动不能超出窗口
if self.rect.left > 0 and self.direction_x<0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.right < self.screen_rect.right and self.direction_x>0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.bottom < self.screen_rect.bottom and self.direction_y>0:
self.rect.centery+=self.direction_y*self.speed
if self.rect.top > 0 and self.direction_y<0:
self.rect.centery+=self.direction_y*self.speed
self.action_timer-=1
else:
self.action_timer-=1
def auto_attack(self):
"""返回攻击物"""
return effect.EnemyFireBall(self.setting,self.screen,self.player,self)
class Warrior(Enemy):
"""小战士"""
def __init__(self,setting,screen):
super().__init__(setting,screen,setting.enemy_warrior_surface,setting.enemy_genrate_point,
setting.enemy_warrior_health,setting.enemy_warrior_move_speed,setting.enemy_warrior_action_interval,
setting.enemy_warrior_attack_interval,setting.enemy_warrior_weight,setting.enemy_warrior_score)
self.ismelee=True
self.rect.centerx+=random.randint(-100,0)
self.rect.centery+=random.randint(-120,120)
def auto_move(self):
"""朝向目标玩家移动"""
if(self.action_timer<=0):
if self.player.rect.centerx-self.rect.centerx<=0:
self.direction_x=random.uniform(-2,-1)
else:
self.direction_x=random.uniform(1,2)
if self.player.rect.centery-self.rect.centery<=0:
self.direction_y=random.uniform(-2,-1)
else:
self.direction_y=random.uniform(1,2)
#重置计时器
self.action_timer=self.action_interval
elif(self.action_timer%2==0):
#移动不能超出窗口
if self.rect.left > 0 and self.direction_x<0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.right < self.screen_rect.right and self.direction_x>0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.bottom < self.screen_rect.bottom and self.direction_y>0:
self.rect.centery+=self.direction_y*self.speed
if self.rect.top > 0 and self.direction_y<0:
self.rect.centery+=self.direction_y*self.speed
self.action_timer-=1
else:
self.action_timer-=1
def auto_attack(self):
return effect.EnemyCollide(self.setting,self.screen,self.player,self)
class Artillery(Enemy):
"""小炮兵"""
def __init__(self,setting,screen):
super().__init__(setting,screen,setting.enemy_artillery_surface,setting.enemy_genrate_point,
setting.enemy_artillery_health,setting.enemy_artillery_move_speed,setting.enemy_artillery_action_interval,
setting.enemy_artillery_attack_interval,setting.enemy_artillery_weight,setting.enemy_artillery_score)
self.rect.centery+=random.randint(-200,200)
def auto_move(self):
"""远离玩家移动"""
if(self.action_timer<=0):
if self.player.rect.centerx-self.rect.centerx<=0:
self.direction_x=random.uniform(1,2)
else:
self.direction_x=random.uniform(-2,-1)
if self.player.rect.centery-self.rect.centery<=0:
self.direction_y=random.uniform(1,2)
else:
self.direction_y=random.uniform(-2,-1)
#重置计时器
self.action_timer=self.action_interval
elif(self.action_timer%2==0):
#移动不能超出窗口
if self.rect.left > 0 and self.direction_x<0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.right < self.screen_rect.right and self.direction_x>0:
self.rect.centerx+=self.direction_x*self.speed
if self.rect.bottom < self.screen_rect.bottom and self.direction_y>0:
self.rect.centery+=self.direction_y*self.speed
if self.rect.top > 0 and self.direction_y<0:
self.rect.centery+=self.direction_y*self.speed
self.action_timer-=1
else:
self.action_timer-=1
def auto_attack(self):
return effect.EnemyTargetBall(self.setting,self.screen,self.player,self)
class Overlord(Enemy):
"""大宿主"""
def __init__(self,setting,screen):
super().__init__(setting,screen,setting.enemy_overlord_surface,setting.enemy_genrate_point,
setting.enemy_overlord_health,setting.enemy_overlord_move_speed,setting.enemy_overlord_action_interval,
setting.enemy_overlord_attack_interval,setting.enemy_overlord_weight,setting.enemy_overlord_score)
self.rect.centerx-=random.randint(0,300)
#眼睛的图像
self.eye_surface=setting.enemy_eye_surface
self.eye_rect=self.eye_surface.get_rect()
self.eye_rect.center=self.rect.center
#半径的平方
self.radius=12**2
def eye_move(self):
"""眼睛移动向玩家"""
move_x=0
move_y=0
if self.player.rect.centerx-self.rect.centerx>=0:
move_x+=1
else:
move_x-=1
if self.player.rect.centery-self.rect.centery>=0:
move_y+=1
else:
move_y-=1
#计算和圆心的距离
delta_x=((self.eye_rect.centerx+move_x)-self.rect.centerx)
delta_y=((self.eye_rect.centery+move_y)-self.rect.centery)
#如果超出半径,则往回移动,否则朝目标移动
if (delta_x**2+delta_y**2)<self.radius:
self.eye_rect.centerx+=move_x
self.eye_rect.centery+=move_y
else:
if delta_x<=0:
self.eye_rect.centerx+=1
else:
self.eye_rect.centerx-=1
if delta_y<=0:
self.eye_rect.centery+=1
else:
self.eye_rect.centery-=1
def update(self):
"""更新状态"""
self.flip()
self.eye_move()
self.update_health_ui(y=-100,x=-50,width=100,height=15)
def auto_attack(self):
"""随机选择一种攻击返回"""
i=random.randint(0,1)
if i==0:
return effect.EnemyRingAttack(self.setting,self.screen,self.player,self)
else:
return effect.EnemyShoot(self.setting,self.screen,self.player,self)
def draw(self):
"""绘制自身和眼睛"""
super().draw()
self.screen.blit(self.eye_surface,self.eye_rect)
总结
源码有点多,所以就不都给大家展示啦
需要源码的小伙伴看文章末尾找到小编领取哈