1. 古いchatGPTのテンプレート
古いchatGPTを使ったAI生成メニューで、PyxelとPymunkを使った物理シミュレーション生成プロンプトを試みているところです。以下、解説してもらった。ありがとうございます。
古いChatGPT(特にGPT-3.5や初期のGPT-4)では、コメント行を自動挿入した際に**インデントの整合性が壊れる(特にupdate()やdraw()内部の空行・コメント混在時)という既知の問題があります。
この問題はモデル側の整形癖(comment insertion bias)**に起因しており、プロンプトで強くルール指定しても完全には抑制できません。
🔧 仕組みのポイント
| 問題点 | 改善方法 |
|---|---|
| コメント自動生成時にインデントずれ | 「update()とdraw()にコメント禁止」を明示 |
| コメントと空行が混ざるとズレる | 「コメント直後に空行禁止」ルールで固定 |
| 古いGPTが自動整形する | 「自動修正せず、統一して出力」と指示 |
| 出力後に文章混入 | 「コードブロックのみ出力」と強制 |
💡補足アドバイス
- **「コメント絶対禁止」**にすると最も安定しますが、上記ルールなら最低限のコメントを許可しつつも安全です。
- それでも崩れる場合は、プロンプト冒頭に出力は「コードのみ」。整形後の再修正禁止。
「コメント完全禁止」版プロンプトは、インデント崩れを完全に防ぐ効果がありますが、その副作用として、古いChatGPT(特にGPT-3.5系)は**「コメントを出すことも解説することも許されない」=“応答制約モード”**に入ってしまい、あなたが見たように
「申し訳ありませんが、コメントや解説は提供できません。」
という反応を返すようになります。
⚙️ なぜそうなるか
旧モデル(GPT-3.5や一部のGPT-4)には「安全モード判定」があり、プロンプト内で
コメント禁止/解説禁止/コードのみ
といった強い禁止指定を含むと、「指示に従って会話文を出してはいけない」と自己判断して、
**“プログラムだけを返すモード”**になります。
このため、説明を挟んだり補足を付けたりする応答が遮断されます。
以下、改良版プロンプトを作って試したみたところ、インデントはうまくいくようになりました。
🧠 改良版プロンプトのポイント
| 旧版との差 | 目的 |
|---|---|
| 「コメント完全禁止」を「一部許可」に変更 | モデルが“説明禁止モード”に入らない |
| 「update/drawコメント禁止」を明記 | 崩れやすい箇所だけを保護 |
| 「自動整形を行わず、統一出力」 | 出力中の内部リフォーマット抑止 |
| 「コード外での説明不要」と明記 | 出力前後の会話制限を解除しつつ整形維持 |
2. プロンプトの書き方比べ
大量の空行が発生したプロンプト例
「マウス左クリックした位置に長方形を発生させ、回転しながら落下する物理シミュレーションを作成してください。 Rキーでリセット時には、全オブジェクトをspaceから削除します。」
draw()メソッド内に大量の空行が発生。プロンプトが2つの独立した動作(マウスクリック生成 + リセット削除)を含み、かつ文末が途切れているため、AIが処理を分断して空行を挿入した可能性がある?
- プロンプトの構造的問題: 「〜させ、」「〜します。」という文末の混在
- 動作の独立性: 「発生」と「削除」が別の処理として認識された
- AIの整形癖: 処理を区切る際に空行を挿入する傾向
追記(2025-11-12):生成AIのfrequency penaltyを上げると、制約条件を無視して、コメント、タブふえる挙動、コード生成がおかしくなるということがわかりました。デフォルトの0で安定しています。ありがとうございます。
改善されたプロンプト案
案1: 一文で流れをつなぐ
「過去のコードを参照せず、独立したプログラムを生成してください。
マウス左クリックした位置に赤い長方形が発生し、角速度3で回転しながら落下して青い地面に衝突する物理シミュレーションを作成し、Rキーでリセット時には全オブジェクトをspaceから削除して初期状態に戻してください。」
import pyxel
import pymunk
COLOR_RED = 8
COLOR_BLUE = 5
class PhysicsSimulation:
def __init__(self):
self.width = 640
self.height = 480
pyxel.init(self.width, self.height, title="2D Physics Simulation")
pyxel.mouse(True)
self.reset()
pyxel.run(self.update, self.draw)
def reset(self):
self.space = pymunk.Space()
self.space.gravity = (0, -900)
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_body.position = (self.width / 2, 20)
ground_shape = pymunk.Poly.create_box(ground_body, (self.width, 40))
ground_shape.friction = 0.8
ground_shape.elasticity = 0.4
self.space.add(ground_body, ground_shape)
self.ground_shape = ground_shape
self.rect_bodies = []
self.rect_shapes = []
def add_rectangle(self, x, y):
size = (60, 30)
mass = 5
moment = pymunk.moment_for_box(mass, size)
body = pymunk.Body(mass, moment)
body.position = (x, y)
body.angular_velocity = 3.0
shape = pymunk.Poly.create_box(body, size)
shape.friction = 0.5
shape.elasticity = 0.6
self.space.add(body, shape)
self.rect_bodies.append(body)
self.rect_shapes.append(shape)
def update(self):
if pyxel.btnp(pyxel.KEY_R):
for body in self.rect_bodies:
for shape in body.shapes:
if shape in self.space.shapes:
self.space.remove(shape)
if body in self.space.bodies:
self.space.remove(body)
del self.rect_bodies[:]
del self.rect_shapes[:]
self.reset()
return
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
mx, my_pyxel = pyxel.mouse_x, pyxel.mouse_y
my_pymunk_y = self.height - my_pyxel
self.add_rectangle(mx, my_pymunk_y)
self.space.step(1 / 60.0)
def draw(self):
pyxel.cls(0)
bbg = self.ground_shape.bb
pyxel.rect(
int(bbg.left), int(self.height - bbg.top),
int(bbg.right - bbg.left), int(bbg.top - bbg.bottom), COLOR_BLUE)
for body, shape in zip(self.rect_bodies, self.rect_shapes):
verts_world = [body.local_to_world(v) for v in shape.get_vertices()]
verts_pyxel = [(int(x), int(self.height - y)) for x,y in verts_world]
v0,v1,v2,v3=verts_pyxel
pyxel.tri(v0[0],v0[1],v1[0],v1[1],v2[0],v2[1],COLOR_RED)
pyxel.tri(v2[0],v2[1],v3[0],v3[1],v0[0],v0[1],COLOR_RED)
if __name__ == "__main__":
PhysicsSimulation()
案2: より詳細な仕様を明記
「過去のコードを参照せず、独立したプログラムを生成してください。
640x480の画面で、青い地面(弾性0.4、摩擦0.8)を配置し、マウス左クリックで赤い長方形(60x30、質量5、弾性0.6、摩擦0.5)をクリック位置に生成し、角速度3で回転しながら落下させ、Rキーでリセット時には生成した全長方形をspaceから削除してください。」
import pyxel
import pymunk
COLOR_RED = 8
COLOR_BLUE = 5
class PhysicsSimulation:
def __init__(self):
self.width = 640
self.height = 480
pyxel.init(self.width, self.height, title="2D Physics Simulation")
pyxel.mouse(True)
self.reset()
pyxel.run(self.update, self.draw)
def reset(self):
self.space = pymunk.Space()
self.space.gravity = (0, -900)
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_body.position = (self.width / 2, 20)
ground_shape = pymunk.Poly.create_box(ground_body, (self.width, 40))
ground_shape.friction = 0.8
ground_shape.elasticity = 0.4
self.space.add(ground_body, ground_shape)
self.ground_shape = ground_shape
self.rect_bodies = []
self.rect_shapes = []
def add_rectangle(self, pos):
size = (60, 30)
mass = 5
moment = pymunk.moment_for_box(mass, size)
body = pymunk.Body(mass, moment)
body.position = pos[0], self.height - pos[1]
body.angular_velocity = 3.0
shape = pymunk.Poly.create_box(body, size)
shape.friction = 0.5
shape.elasticity = 0.6
self.space.add(body, shape)
self.rect_bodies.append(body)
self.rect_shapes.append(shape)
def update(self):
if pyxel.btnp(pyxel.KEY_R):
for body in self.rect_bodies:
for shape in body.shapes:
if shape in self.space.shapes:
self.space.remove(shape)
if body in self.space.bodies:
self.space.remove(body)
self.rect_bodies.clear()
self.rect_shapes.clear()
return
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
x, y = pyxel.mouse_x, pyxel.mouse_y
if y < self.height - 40:
self.add_rectangle((x,y))
self.space.step(1 / 60.0)
def draw(self):
pyxel.cls(0)
bbg = self.ground_shape.bb
pyxel.rect(
int(bbg.left), int(self.height - bbg.top),
int(bbg.right - bbg.left), int(bbg.top - bbg.bottom), COLOR_BLUE)
for body, shape in zip(self.rect_bodies, self.rect_shapes):
verts_world = [body.local_to_world(v) for v in shape.get_vertices()]
verts_pyxel = [(int(x), int(self.height - y)) for x,y in verts_world]
v0,v1,v2,v3=verts_pyxel
pyxel.tri(v0[0],v0[1],v1[0],v1[1],v2[0],v2[1],COLOR_RED)
pyxel.tri(v2[0],v2[1],v3[0],v3[1],v0[0],v0[1],COLOR_RED)
if __name__ == "__main__":
PhysicsSimulation()
案3: テンプレート形式(最も安定)
「過去のコードを参照せず、独立したプログラムを生成してください。
条件:
- 640x480画面
- 青い地面(色=5、弾性0.4、摩擦0.8)
- 赤い長方形(色=8、サイズ60x30、質量5、弾性0.6、摩擦0.5、角速度3)
- マウス左クリックでクリック位置に長方形生成
- Rキーでリセット時に全オブジェクトをspaceから削除
- マウスカーソル表示
」
import pyxel
import pymunk
COLOR_RED = 8
COLOR_BLUE = 5
class PhysicsSimulation:
def __init__(self):
self.width = 640
self.height = 480
pyxel.init(self.width, self.height, title="2D Physics Simulation")
pyxel.mouse(True)
self.reset()
pyxel.run(self.update, self.draw)
def reset(self):
if hasattr(self, "space"):
for body in self.space.bodies[:]:
if body.body_type != pymunk.Body.STATIC:
for shape in body.shapes[:]:
self.space.remove(shape)
self.space.remove(body)
for shape in self.ground_shapes[:]:
self.space.remove(shape)
for body in [self.ground_body]:
if body is not None:
self.space.remove(body)
self.space = pymunk.Space()
self.space.gravity = (0, -900)
ground_y = 20
ground_height = 40
ground_width = self.width
ground_body = pymunk.Body(body_type=pymunk.Body.STATIC)
ground_body.position = (self.width / 2, ground_y)
ground_shape = pymunk.Poly.create_box(ground_body, (ground_width, ground_height))
ground_shape.friction = 0.8
ground_shape.elasticity = 0.4
self.space.add(ground_body, ground_shape)
self.ground_body = ground_body
self.ground_shapes = [ground_shape]
self.rect_bodies = []
self.rect_shapes = []
def add_rectangle(self, pos):
size = (60, 30)
mass = 5
moment = pymunk.moment_for_box(mass, size)
body = pymunk.Body(mass, moment)
x, y_pyxel = pos
y_pymunk = self.height - y_pyxel
body.position = (x, y_pymunk)
body.angular_velocity = 3.0
shape = pymunk.Poly.create_box(body, size)
shape.friction=0.5
shape.elasticity=0.6
self.space.add(body, shape)
self.rect_bodies.append(body)
self.rect_shapes.append(shape)
def update(self):
if pyxel.btnp(pyxel.KEY_R):
for body in list(self.rect_bodies):
for shape in list(body.shapes):
if shape in self.space.shapes:
try:
self.space.remove(shape)
except Exception:
pass
if body in self.space.bodies:
try:
self.space.remove(body)
except Exception:
pass
del self.rect_bodies[:]
del self.rect_shapes[:]
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
mx=pyxel.mouse_x
my=pyxel.mouse_y
if 0<=mx<self.width and 0<=my<self.height:
self.add_rectangle((mx,my))
for i,b in enumerate(list(self.rect_bodies)):
if b.position.y < -100 or b.position.x < -100 or b.position.x >self.width+100 or b.position.y >self.height+100:
shapes_to_remove=list(b.shapes)[:]
for s in shapes_to_remove:
try:self.space.remove(s)
except Exception:pass
try:self.space.remove(b)
except Exception:pass
del_index=None
try:del_index=self.rect_bodies.index(b)
except Exception:pass
if del_index is not None and del_index<len(self.rect_shapes):
del self.rect_bodies[del_index]
del self.rect_shapes[del_index]
dt=1/60.0
steps=10
sub_dt=dt/steps
for _ in range(steps):
try:self.space.step(sub_dt)
except Exception:pass
def draw(self):
pyxel.cls(0)
bb=self.ground_shapes[0].bb
pyxel.rect(
int(bb.left),
int(self.height - bb.top),
int(bb.right - bb.left),
int(bb.top - bb.bottom),
COLOR_BLUE,
)
for i,(body,shape) in enumerate(zip(self.rect_bodies,self.rect_shapes)):
verts=[body.local_to_world(v)for v in shape.get_vertices()]
verts_pyxel=[(int(x),int(self.height-y))for x,y in verts]
v0,v1,v2,v3=verts_pyxel
pyxel.tri(v0[0],v0[1],v1[0],v1[1],v2[0],v2[1],COLOR_RED)
pyxel.tri(v2[0],v2[1],v3[0],v3[1],v0[0],v0[1],COLOR_RED)
if __name__=="__main__":
PhysicsSimulation()
3.プロンプト設計ガイド(AIが解釈する参考規則)
-
文を短く切らず、「〜し、〜して…」のように1つの流れにまとめる
-
「〜を作成します。」のような独立文を連続させない(整形崩れの原因)
-
「マウスで発生 → 落下 → リセット → 地面追加」のように時系列に沿って記述する
-
主目的を最初に書き、補足的要素は「さらに」「加えて」などで接続
-
「過去のコードを参照しないでください」を明記すると安定する
-
既存コードを変更・追加するような指示(例:〜を付加してください)は避け、**『過去のコードを参照せず新しく生成してください』**と明示すると構造が安定します
-
位置指定を含むときは、『左下付近からボールを投げ上げる』のように動作主体(ボールなど)を明確にし、数値座標または方位表現(左下・右上など)で書くと誤解を防げます
一歩一歩です。ありとうございます。


