1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PyxelとPymunkでサンプルプログラム その10 マウスクリックで星形にimpulse

Posted at

落下する星形の下あたりで、クリックすると、なんとか浮いてくれそうな、もどかしい。

  • 画面を 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()

pyxel-20251123-165618.gif

ありがとうございます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?