以下、少しずつ、いろいろ変更を加えていくことで、変化を検証してみてください。
1.地面にボールが落下する物理シミュレーション
設定
- 200,150 画面サイズ
- 地面、ボール、ボールに回転を示す線(中心から半径方向)
- 画面中央上から、鉛直落下
- ボールに角速度を付加
- スペースキーでリセットする
pyxel_pymunk_ball2.py
pyxel_pymunk_ball2.py
import math
import pyxel
import pymunk
class App:
def __init__(self):
pyxel.init(200, 150, title="Pyxel + pymunk: Rotating Ball")
self.space = pymunk.Space()
self.space.gravity = (0, 400)
# 床
floor = pymunk.Segment(self.space.static_body, (0, 130), (200, 130), 0)
floor.elasticity = 0.9
self.space.add(floor)
# ボール
mass, radius = 1, 8
moment = pymunk.moment_for_circle(mass, 0, radius)
self.ball_body = pymunk.Body(mass, moment)
self.ball_body.position = (100, 50)
self.ball_body.angular_velocity = 4.0 # ← 初期角速度を設定!
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.elasticity = 0.8
self.space.add(self.ball_body, self.ball_shape)
pyxel.run(self.update, self.draw)
def update(self):
if pyxel.btnp(pyxel.KEY_SPACE):
self.ball_body.position = (100, 50)
self.ball_body.angle = 0 # 角度リセット
self.ball_body.velocity = (0, 0)
self.ball_body.angular_velocity = 4.0
self.space.step(1/60)
def draw(self):
pyxel.cls(0)
pyxel.rect(0, 130, 200, 20, 5)
# ボール位置と角度を取得
x, y = self.ball_body.position
r = 8
angle = self.ball_body.angle
# 半径方向の端点を計算
rx = x + math.cos(angle) * r
ry = y + math.sin(angle) * r
# ボール本体
pyxel.circ(int(x), int(y), r, 9)
# 回転を示す線(中心から半径方向)
pyxel.line(int(x), int(y), int(rx), int(ry), 8)
pyxel.text(5, 5, f"angle={angle:.2f}", 7)
App()
2.ボールに横方向の初速度と角速度をつけて、落下する物理シミュレーション
設定
- 200,150 画面サイズ
- 地面、ボール、ボールに回転を示す線(中心から半径方向)
- 画面中央上から、ボールに角速度、初速度、落下
- スペースキーでリセットする
pyxel_pymunk_ball3.py
pyxel_pymunk_ball3.py
# pyxel_pymunk_ball3.py
# pip install pyxel pymunk
import math
import pyxel
import pymunk
class App:
def __init__(self):
pyxel.init(200, 150, title="Pyxel + pymunk: Rolling Ball")
self.space = pymunk.Space()
self.space.gravity = (0, 400)
# 床
floor = pymunk.Segment(self.space.static_body, (0, 130), (200, 130), 0)
floor.elasticity = 0.8
floor.friction = 0.9 # ← 床の摩擦を設定
self.space.add(floor)
# ボール
mass, radius = 1, 8
moment = pymunk.moment_for_circle(mass, 0, radius)
self.ball_body = pymunk.Body(mass, moment)
self.ball_body.position = (100, 50)
self.ball_body.velocity = (1, 0) # ← 横方向の初速度
self.ball_body.angular_velocity = 4.0 # ← 初期角速度(スピン)
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.elasticity = 0.8
self.ball_shape.friction = 0.9 # ← ボール側にも摩擦を設定
self.space.add(self.ball_body, self.ball_shape)
pyxel.run(self.update, self.draw)
def update(self):
# スペースキーでリセット
if pyxel.btnp(pyxel.KEY_SPACE):
self.ball_body.position = (100, 50)
self.ball_body.angle = 0
self.ball_body.velocity = (2, 0)
self.ball_body.angular_velocity = 4.0
self.space.step(1 / 60)
def draw(self):
pyxel.cls(0)
pyxel.rect(0, 130, 200, 20, 5)
# ボール位置と角度を取得
x, y = self.ball_body.position
r = 8
angle = self.ball_body.angle
# 半径方向の端点を計算(回転表示用)
rx = x + math.cos(angle) * r
ry = y + math.sin(angle) * r
# ボール本体
pyxel.circ(int(x), int(y), r, 9)
# 回転を示す線(スピン方向を視覚化)
pyxel.line(int(x), int(y), int(rx), int(ry), 8)
# 情報表示
vx, vy = self.ball_body.velocity
pyxel.text(5, 5, f"v=({vx:.1f},{vy:.1f})", 7)
pyxel.text(5, 12, f"kakusoku={self.ball_body.angular_velocity:.2f}", 7)
App()
3.地面にボールが落下する。画面640 x 480
設定
- 640,480 画面サイズ
- 地面、ボール
- 画面中央上から、鉛直落下
- リセットなし
02redball_elastic.py
02redball_elastic.py
import pyxel
import pymunk
class App:
def __init__(self):
# 画面サイズ
self.WIDTH = 640
self.HEIGHT = 480
# Pyxel の初期化(caption→title に変更)
pyxel.init(self.WIDTH, self.HEIGHT, title="Pyxel + Pymunk Demo")
pyxel.mouse(True)
# Pymunk のスペースを作成し、重力を設定(y軸下向きの重力を -900)
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# 地面のセグメントを作成
ground_y = 100
body = pymunk.Body(body_type=pymunk.Body.STATIC)
shape = pymunk.Segment(body, (0, ground_y), (self.WIDTH, ground_y), 1)
shape.friction = 0.8
shape.elasticity = 0.9 # ← ここを追加!
self.space.add(body, shape)
# 落下する赤いボール(動的円形オブジェクト)
mass = 1
radius = 20
inertia = pymunk.moment_for_circle(mass, 0, radius)
self.ball_body = pymunk.Body(mass, inertia)
self.ball_body.position = (self.WIDTH // 2, 400)
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.elasticity = 0.9
self.ball_shape.friction = 0.6
self.space.add(self.ball_body, self.ball_shape)
pyxel.run(self.update, self.draw)
def update(self):
dt = 1.0 / 60.0
self.space.step(dt)
if pyxel.btnp(pyxel.KEY_ESCAPE):
pyxel.quit()
def draw(self):
pyxel.cls(0)
# 地面の描画
ground_screen_y = self.HEIGHT - 100
pyxel.line(0, ground_screen_y, self.WIDTH, ground_screen_y, 7)
# ボールの描画
x, y_phys = self.ball_body.position
y = self.HEIGHT - y_phys
pyxel.circ(x, y, int(self.ball_shape.radius), 8)
if __name__ == "__main__":
App()
4.ボールに角速度と初速度を加え、落下する。画面640 x 480
設定
- 640,480 画面サイズ
- 地面、ボール
- 画面中央上から、角速度と初速度、落下
- リセットなし
03ball_angular.py
03ball_angular.py
import pyxel
import pymunk
class App:
def __init__(self):
self.WIDTH = 640
self.HEIGHT = 480
# title に変更
pyxel.init(self.WIDTH, self.HEIGHT, title="Pyxel + Pymunk Demo",fps=60)
pyxel.mouse(True)
# Pymunk SPACE と重力設定
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# 地面のセグメント
ground_y = 100
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_shape = pymunk.Segment(ground_body, (0, ground_y), (self.WIDTH, ground_y), 1)
ground_shape.friction = 0.8
ground_shape.elasticity = 0.9 # 大きくバウンド
self.space.add(ground_body, ground_shape)
# 動的な赤いボール
mass = 1
radius = 20
inertia = pymunk.moment_for_circle(mass, 0, radius)
self.ball_body = pymunk.Body(mass, inertia)
# 初期位置
self.ball_body.position = (self.WIDTH // 2, 400)
# ここで横方向の速度と角速度を設定
self.ball_body.velocity = (5.0, 0.0) # 右方向に初速度
self.ball_body.angular_velocity = -10.0 # 時計回りに回転させる(負の符号は Pymunk の座標系依存)
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.elasticity = 0.9
self.ball_shape.friction = 0.6
self.space.add(self.ball_body, self.ball_shape)
pyxel.run(self.update, self.draw)
def update(self):
dt = 1.0 / 60.0
self.space.step(dt)
if pyxel.btnp(pyxel.KEY_ESCAPE):
pyxel.quit()
def draw(self):
pyxel.cls(0)
# 地面描画
ground_screen_y = self.HEIGHT - 100
pyxel.line(0, ground_screen_y, self.WIDTH, ground_screen_y, 7)
# ボール描画
x, y_phys = self.ball_body.position
y = self.HEIGHT - y_phys
pyxel.circ(x, y, int(self.ball_shape.radius), 8)
# デバッグ: 速度と角速度(任意)
vel = self.ball_body.velocity
ang = self.ball_body.angular_velocity
pyxel.text(5, 5, f"V=({vel.x:.1f},{vel.y:.1f}) w={ang:.1f}", 7)
if __name__ == "__main__":
App()
5.ボールに角速度と初速度を加え、落下する。ボールに回転を示す線を入れる
設定
- 640,480 画面サイズ
- 地面、ボール、ボールに回転を示す線(中心から半径方向)
- 画面中央上から、角速度と初速度、落下
- リセットなし
04redball_radiusline2.py
04redball_radiusline2.py
import pyxel
import pymunk
import math
class App:
def __init__(self):
self.WIDTH = 640
self.HEIGHT = 480
# Pyxel の初期化:タイトルと FPS を指定
pyxel.init(self.WIDTH, self.HEIGHT,
title="Pyxel + Pymunk Demo",
fps=60)
# Pymunk のスペース設定は、pyxel.run の前に済ませる
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# 地面の作成
ground_y = 100
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_shape = pymunk.Segment(
ground_body,
(0, ground_y),
(self.WIDTH, ground_y),
1
)
ground_shape.friction = 0.8
ground_shape.elasticity = 0.9
self.space.add(ground_body, ground_shape)
# ボールの作成
mass = 1
radius = 20
inertia = pymunk.moment_for_circle(mass, 0, radius)
self.ball_body = pymunk.Body(mass, inertia)
self.ball_body.position = (self.WIDTH // 2, 400)
self.ball_body.velocity = (5.0, 0.0)
self.ball_body.angular_velocity = -10.0
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.elasticity = 0.9
self.ball_shape.friction = 0.6
self.space.add(self.ball_body, self.ball_shape)
# メインループ開始(update → draw を FPS=60 で呼び出し)
pyxel.run(self.update, self.draw)
def update(self):
# 1/60秒だけ物理演算を進める
dt = 1.0 / 60.0
self.space.step(dt)
# ESC で終了
if pyxel.btnp(pyxel.KEY_ESCAPE):
pyxel.quit()
def draw(self):
pyxel.cls(0)
# 地面を描画
ground_screen_y = self.HEIGHT - 100
pyxel.line(0, ground_screen_y,
self.WIDTH, ground_screen_y, 7)
# ボール位置を画面座標に変換
x_phys, y_phys = self.ball_body.position
x = x_phys
y = self.HEIGHT - y_phys
r = self.ball_shape.radius
# 1) ボール本体(赤色で塗りつぶし)
pyxel.circ(x, y, int(r), 8)
# 2) 回転確認用の半径線(白色)
angle = self.ball_body.angle
dx = r * math.cos(angle)
dy = r * math.sin(angle)
x2 = x + dx
y2 = y - dy
pyxel.line(x, y, x2, y2, 7)
if __name__ == "__main__":
App()
6.ボールに角速度と初速度を加え、落下する。リセットキーを入れる
設定
- 640,480 画面サイズ
- 地面、ボール、ボールに回転を示す線(中心から半径方向)
- 画面中央上から、角速度と初速度、落下
- スペースキーでリセットする
05redball_resetkey.py
05redball_resetkey.py
import pyxel
import pymunk
import math
class App:
def __init__(self):
self.WIDTH = 640
self.HEIGHT = 480
# Pyxel 初期化:タイトルと FPS を指定
pyxel.init(self.WIDTH, self.HEIGHT,
title="Pyxel + Pymunk Demo",
fps=60)
pyxel.mouse(True)
# Pymunk のスペースとオブジェクトを作成
self._setup_space_and_objects()
# メインループ開始
pyxel.run(self.update, self.draw)
def _setup_space_and_objects(self):
# スペース
self.space = pymunk.Space()
self.space.gravity = (0.0, -900.0)
# 地面
ground_y = 100
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_shape = pymunk.Segment(
ground_body,
(0, ground_y),
(self.WIDTH, ground_y),
1
)
ground_shape.friction = 0.8
ground_shape.elasticity = 0.9
self.space.add(ground_body, ground_shape)
# ボール(共通設定)
mass = 1
radius = 20
inertia = pymunk.moment_for_circle(mass, 0, radius)
# Body と Shape を属性に保存
self.ball_body = pymunk.Body(mass, inertia)
self.ball_shape = pymunk.Circle(self.ball_body, radius)
self.ball_shape.friction = 0.6
self.ball_shape.elasticity = 0.9
# 最初の初期化
self.reset_ball()
# スペースへ追加
self.space.add(self.ball_body, self.ball_shape)
def reset_ball(self):
"""ボールを初期位置・初速度・角速度にリセットする"""
# 初期位置
self.ball_body.position = (self.WIDTH // 2, 400)
# 初速度(右方向へ)
self.ball_body.velocity = (5.0, 0.0)
# 角速度(負で右回転)
self.ball_body.angular_velocity = -10.0
# 回転角度も 0 に戻しておく
self.ball_body.angle = 0
def update(self):
# Rキーでリセット
if pyxel.btnp(pyxel.KEY_R):
self.reset_ball()
# 物理演算を 1/60 秒進める
dt = 1.0 / 60.0
self.space.step(dt)
# ESCキーで終了
if pyxel.btnp(pyxel.KEY_ESCAPE):
pyxel.quit()
def draw(self):
pyxel.cls(0)
# 地面を描画
ground_screen_y = self.HEIGHT - 100
pyxel.line(0, ground_screen_y,
self.WIDTH, ground_screen_y, 7)
# ボールを描画
x_phys, y_phys = self.ball_body.position
x = x_phys
y = self.HEIGHT - y_phys
r = self.ball_shape.radius
# 本体(色8=赤)
pyxel.circ(x, y, int(r), 8)
# 半径線(色7=白)
angle = self.ball_body.angle
dx = r * math.cos(angle)
dy = r * math.sin(angle)
x2 = x + dx
y2 = y - dy
pyxel.line(x, y, x2, y2, 7)
# デバッグ: 速度と角速度(任意)
vel = self.ball_body.velocity
ang = self.ball_body.angular_velocity
pyxel.text(5, 5, f"V=({vel.x:.1f},{vel.y:.1f}) w={ang:.1f}", 7)
if __name__ == "__main__":
App()
