category
This commit is contained in:
		| @@ -0,0 +1,359 @@ | ||||
| """ | ||||
| This code is supported by the website: https://www.guanjihuan.com | ||||
| The newest version of this code is on the web page: https://www.guanjihuan.com/archives/703 | ||||
| """ | ||||
|  | ||||
| import pygame | ||||
| import random | ||||
| import math | ||||
| import numpy as np | ||||
|  | ||||
| # 参数 | ||||
| screen_width = 1500  # 屏幕宽度 | ||||
| screen_height = 900  # 屏幕高度 | ||||
| map_width = screen_width*4  # 地图的大小 | ||||
| map_height = screen_height*4  # 地图的大小 | ||||
| number_enemy = map_width*map_height/500000  # 敌人的数量 | ||||
| number_dots = map_width * map_height / 50  # 点点的数量 | ||||
| max_show_size = 100  # 球显示的最大半径(屏幕有限,球再增大时,改变的地图比例尺寸) | ||||
|  | ||||
| my_value = 1000  # 我的初始值 | ||||
| enemy_value_low = 500  # 敌人的初始值(最低) | ||||
| enemy_value_high = 1500  # 敌人的初始值(最高) | ||||
| dot_value = 30  # 点点的值(地上的豆豆/食物值) | ||||
| my_speed = 10  # 我的球运动的速度 | ||||
| speed_up = 20  # 按下鼠标时加速 | ||||
| speed_enemy = 10  # 敌人球正常运动速度 | ||||
| speed_enemy_anomaly = 20  # 敌人突然加速时的速度(速度异常时的速度) | ||||
| anomaly_pro = 0.5  # 敌人加速的概率 | ||||
| change_pro = 0.05  # 敌人移动路径变化的概率,也就是1/change_pro左右会变化一次 | ||||
| eat_percent = 0.9  # 吃掉敌人的球,按多少比例并入自己的体积,1对应的是100% | ||||
| loss = 0.001  # 按比例减小体重(此外越重的减少越多,10万体积损失值为loss的一倍) | ||||
| enemy_bigger_pro = 0.0005  # 敌人的值增加了我的球的值的enemy_bigger_rate倍的几率 | ||||
| enemy_bigger_rate = 0.1  # 增加我的球的体积的enemy_bigger_rate倍 | ||||
|  | ||||
|  | ||||
| class Color(object):  # 定义颜色的类 | ||||
|     @classmethod  # 加了这个可以不需要把实例化,能直接调用类的方法 | ||||
|     def random_color(cls):  # cls, 即class,表示可以通过类名直接调用 | ||||
|         red = random.randint(0, 255) | ||||
|         green = random.randint(0, 255) | ||||
|         blue = random.randint(0, 255) | ||||
|         return red, green, blue | ||||
|  | ||||
|  | ||||
| class Ball(object):  # 定义球 | ||||
|     def __init__(self, x, y, sx, sy, color, value):  # 初始化 | ||||
|         self.x = x  # 球的地图位置参数 | ||||
|         self.y = y | ||||
|         self.sx = sx  # 速度参数 | ||||
|         self.sy = sy | ||||
|         self.color = color  # 颜色 | ||||
|         self.value = value  # 球的值,也就是球的大小(不是显示的大小) | ||||
|         self.is_alive = True  # 球默认是存活状态 | ||||
|  | ||||
|  | ||||
| class My_Ball(Ball):  # 定义我的球,继承了Ball类的方法 | ||||
|     def __init__(self, x, y, sx, sy, color, value): | ||||
|         # 注意:如果重写了__init__() 时,实例化子类,就不会调用父类已经定义的__init__() | ||||
|         # 如果子类不重写__init__()方法,实例化子类后,会自动调用父类的__init__()的方法 | ||||
|         # 如果子类重写__init__()方法又需要调用父类的方法,则要使用super关键词。 | ||||
|         super().__init__(x, y, sx, sy, color, value)  # 调用父类Ball的初始化方法__init__() | ||||
|         self.radius = int(self.value**0.5)  # 我的球的半径(不考虑系数pi) | ||||
|         if self.radius >= max_show_size:  # 如果半径比规定的最大半径还大,则显示最大半径 | ||||
|             self.show_radius = max_show_size  # 我的球显示的半径 | ||||
|         else: | ||||
|             self.show_radius = self.radius  # 如果半径没有超过规定最大的半径,则显示原来实际大小的半径 | ||||
|         self.position_x = int(screen_width/2)   # 把我的球固定在屏幕中间position_x,是屏幕显示的位置 | ||||
|         self.position_y = int(screen_height/2)  # 把我的球固定在屏幕中间position_y,是屏幕显示的位置 | ||||
|  | ||||
|     def draw(self, window):  # 把我的球画出来 | ||||
|         self.radius = int(self.value ** 0.5)   # 这里重复上面的,因为除了初始化之后,还要更新 | ||||
|         if self.radius >= max_show_size: | ||||
|             self.show_radius = max_show_size | ||||
|         else: | ||||
|             self.show_radius = self.radius | ||||
|         self.position_x = int(screen_width / 2) | ||||
|         self.position_y = int(screen_height / 2) | ||||
|         pygame.draw.circle(window, self.color, (self.position_x , self.position_y), self.show_radius) | ||||
|  | ||||
|     def eat_ball(self, other):  # 吃别的球(包括小点点和敌人) | ||||
|         if self != other and self.is_alive and other.is_alive:  # 如果other不是自身,自身和对方也都是存活状态,则执行下面动作 | ||||
|             distance = ((self.position_x - other.position_x) ** 2 + (self.position_y - other.position_y) ** 2) ** 0.5   # 两个球之间的距离 | ||||
|             if distance < self.show_radius and (self.show_radius > other.show_radius or (self.show_radius == other.show_radius and self.value > other.value)):  # 如果自身半径比别人大,而且两者距离小于自身半径,那么可以吃掉。 | ||||
|                 other.is_alive = False  # 吃球(敌方已死) | ||||
|                 self.value += other.value*eat_percent   # 自己的值增大(体量增大) | ||||
|                 self.radius = int(self.value ** 0.5)  # 计算出半径 | ||||
|                 if self.radius >= max_show_size:  # 我的球的显示半径 | ||||
|                     self.show_radius = max_show_size | ||||
|                 else: | ||||
|                     self.show_radius = self.radius | ||||
|  | ||||
|     def move(self):  # 移动规则 | ||||
|         self.x += self.sx  # 地图位置加上速度 | ||||
|         self.y += self.sy | ||||
|         # 横向出界 | ||||
|         if self.x < 0:  # 离开了地图左边 | ||||
|             self.x = 0 | ||||
|         if self.x > map_width:  # 离开了地图右边 | ||||
|             self.x = map_width | ||||
|         # 纵向出界 | ||||
|         if self.y <= 0:  # 离开了地图下边 | ||||
|             self.y = 0 | ||||
|         if self.y >= map_height:  # 离开了地图上边 | ||||
|             self.y = map_height | ||||
|  | ||||
|  | ||||
| class Enemy_Ball(Ball):  # 定义敌人的球,继承了Ball类的方法 | ||||
|     def __init__(self, x, y, sx, sy, color, value, host_ball):  # 初始化带上host_ball,也就是我的球 | ||||
|         super().__init__(x, y, sx, sy, color, value) | ||||
|         self.host_ball = host_ball | ||||
|         self.radius = int(self.value**0.5) | ||||
|         if self.host_ball.radius >= max_show_size:  # 如果我的球比规定的最大尺寸还大,则敌人的球显示的比例要减小 | ||||
|             self.show_radius = max(10, int(self.radius/(self.host_ball.radius/max_show_size)))  # 敌人的球也不能太小,最小半径为10 | ||||
|             self.position_x = int((self.x - self.host_ball.x) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_width / 2)  # 计算出敌人的球和我的球的相对位置,并且按比例减小 | ||||
|             self.position_y = int((self.y - self.host_ball.y) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_height / 2)  # 计算出敌人的球和我的球的相对位置,并且按比例减小 | ||||
|         else: | ||||
|             self.show_radius = self.radius  # 正常显示 | ||||
|             self.position_x = (self.x - self.host_ball.x) + int(screen_width / 2)  # 敌人和我的球的相对位置 | ||||
|             self.position_y = (self.y - self.host_ball.y) + int(screen_height / 2)  # 敌人和我的球的相对位置 | ||||
|  | ||||
|     # 画出球 | ||||
|     def draw(self, window): | ||||
|         self.radius = int(self.value ** 0.5) | ||||
|         if self.host_ball.radius >= max_show_size:  # 这边把初始化的内容再写一遍,因为敌人的球初始化之后还要根据我的球而动态改变 | ||||
|             self.show_radius = max(10, int(self.radius/(self.host_ball.radius/max_show_size))) | ||||
|             self.position_x = int((self.x - self.host_ball.x) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_width / 2) | ||||
|             self.position_y = int((self.y - self.host_ball.y) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_height / 2) | ||||
|         else: | ||||
|             self.show_radius = self.radius | ||||
|             self.position_x = (self.x - self.host_ball.x) + int(screen_width / 2) | ||||
|             self.position_y = (self.y - self.host_ball.y) + int(screen_height / 2) | ||||
|         pygame.draw.circle(window, self.color, (self.position_x, self.position_y), self.show_radius) | ||||
|  | ||||
|     def eat_ball(self, other): | ||||
|         if self != other and self.is_alive and other.is_alive: | ||||
|             distance = ((self.position_x - other.position_x) ** 2 + (self.position_y - other.position_y) ** 2) ** 0.5 | ||||
|             if distance < self.show_radius and (self.show_radius > other.show_radius or (self.show_radius == other.show_radius and self.value > other.value)): | ||||
|                 other.is_alive = False  # 吃球 | ||||
|                 self.value += other.value*eat_percent | ||||
|                 self.radius = int(self.value ** 0.5) | ||||
|  | ||||
|     def move(self):  # 移动规则 | ||||
|         self.x += self.sx  # 地图位置加上速度 | ||||
|         self.y += self.sy | ||||
|         # 横向出界 | ||||
|         if self.x < 0:  # 离开了地图左边 | ||||
|             self.sx = -self.sx | ||||
|             self.x = 0 | ||||
|         if self.x > map_width:  # 离开了地图右边 | ||||
|             self.sx = -self.sx | ||||
|             self.x = map_width | ||||
|         # 纵向出界 | ||||
|         if self.y <= 0:  # 离开了地图下边 | ||||
|             self.sy = -self.sy | ||||
|             self.y = 0 | ||||
|         if self.y >= map_height:  # 离开了地图上边 | ||||
|             self.sy = -self.sy | ||||
|             self.y = map_height | ||||
|  | ||||
|  | ||||
| class Dot_Ball(Ball):  # 定义地上的小点点,供自己的球和敌人的球吃,继承了Ball类的方法 | ||||
|     def __init__(self, x, y,  sx, sy, color, value, host_ball): | ||||
|         super().__init__(x, y, sx, sy, color, value) | ||||
|         self.host_ball = host_ball | ||||
|         self.radius = 8  # 初始小点点大小 | ||||
|         if self.host_ball.radius >= max_show_size: | ||||
|             self.show_radius = max(3, int(self.radius/(self.host_ball.radius/max_show_size)))  # 小点点显示也不能太小,最小显示半径为3 | ||||
|             self.position_x = int((self.x - self.host_ball.x) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_width / 2) | ||||
|             self.position_y = int((self.y - self.host_ball.y) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_height / 2) | ||||
|         else: | ||||
|             self.show_radius = self.radius | ||||
|             self.position_x = (self.x - self.host_ball.x) + int(screen_width / 2) | ||||
|             self.position_y = (self.y - self.host_ball.y) + int(screen_height / 2) | ||||
|  | ||||
|     # 画出球 | ||||
|     def draw(self, window): | ||||
|         if self.host_ball.radius >= max_show_size:  # 这边把初始化的内容再写一遍,因为小点点初始化之后还要根据我的球而动态改变 | ||||
|             self.show_radius = max(3, int(self.radius/(self.host_ball.radius/max_show_size))) | ||||
|             self.position_x = int((self.x - self.host_ball.x) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_width / 2) | ||||
|             self.position_y = int((self.y - self.host_ball.y) / (self.host_ball.radius / max_show_size)) + int( | ||||
|                 screen_height / 2) | ||||
|         else: | ||||
|             self.show_radius = self.radius | ||||
|             self.position_x = (self.x - self.host_ball.x) + int(screen_width / 2) | ||||
|             self.position_y = (self.y - self.host_ball.y) + int(screen_height / 2) | ||||
|         pygame.draw.circle(window, self.color, (self.position_x, self.position_y) , self.show_radius) | ||||
|  | ||||
|  | ||||
| def creat_my_ball():  # 产生我的球 | ||||
|     x = random.randint(0, map_width)  # 我的球在地图中的位置,随机生成 | ||||
|     y = random.randint(0, map_height) | ||||
|     value = my_value  # 我的球的初始值 | ||||
|     color = 255, 255, 255  # 我的球的颜色 | ||||
|     sx = 0  # 速度默认为0 | ||||
|     sy = 0 | ||||
|     host_ball = My_Ball(x, y, sx, sy, color, value)  # 调用My_Ball类 | ||||
|     return host_ball  # 返回我的球 | ||||
|  | ||||
|  | ||||
| def auto_creat_ball(balls, host_ball):  # 自动产生敌人的球 | ||||
|     if len(balls) <= number_enemy:  # 控制敌人的数量,如果个数够了,就不再生成 | ||||
|         x = random.randint(0, map_width)  # 敌人球在地图中的位置,随机生成 | ||||
|         y = random.randint(0, map_height) | ||||
|         value = random.randint(enemy_value_low, enemy_value_high)  # 敌人的球初始值 | ||||
|         sx = random.randint(-speed_enemy, speed_enemy)  # 敌人的球移动速度 | ||||
|         i2 = random.randint(0, 1)  # y的移动方向 | ||||
|         if i2 == 0: | ||||
|             sy = int((speed_enemy**2 - sx**2) ** 0.5) | ||||
|         else: | ||||
|             sy = -int((speed_enemy ** 2 - sx ** 2) ** 0.5) | ||||
|         color = Color.random_color()  # 敌人的颜色随机生成 | ||||
|         enemy = Enemy_Ball(x, y, sx, sy, color, value, host_ball) | ||||
|         balls.append(enemy) | ||||
|  | ||||
|  | ||||
| def auto_creat_dots(dots, host_ball):  # 自动生成点点 | ||||
|     if len(dots) <= number_dots:  # 控制点点的数量 | ||||
|         x = random.randint(0, map_width)  # 随机生成点点的位置 | ||||
|         y = random.randint(0, map_height) | ||||
|         value = dot_value  # 点点的值 | ||||
|         sx = 0  # 点点速度为0 | ||||
|         sy = 0 | ||||
|         color = Color.random_color()  # 颜色 | ||||
|         dot = Dot_Ball(x, y, sx, sy, color, value, host_ball) | ||||
|         dots.append(dot) | ||||
|  | ||||
|  | ||||
| def control_my_ball(host_ball):  # 控制我的球 | ||||
|     host_ball.move() | ||||
|     host_ball.value = host_ball.value*(1-loss*host_ball.value/100000) | ||||
|     for event in pygame.event.get():  # 监控事件(鼠标移动) | ||||
|         # print(event) | ||||
|         if event.type == pygame.MOUSEBUTTONDOWN: | ||||
|             pos = event.pos | ||||
|             speed = speed_up | ||||
|         elif event.type == pygame.MOUSEMOTION: | ||||
|             pos = event.pos | ||||
|             if event.buttons[0] == 1: | ||||
|                 speed = speed_up | ||||
|             if event.buttons[0] == 0: | ||||
|                 speed = my_speed | ||||
|         elif event.type == pygame.MOUSEBUTTONUP: | ||||
|             pos = event.pos | ||||
|             speed = my_speed | ||||
|         else: | ||||
|             pos = [screen_width/2, screen_height/2] | ||||
|             speed = my_speed | ||||
|         if abs(pos[0] - screen_width/2) < 30 and abs(pos[1] - screen_height/2) < 30: | ||||
|             host_ball.sx = 0 | ||||
|             host_ball.sy = 0 | ||||
|         elif pos[0] > screen_width/2 and pos[1] >= screen_height/2: | ||||
|             angle = abs(math.atan((pos[1] - screen_height/2) / (pos[0] - screen_width/2))) | ||||
|             host_ball.sx = int(speed * math.cos(angle)) | ||||
|             host_ball.sy = int(speed * math.sin(angle)) | ||||
|         elif pos[0] > screen_width/2 and pos[1] < screen_height/2: | ||||
|             angle = abs(math.atan((pos[1] - screen_height/2) / (pos[0] - screen_width/2))) | ||||
|             host_ball.sx = int(speed * math.cos(angle)) | ||||
|             host_ball.sy = -int(speed * math.sin(angle)) | ||||
|         elif pos[0] < screen_width/2 and pos[1] >= screen_height/2: | ||||
|             angle = abs(math.atan((pos[1] - screen_height/2) / (pos[0] - screen_width/2))) | ||||
|             host_ball.sx = -int(speed * math.cos(angle)) | ||||
|             host_ball.sy = int(speed * math.sin(angle)) | ||||
|         elif pos[0] < screen_width/2 and pos[1] < screen_height/2: | ||||
|             angle = abs(math.atan((pos[1] - screen_height/2) / (pos[0] - screen_width/2))) | ||||
|             host_ball.sx = -int(speed * math.cos(angle)) | ||||
|             host_ball.sy = -int(speed * math.sin(angle)) | ||||
|         elif pos[0] == screen_width/2: | ||||
|             host_ball.sx = 0 | ||||
|             if pos[1] >= 0: | ||||
|                 host_ball.sy = speed | ||||
|             else: | ||||
|                 host.ball.sy = -speed | ||||
|  | ||||
|  | ||||
| def enemy_move(balls, host_ball):  # 敌人移动 | ||||
|     for enemy in balls: | ||||
|         enemy.move()  # 移动 | ||||
|         enemy.value = enemy.value*(1-loss*enemy.value/100000) | ||||
|         if random.randint(1, int(1/enemy_bigger_pro)) == 1: | ||||
|             enemy.value += host_ball.value*enemy_bigger_rate | ||||
|         if random.randint(1, int(1/anomaly_pro)) == 1: | ||||
|             speed_enemy0 = speed_enemy_anomaly  # 敌人异常速度 | ||||
|         else: | ||||
|             speed_enemy0 = speed_enemy  # 敌人正常速度 | ||||
|         i = random.randint(1, int(1/change_pro))  # 一定的概率改变轨迹 | ||||
|         if i == 1: | ||||
|             enemy.sx = random.randint(-speed_enemy0, speed_enemy0) | ||||
|             i2 = random.randint(0, 1) | ||||
|             if i2 == 0: | ||||
|                 enemy.sy = int((speed_enemy0 ** 2 - enemy.sx ** 2) ** 0.5) | ||||
|             else: | ||||
|                 enemy.sy = -int((speed_enemy0 ** 2 - enemy.sx ** 2) ** 0.5) | ||||
|  | ||||
|  | ||||
| def eat_each_other(host_ball, balls, dots):  # 吃球 | ||||
|     for enemy in balls: | ||||
|         for enemy2 in balls: | ||||
|             enemy.eat_ball(enemy2)  # 敌人互吃 | ||||
|         for food in dots: | ||||
|             enemy.eat_ball(food)  # 敌人吃点点 | ||||
|     for enemy in balls: | ||||
|         host_ball.eat_ball(enemy)  # 我吃敌人 | ||||
|         enemy.eat_ball(host_ball)  # 敌人吃我 | ||||
|     for food in dots: | ||||
|         host_ball.eat_ball(food)  # 我吃点点 | ||||
|  | ||||
|  | ||||
| def paint(host_ball, balls, dots, screen): | ||||
|     screen.fill((0, 0, 0))  # 刷漆 | ||||
|     if host_ball.is_alive: | ||||
|         host_ball.draw(screen) | ||||
|     for enemy in balls:  # 遍历容器 | ||||
|         if enemy.is_alive: | ||||
|             enemy.draw(screen) | ||||
|         else: | ||||
|             balls.remove(enemy) | ||||
|     for food in dots:  # 遍历容器 | ||||
|         if food.is_alive: | ||||
|             food.draw(screen) | ||||
|         else: | ||||
|             dots.remove(food) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     pygame.init()  # 初始化 | ||||
|     screen = pygame.display.set_mode((screen_width, screen_height))  # 设置屏幕 | ||||
|     pygame.display.set_caption("球球大作战")  # 设置屏幕标题 | ||||
|     balls = []  # 定义一容器  存放所有的敌方球 | ||||
|     dots = []  # 定义一容器 存放所有的点点 | ||||
|     is_running = True  # 默认运行状态 | ||||
|     host_ball = creat_my_ball()  # 产生我的球 | ||||
|     i00 = 0  # 一个参数 | ||||
|     while is_running: | ||||
|         for event in pygame.event.get(): | ||||
|             if event.type == pygame.QUIT: | ||||
|                 is_running = False | ||||
|         auto_creat_dots(dots, host_ball)  # 自动生成点点 | ||||
|         auto_creat_ball(balls, host_ball)  # 自动生成敌人 | ||||
|         paint(host_ball, balls, dots, screen)  # 把所有的都画出来 调用draw方法 | ||||
|         pygame.display.flip()  # 渲染 | ||||
|         pygame.time.delay(30)  # 设置动画的时间延迟 | ||||
|  | ||||
|         control_my_ball(host_ball)  # 移动我的球 | ||||
|         enemy_move(balls, host_ball)  # 敌人的球随机运动 | ||||
|         eat_each_other(host_ball, balls, dots)  # 吃球 调用eat_ball方法 | ||||
|         i00 += 1 | ||||
|         if np.mod(i00, 50) == 0: | ||||
|             print(host_ball.value) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
		Reference in New Issue
	
	Block a user