Godotバージョン
4.3
OSとそのバージョン
win11
使用言語
GDS
内容
Godotの3Dチュートリアルが終わったので、
試しにブロック崩しを作っていて、ブロックの操作について質問です。
ブロックを並べるのにはTileMapLayerを使っていて
動作として、物理的な判定や、表示に関しては特に問題ないのですが、
ボールがブロック(セル)に衝突した際、。衝突したブロックだけを消すことができません。
具体的には、
ブロックの挙動はボールのスクリプトで行っている
ボールがブロックに衝突した判定と、そのセルの位置は取得できる
ボールの_on_body_entard()内でlocal_to_map( position )からは( x , y )のようにセルの位置が返ってきます、例:(1,2)や(3,5)など
erase_cell(position)でセルを指定してもなにも起こらない
get_cell_sourse_id(position)などからは-1が返ってくる
body.queue_free()だとTileMapLayerの全てが消えてしまう
以上のことから、何か型の問題が起こっていることを予想しているのですが、ドキュメントや他の掲示板を見ても具体的な解決手段がわかりません。
この問題について、解決する方法を質問したいです。
もしくは、ブロックの型はTileMapLayerではなく、StaticBody2Dなどを使った方がいいのでしょうか。
TokageItLab
(Silc Lizard (Tokage) Renew)
November 25, 2024, 7:13am
2
ソースコードがないので何とも言えませんが TileMapLayer のメソッドに渡す時点での position が間違っているか、間違った TileMapLayer を取得している(裏で重複して空の TileMapLayer を作成していたりしませんか?)というような状態だと思います
問題と思われる部分のコードは
func _on_body_entered(body):
if body is TileMapLayer:
var pos = body.local_to_map(position)
body.erase_cell(pos)
print(body.get_cell_source_id(pos))
となっています
また、コード全文(githubのリポジトリ)は
extends RigidBody2D
var initial_velocity = Vector2(randf_range(-3,3),randf_range(-2,-3))
var initial_speed = 6
var screen_size
var max_speed_multiplier = 1
var linear_velocity_low_limit = 1
#var min_angle = deg_to_rad(45)
#var max_angle = deg_to_rad(180)
func _ready():
$ContactsTimer.start()
screen_size = get_viewport_rect().size
func int_process(delta) -> void:
pass
func _on_body_entered(body):
if body is TileMapLayer:
var pos = body.local_to_map(position)
This file has been truncated. show original
で確認できます
ありがとうございます!提案いただいた方向で確認してみます
TokageItLab
(Silc Lizard (Tokage) Renew)
November 25, 2024, 9:10am
5
プロジェクトを見た感じ2つ問題があります:
TileMapLayer がスケーリング(※1)されているので position が正しくありません
衝突判定直後のボールの position は貫通が防がれた状態にあり(※2)、ブロックの外にあります。なので body_entered
シグナルのコールバック内で position を利用するのではなく body_shape_entered
シグナルからコリジョンの rid を取得し、そこからタイルマップ座標を取得する必要があります。それを考慮すると、ball.gd はシグナルを繋ぎなおした後、以下のようなコードになる筈です
func _on_body_shape_entered(body_rid: RID, body: Node, body_shape_index: int, local_shape_index: int):
if body is TileMapLayer:
body.erase_cell(body.get_coords_for_body_rid(body_rid))
※1: rid を利用する方法だと position は利用しないので TileMapLayer をスケーリングしても問題ありませんが、零ベクトルや負のスケールにより計算が壊れるため、基本的にコリジョンや物理挙動を含むオブジェクトのスケーリングは推奨されない点に注意してください
※2: 貫通を許したとしても衝突開始時にはボールの中心座標はタイルに乗っていません。正規化した linear_velocity をボール半径で乗算するなどして衝突座標を予測する方法がありますが、これは太さを持たない直線の軌跡上(ボールの中心点の移動する直線上)の衝突しか見ることができないため、今回のようなコリジョンの端に衝突する可能性のあるケースでは不適切です
system
(system)
Closed
November 25, 2024, 3:20pm
6
このトピックは最後の返信から 60 分が経過したので自動的にクローズされました。新たに返信することはできません。