前言

halo,包子们晚上好
很久没有更新啦,主要是小编这边最近有点小忙
今天给大家整一个简易版本的王者荣耀
有法师,射手,坦克,辅助
支持双人游戏哟
快跟你的小伙伴一起玩耍吧


开发工具

Python版本:3.7.8
相关模块:
pygame模块;
setting模块;
re模块;
以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

模块介绍

  1. main.py 程序入口,进行游戏内容的初始化及主循环。
  2. game_event.py 处理输入事件,生成和更新物体状态的方法。
  3. live.py 玩家操控人物的属性和行为。
  4. enemy.py 游戏中的敌人的属性和行为。
  5. gameui.py 游戏过程中的信息的显示。
  6. startupui.py 游戏启动界面的按钮等组件的显示。
  7. rigidbody.py 模拟物体碰撞产生的位移。
  8. effect.py包含人物和敌人产生的攻击物体的更新和显示。
  9. setting.py 从外部加载图片,汇总游戏中各类属性的定义。

效果展示

游戏主页

三个模式,四大人物选择,大家不要看这个玩意不咋好看,小编只有这个能力画出这个玩意

王者荣耀 python 王者荣耀python代玩_python

游戏中

我们选择了法师,妲己,可能有点潦草的妲己,希望大家不要喷我,哈哈哈

王者荣耀 python 王者荣耀python代玩_pygame_02


游戏结束

王者荣耀 python 王者荣耀python代玩_初始化_03


四大人物

辅助:孙斌

射手:后羿

上单:猴子

法师:妲己

可以认出来就行啦,哈哈哈哈

王者荣耀 python 王者荣耀python代玩_pygame_04

部分代码展示

游戏初始化和主函数


程序主函数,汇总其它模块输出游戏窗口
'''

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()

游戏启动界面的按钮等组件的显示。


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)

游戏中的敌人的属性和行为。


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)