from kivy.app import App from kivy.uix.widget import Widget from kivy.graphics import Color, Ellipse from kivy.core.window import Window from kivy.clock import Clock import random import math # ウィンドウサイズ Window.size = (400, 400) class Ball: def __init__(self, canvas, x, y, radius, dx, dy, color=(1, 0, 0)): self.x = x self.y = y self.radius = radius self.dx = dx self.dy = dy self.color = color with canvas: Color(*self.color) self.ellipse = Ellipse(pos=(self.x - self.radius, self.y - self.radius), size=(2 * self.radius, 2 * self.radius)) def update(self): # 移動 self.x += self.dx self.y += self.dy # 壁との反射 if self.x - self.radius <= 0 or self.x + self.radius >= Window.width: self.dx *= -1 if self.y - self.radius <= 0 or self.y + self.radius >= Window.height: self.dy *= -1 # 位置座標を更新 self.ellipse.pos = (self.x - self.radius, self.y - self.radius) class BouncingBallApp(Widget): def __init__(self, **kwargs): super().__init__(**kwargs) self.balls = [] # 複数のボールオブジェクトを入れる配列を定義 self.max_balls = 20 # 最大ボール数 # 0.5秒ごとに新しいボールを追加 Clock.schedule_interval(self.add_ball, 0.5) # 毎フレーム更新 Clock.schedule_interval(self.update, 1/60) def add_ball(self, dt): if len(self.balls) < self.max_balls: #生成したボールが最大数に達していないとき # 中心から発射 x, y = Window.width / 2, Window.height / 2 radius = 10 # ランダム方向・速度 speed = 2 angle = random.uniform(0, 2 * math.pi) # random.uniform(a, b) は、 a から b の範囲でランダムな実数を返す 関数 # math.pi は円周率 (π ≒ 3.14159)、0 ~ 2π は、円を1周する角度の範囲(ラジアン単位) dx = speed * math.cos(angle) dy = speed * math.sin(angle) # angle=0のときcos=1,sin=0で右方向 # angle=π/2のときcos=0,sin=1で上方向 # angle=πのときcos=-1,sin=0で左方向 # angle=3π/2のときcos=0,sin=-1で下方向 # ランダム色 (RGB 0〜1) color = (random.random(), random.random(), random.random()) ball = Ball(self.canvas, x, y, radius, dx, dy, color) self.balls.append(ball) def update(self, dt): for ball in self.balls: ball.update() class MyApp(App): def build(self): return BouncingBallApp() if __name__ == "__main__": MyApp().run()