ぬーぶのメモ帳

フリーゲームエンジン「Godot」でプログラム経験のない素人の備忘録 最近は色々な動作を考えて試すのが好き。

【Godot】Polygon2Dをスクリプトで作ってみる

一つの疑問が浮かんで



2Dカスタム描画 — Godot Engine (stable)の日本語のドキュメント

こちらのガイドを読んでいてふと気になることが、

PoolVector2Array 使ってるし、もしかしてドロー関数だけじゃなくてポリゴン2Dやコリジョンポリゴンでも使えるんじゃ?



結論から言うとポリゴンを生成することができました。
そもそも手動でポチポチポリゴン成形するだけでも十分な気も?

でもスクリプト制御が必要になる場面もあるかもしれないし…とにかくやってみよう。

上のコードをほぼそのままでポリゴン生成を試みる。
今回は生成に失敗しても分かりやすいCollisionPolygon2Dを使用。

ポリゴンが見えるようにコリジョン形状表示も忘れないように。

onready var polygon := $CollisionPolygon2D
# ポリゴンの生成地点
onready var center = $position2D.position
# center からの半径、長さ
var radius = 80
# ポリゴン描画の開始角度と終了角度
var angle_from = -90
var angle_to = 90
# ポリゴンの生成回数
var nb_points = 10
# ポリゴンの生成地点(Vector2)を格納する配列
var points_arc = PoolVector2Array()


func _ready() -> void:
	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
	polygon.set_polygon(points_arc)

さてどうだろう

おお…いい感じ、綺麗な半円成形するのって何だかんだ大変。



ここでちょっと色気を出して、中がくり抜かれている状態を作りたくなりました。

先に内径作った後に外径作れば楽勝と思っていました。

# 内径
func _ready() -> void:
	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius / 3)
# 外径
	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
	polygon.set_polygon(points_arc)

ところが

あ、たぶんダメだこれ。
別のノードに貼り付けて当たり判定を確かめても機能しません。



ここでポリゴンを作る時ポリゴンを囲むように作る、いわゆる一筆書きでないとダメな事を思い出す。
おそらくは内径で作った配列の最後と、外径の配列の最初の位置がダメだと考えました。

何か方法はないかと思案した結果、内径の配列を全て入れた後invert()という配列の順序を逆転させるメソッドで返した後外径を加えてみました。

# 内径
func _ready() -> void:
	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * 40)
	points_arc.invert()
# 外径
	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
	polygon.set_polygon(points_arc)

さてどうか

おーよしよし上手くいったぞー
と喜んだ後に気づいたのですが、単純に内径の angle_from + i angle_to - i に変えるのが一番楽でした。(´・ω・`)しょんぼり
最初の目的であるポリゴンをスクリプトで生成する事は成功したしいいよね。

おまけ

ポリゴン生成と一緒に Raycast2D を生成してRayが物体に当たった場所が生成ポジションになるようにしました。
(敵の範囲攻撃からオブジェクトで隠れて逃れるイメージで作りたかった)


理想は衝突オブジェクトの端と端を取得してポリゴン生成する事だけどいまはこれが精一杯でした。