「エラーは出ていないのに、なぜか動かない」。UE開発で最も時間を奪うのは、この静かなバグです。
原因を推理で当てようとすると迷宮入りします。必要なのは推理ではなく 証拠集め 。そのための最初の道具が、Blueprintの Print String とエディタの Output Log です。この記事では、2つの道具の使い方と使い分け、そして「攻撃が当たっているのにダメージが入らない」という定番のバグを証拠から切り分ける手順を解説します。
この記事でわかること
- Print String の使い方と、 Key による画面表示の上書きテクニック
- Output Log の開き方・フィルタリング・ログカテゴリ
- C++の UE_LOG マクロと Verbosity(重要度) の使い分け
- 実践:「当たったのにダメージが入らない」を 3つの質問で切り分ける
Print Stringの基本と応用
Print String は、指定した文字列をゲーム画面の左上(とOutput Log)に出す、最も手軽なデバッグノードです。処理の流れの途中に挿むだけで、「この処理は本当に実行されたか」「この変数はいま何か」を目で確かめられます。

Event Jump → Print String(In String: "Jump! Velocity: " に Get Velocity を Append)
| パラメータ | 役割 | 使いこなし |
|---|---|---|
| In String | 表示する文字列 | どの処理 からの出力か分かる印を付ける(例: [Jump]) |
| Print to Screen / Log | 画面/Output Logへの出力切替 | 基本は両方ON。画面が邪魔ならLogのみに |
| Text Color | 画面表示の色 | 重要なメッセージだけ目立つ色に |
| Duration | 画面に残る秒数(既定2.0) | 流れの速い処理を追うときは5.0などへ |
| Key | メッセージの識別キー | 同じKeyのメッセージは上書きされる(下記) |
Keyを使った値の追跡
Key は、Print Stringをデバッグツールとして一段強くする仕掛けです。TickでHPを表示するような「毎フレーム出る」ログは、そのままでは画面を埋め尽くします。同じKeyを設定すれば、 画面には常に最新の1行だけ が表示され、変数の変化をカウンターのように追跡できます。

Output Logの活用

Print Stringが「その場の目視確認」なら、 Output Log はUE全体の情報が集まる デバッグの心臓部 です。自分のログだけでなく、エンジンの警告・エラー・アセットのロード情報まで、すべてがここに時系列で記録されます。
- 開き方: メニューの ウィンドウ → 出力ログ(Output Log)
- フィルタリング: 上部の検索バーでキーワード絞り込み。Verbosityフィルタで
Errors/Warningsだけの表示に切り替えられます - ログカテゴリ: ログは
LogTemp・LogBlueprint・LogAIなどのカテゴリ付きで記録されます。「どのシステムの発言か」で絞り込めます
Blueprintだけで開発している間も、 「動かない時はまずOutput LogのErrorとWarningを見る」 を習慣にしてください。画面のPrint Stringは流れて消えますが、ログには全部残っています。
C++でのログ出力:UE_LOGマクロ
C++側のPrint Stringに相当するのが UE_LOG マクロです。printf や std::cout はUEのログシステムに乗らないため使いません。
// ログカテゴリを定義(プロジェクト用に1つ作ると絞り込みが楽になる)
DEFINE_LOG_CATEGORY_STATIC(LogMyGame, Log, All);
// 警告レベルで、変数を埋め込んで出力
UE_LOG(LogMyGame, Warning, TEXT("Player %s damaged. HP: %f"), *PlayerName, CurrentHealth);
// エラーレベル+早期リターン(Nullチェックの定番形)
if (TargetActor == nullptr)
{
UE_LOG(LogMyGame, Error, TEXT("TargetActor is null!"));
return;
}
第二引数が Verbosity(重要度) です。重要度で色分けしておくと、あとからOutput Logのフィルタで「ErrorとWarningだけ見る」が効くようになります。

| Verbosity | 役割 | 用途の例 |
|---|---|---|
| Error | 致命的な問題(赤字で表示) | 必須リソースのロード失敗、null参照 |
| Warning | 問題の兆候(黄字で表示) | 予期しない入力値、非推奨機能の使用 |
| Display | コンソールにも出したい 情報 | 起動時の設定値の記録など |
| Log | 標準の記録 | 処理の開始・終了、値の確認 |
補足: ほかに、出力した瞬間にクラッシュさせる
Fatal、普段は非表示の詳細用Verbose/VeryVerboseもあります。まずは表の4つで十分です。
実践:「当たったのにダメージが入らない」を切り分ける
道具が揃ったところで、定番のバグを1つ捜査してみましょう。シューティングの弾でも、アクションの剣でも、RPGの魔法でも構いません——「攻撃がヒットしているように見えるのに、敵のHPが減らない」。あの現象です。

推理で「たぶんコリジョンかな……」と当てずっぽうにいじり始める前に、Print Stringで 3つの質問 に順番に答えさせます。
再現用の準備(手元に該当グラフがない方は、これだけ作れば試 せます)。敵Blueprint BP_Enemy に次の変数を用意します。
| 変数名 | 型 | 初期値 | 役割 |
|---|---|---|---|
Health | Float | 100.0 | 敵の体力 |
IncomingDamage | Float | 25.0 | 受け取ったダメージ量。武器から渡ってくる値のつもりで、ここに直接入れておきます |
bIsInvincible | Boolean | true | 無敵フラグ。 このtrueがわざと仕込んだ不具合 です |

