使用Python+Pygame实现弹幕效果

为什么要写这么个东西,还是因为某室友在宿舍群里写骚代码来迫害我们无辜的室友们。于是,我也花了一晚上时间来搞了这么个迫害他的东西。此处应该大喊吴鸿声牛逼!

程序实现的效果是从一个包含弹幕内容的数组中随机抽取弹幕,并以随机的位置、随机的颜色显示在窗口内。 程序主要实现了一个弹幕类,其中包括生成弹幕、显示弹幕以及弹幕移动等。弹幕类的构造函数中,首先随机生成所有参数,并将弹幕位置的x坐标定位到屏幕宽度处(刚好在屏幕右侧的外部)。如果随机生成的y坐标处已经存在弹幕,为了防止遮挡会重新产生一个y坐标。若这个过程重复超过100次以上,说明可能当前弹幕已经满了(即屏幕宽度处已经没有空行了),就抛出异常。 弹幕的移动使用每秒像素数作为速度,弹幕类中的移动函数接收一个时间,该时间为程序循环一次所耗费的时间,函数使用时间计参数算弹幕在此时间内应移动的像素数,并将弹幕的x坐标减去对应像素数,通过在主循环中不断调用此函数,实现弹幕的连续移动。 最终,在主循环当中,不断获取上次循环的时间控制弹幕移动,并随机产生新的弹幕,删除已经溢出屏幕外的弹幕,最终通过弹幕类中的显示函数显示到屏幕上。

https://img.yuanze.wang/posts/pygame-danmaku/danmaku.jpg
最终效果

下面是全部代码。

import pygame
from random import randint
danmaku_text = ['吴鸿声牛逼', '我永远喜欢吴鸿声', '吴鸿声天下第一', '吴鸿声tql', '吴鸿声太强了',
            '吴鸿声太强了8', '爱了爱了', '呜呜呜太强了', '声声永远牛逼!']  # 弹幕文本
danmaku_height = 32  # 弹幕字号
danmaku_speed = 200  # 弹幕速度 每秒200像素
danmaku_color = [(255,255,255), (255,255,255), (255,255,255), (255,255,255), (255,255,255), (255,255,255), (255,255,255)
            , (255, 255, 255), (255, 255, 255), (255,0,0), (0,255,0), (255,255,0)]  # 弹幕颜色 白色概率大一些
width, height = 1280, 720  # 屏幕分辨率
class Danmaku(object):  # 弹幕类
   def __init__(self, existing_danmaku):  # 构造函数
      self.x = width
      self.speed = danmaku_speed
      self.text = danmaku_text[randint(0, danmaku_text.__len__()-1)]
      self.color = danmaku_color[randint(0, danmaku_color.__len__()-1)]
      retry = 0
      while True:  # 防止弹幕重叠
         self.y = randint(0, height//danmaku_height-1) * danmaku_height
         overlay = False
         for danmaku in existing_danmaku:
            if danmaku.y == self.y:
               if len(danmaku.text)*danmaku_height + danmaku.x > self.x:  # 弹幕会重叠
                  overlay = True
                  break
         retry += 1
         if retry > 100:  # 重试次数超出阈值 说明可能无处创建新的弹幕了
            raise Exception  # 抛出异常
         if not overlay:
            break
   def shift(self, seconds):  # 弹幕移动
      self.x -= seconds * self.speed
   def show(self, font, screen):
      text_serface = font.render(self.text, True, self.color)
      screen.blit(text_serface, (self.x, self.y))
def run():  # 函数
   pygame.init()  # pygame初始化
   pygame.display.set_caption('By 王远泽')  # 设置窗口标题
   screen = pygame.display.set_mode((width, height))  # 设置分辨率
   font = pygame.font.SysFont('SimHei', danmaku_height)  # 设置字体 这是Windows下的黑体名称
   clock = pygame.time.Clock()  # Clock对象
   danmaku_list = []
   while True:  # 主循环
      for event in pygame.event.get():
         if event.type == pygame.QUIT:  # 检测退出键按下
            return
      time_passed = clock.tick() / 1000  # 获取程序执行时间
      if randint(0, 19) == 0:  # 每次循环5%几率新增一个弹幕
         try:
            danmaku_list.append(Danmaku(danmaku_list))  # 新增弹幕
         except Exception:
            pass  # 如果无法创建 不执行任何操作
      screen.fill((0, 0, 0))  # 清屏
      for danmaku in danmaku_list:
         danmaku.show(font, screen)  # 显示弹幕
         danmaku.shift(time_passed)  # 更新所有弹幕的位置
      def is_on_screen(danmaku_obj):  # 判断弹幕是否还在屏幕上
         return not danmaku_obj.x < -len(danmaku_obj.text) * danmaku_height
      danmaku_list = list(filter(is_on_screen, danmaku_list))  # 去除已经溢出屏幕的弹幕
      pygame.display.update()  # 刷新显示
if __name__ == "__main__":
   run()