主要是参照网上这个代码进行改编的:Python 球球大作战简化版https://www.cnblogs.com/wenqiangblog/p/9469909.html。该代码实现了以下功能:点击一下鼠标,在鼠标的地方会出现一个随机大小的球,然后球随机移动,大球遇到小球,会吃掉小球。可玩性不高。
通过改编后,实现了这些功能:
- 根据鼠标的位置,自身球在地图中的位置会发生移动;
- 自身球固定在屏幕中心,其他球是会根据自身球相对移动。
- 当自身球显示大小不再增大时(因为屏幕大小有限,实际值还在增大),其他球显示的大小会根据自身球而等比例减小(实际值仍保持);
- 吃地上的豆豆可以慢慢发育起来;
- 大球吃小球, 会按一定比例吸收到自身的体积;
- 按住鼠标左键,球会加速;
- 敌方的球有一定几率改变运动轨迹;
- 敌方的球有一定几率会突然加速;
- 敌方的球有一定几率会增加自身球的体积的一部分(为了增加后期挑战性);
- 所有的球会按一定的比例减小体积,而且体积越大,减少越多。
未开发的功能:
- 分身;
- 吐球;
- 扎刺;
- 参数科学化;
- 设计和美工;
- 联网对战等。
这是游戏的界面截图:
以下是改编的球球大作战代码。可以复制到 Python 中试玩,也可以改参数后增加挑战性。前提是需要安装 pygame 库。安装方法是:win+R, 输入 cmd 回车, 输入 pip install pygame 后回车。需要说明的是:这里的代码没有做额外的优化,可能有些代码内容比较相似或重复,仅供参考。
"""
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()
【说明:本站主要是个人的一些笔记和代码分享,内容可能会不定期修改。为了使全网显示的始终是最新版本,这里的文章未经同意请勿转载。引用请注明出处:https://www.guanjihuan.com】