落下する星形の下あたりで、クリックすると、なんとか浮いてくれそうな、もどかしい。
- 画面を 640×480 に拡大
- 床は y=450 に設定し、画面下 30px をすべて覆う四角形として描画
- 星型の三角形頂点は元のほぼ3倍にして(12→36px など)、大きさを調整
- 重力は元の400→800 にし、見た目上の落下速度が速くならないよう補正
- STAR の質量・慣性モーメントも適宜調整しています。
- マウスクリックでインパルスを与え、スペースキーでリセットします。
# -*- coding: utf-8 -*-
# star_compound_pymunk_colors_scaled.py
# pip install pyxel pymunk
import pyxel
import pymunk
import math
class App:
def __init__(self):
# 画面を 640×480 に拡大
self.WIDTH = 640
self.HEIGHT = 480
pyxel.init(self.WIDTH, self.HEIGHT,
title="Pyxel + pymunk: Colored Star Shape (Scaled)")
pyxel.mouse(True)
self.space = pymunk.Space()
# 下向き重力も増やして見栄えを維持
self.space.gravity = (0, 800)
# --- 床 (y=450) ---
floor_y = 450
floor = pymunk.Segment(self.space.static_body,
(0, floor_y),
(self.WIDTH, floor_y),
0)
floor.elasticity = 0.7
floor.friction = 0.9
self.space.add(floor)
# --- 星の複合剛体を作成 ---
# スタート位置も中央付近に
self.create_star_body((self.WIDTH // 2, 200))
pyxel.run(self.update, self.draw)
def create_star_body(self, pos):
mass = 6.0
# 星のサイズに合わせて慣性モーメントを計算
# moment_for_poly を使っても良い
moment = pymunk.moment_for_box(mass, (72, 72))
self.body = pymunk.Body(mass, moment)
self.body.position = pos
self.body.angular_velocity = 2.5
self.body.velocity = (60, 0)
self.space.add(self.body)
# 星を構成する 5 つの三角形(元の頂点を3倍に)
tris = [
[(0, -36), (12, -6), (-12, -6)], # 上
[(12, -6), (36, 0), (12, 6)], # 右上
[(12, 6), (24, 30), (0, 15)], # 右下
[(-12, 6), (-24, 30), (0, 15)], # 左下
[(-12, -6), (-36, 0), (-12, 6)], # 左上
]
# 赤→青系の色を適度に選択
colors = [8, 9, 10, 11, 12]
self.shapes = []
for tri, col in zip(tris, colors):
shape = pymunk.Poly(self.body, tri)
shape.elasticity = 0.8
shape.friction = 0.9
shape.color = col
self.space.add(shape)
self.shapes.append(shape)
def update(self):
# SPACE でリセット
if pyxel.btnp(pyxel.KEY_SPACE):
# 再配置
self.body.position = (self.WIDTH // 2, 200)
self.body.velocity = (60, 0)
self.body.angle = 0
self.body.angular_velocity = 2.5
# 左クリックで押す
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
mx, my = pyxel.mouse_x, pyxel.mouse_y
self.apply_click_impulse(mx, my)
# 物理ステップ
self.space.step(1 / 60)
def apply_click_impulse(self, mx, my):
x, y = self.body.position
dx = x - mx
dy = y - my
dist = math.hypot(dx, dy) + 1e-3
force = 1200 / (dist + 40)
impulse = (dx * force, dy * force)
self.body.apply_impulse_at_world_point(impulse, (mx, my))
def draw(self):
# 背景黒
pyxel.cls(0)
# 地面を描画(幅640, 高さ30)
pyxel.rect(0, 450, self.WIDTH, 30, 5)
# 星型を描画
x, y = self.body.position
angle = self.body.angle
for shape in self.shapes:
vs = shape.get_vertices()
pts = []
for vx, vy in vs:
# 回転・平行移動
rx = x + math.cos(angle) * vx - math.sin(angle) * vy
ry = y + math.sin(angle) * vx + math.cos(angle) * vy
pts.append((int(rx), int(ry)))
# 三角形ごとに色分け
pyxel.tri(pts[0][0], pts[0][1],
pts[1][0], pts[1][1],
pts[2][0], pts[2][1],
shape.color)
# マウスカーソル
pyxel.circ(pyxel.mouse_x, pyxel.mouse_y, 3, 7)
# 操作説明
pyxel.text(10, 10, "Click: push star | SPACE: reset", 6)
if __name__ == "__main__":
App()
ありがとうございます。