ログを仕込んだあとのグラフは、この形になります。①と②の位置を頭に入れてから読み進めてください。

-
質問①「そのイベント、呼ばれてる?」: ヒット処理の先頭に、ま ずログを1つ挿します
Event OnHit(Overlap や Any Damage など) → Print String(In String: "Hit!") ← ★質問① → Branch(Condition: Not(bIsInvincible))Playして攻撃してみてください。画面に
Hit!が出なければ、犯人はダメージ計算より手前、 当たり判定そのもの です(→ カスタムコリジョンチャンネル) -
質問②「値はいくつ?」:
Hit!が出たなら、次はダメージ量を数字で見ます。文字列と数値は Append で繋ぎますPrint String(In String: Append(A: "Damage: ", B: ToString(IncomingDamage)))今回は
Damage: 25.0と出るはずです。数値が正しく渡っているので、犯人はもっと先にいます。もしここでDamage: 0.0と出るようなら、処理そのものは動いていて 渡している数値がゼロ なだけなので、武器データの設定ミスが濃厚です -
質問③「どっちへ進んだ?」: 値も正しいのに減らないなら、分岐の両側にログを1つずつ置いて、通った道を白状させます
Branch(Condition: Not(bIsInvincible)) → True → Print String("通った: ダメージ適用へ") → Health から IncomingDamage を引いて Set → False → Print String("通った: 無敵でスキップ") ← ★今回はこちらが出る画面に
通った: 無敵でスキップと出れば、犯人はbIsInvincibleです。初期値をfalseに直して、もう一度攻撃してみてください。Healthが100→75に減れば解決です
3つの質問はどれも30秒で仕掛けられて、答えが Yes/Noで返ってくる のが強みです。犯人の居場所が「当たり判定」「データ」「条件式」のどれかまで絞れたら、捜査は9割終わっています。仕上げにOutput Logを開いて、赤いエラー——特に Accessed None(空の参照を触った)——が出ていないかを確認しましょう。出ていれば、そのメッセージがバグの住所を教えてくれています。
ポイントは2つです。
- 一度に1つだけ疑う: 「呼ばれたか → 値は → 分岐は」の順に、疑いを1つずつ潰します。まとめて疑うと、直ったときに何が原因だったのか分からなくなります
- 捜査が終わったらPrint Stringを掃除する: 役目を終えたデバッグノードは削除するか、切断しておきます。次のバグのときに、古いログはノイズにしかなりません
ベストプラクティスとよくある間違い
| プラクティス | 効果 |
|---|---|
ログに 出どころの印 を含める([MyActor] HP: 100) | 大量のログでも発信元が一目で分かる |
| Verbosityを使い分ける(情報=Log/兆候=Warning/致命=Error) | フィルタが効き、緊急度で対応できる |
| Tickでの追跡は 必ずKeyを設定 | 画面が埋まらず、値の変化だけ追える |
bDebugMode のような デバッグ用フラグ を用意し、ログの前でチェック | フラグ1つで全ログを止められる |
よくある間違いは3つあります。①Durationを既定の2秒のままにして「一瞬で消えた」と見逃す(長くするかKeyで常駐させる)、②画面のPrint Stringだけ見てOutput LogのError/Warningを見ない、③C++で printf を使う(必ずUE_LOGで)。
おまけ:先に知っておくと良いこと
文字で分からないものは、描く。 「検知範囲がどこまでか」「敵がどちらを向いているか」といった 空間の情報は、文字にしても分かりません 。そういうときは範囲や向きをゲーム画面の中に描いてしまうのが速いです(→ Draw DebugとVisual Logger)。
- Print Stringは開発ビルド専用: パッケージ版(Shipping)では出力されません。「消し忘れたら製品に出てしまう」心配はない一方、Shipping版だけで起きる問題の調査には使えない、と覚えておきましょう
- ログはファイルにも残っている: プロジェクトの
Saved/Logs/フォルダに、実行ごとのログファイルが保存されています。「さっき閉じてしまったあのエラー」も後から読めます - 次の武器はブレークポイント: Print Stringで場所を絞ったら、その行で実行を一時停止して変数の中身を覗ける Blueprint Debugger が次の道具です → Blueprint Debuggerの使い方
まとめ
- Print String=画面でさっと、Output Log=ログでじっくり 。2つで1セット
- Tickの追跡は Key で上書き表示。C++は UE_LOG + Verbosity の色分けで「あとから絞れる」ログを書く
- バグは推理せず、 「呼ばれたか → 値は → 分岐は」 の3つの質問で証拠を集めて切り分ける
デバッグの相棒ができたら、Blueprintでよくある10のミスで「そもそも踏みやすい地雷」を先回りして知っておくのもおすすめです。
いまあなたのプロジェクトで「なぜか動かない」ままになっている処理、3つの質問のどれから聞いてみますか?