【Cocos Creator 3.8】DamageFlash(被弾点滅)の実装:アタッチするだけで「ダメージ時にスプライトを白/赤くフラッシュさせる」汎用スクリプト
このガイドでは、任意のノードにアタッチするだけで「ダメージを受けたときにスプライトの色を一時的に白や赤に変えて点滅させる」DamageFlash コンポーネントを実装します。
外部の GameManager やシングルトンには一切依存せず、インスペクタから設定&API呼び出しだけで完結する設計です。
コンポーネントの設計方針
1. 機能要件の整理
- このコンポーネントをアタッチしたノード(または任意の指定ノード)の
Spriteコンポーネントの色(Color / Modulate)を一時的に変更する。 - 「ダメージを受けた瞬間」に外部スクリプトから
trigger()を呼ぶだけでフラッシュが始まる。 - フラッシュ中は元の色から指定色(白 or 赤など)へ変化し、一定時間後に元の色へ戻す。
- 複数回連続でダメージを受けた場合の挙動をオプションで制御できる(上書き/無視)。
- 外部依存は一切なし。必要な設定はすべてインスペクタから行う。
- 対象ノードに Sprite が無い場合は、エラーログを出して処理をスキップする(防御的実装)。
2. 設計アプローチ
- 対象とする Sprite
- デフォルトでは「このコンポーネントがアタッチされているノード」の
Spriteを対象にする。 - インスペクタで
targetNodeを指定した場合は、そちらのSpriteを対象にする。
- デフォルトでは「このコンポーネントがアタッチされているノード」の
- 色の変化方式
- フラッシュ色(例:白 or 赤)と、元の色を保持しておき、一定時間後に元の色へ戻す。
- 「点滅回数」と「1回あたりのON/OFF時間」を指定して、ON/OFFを繰り返す方式にする。
- トリガーAPI
trigger(): 外部から呼び出してフラッシュを開始する。triggerIfIdle(): すでにフラッシュ中の場合は新規フラッシュを無視する。stop(): 手動でフラッシュ処理を中断し、元の色に戻す。
- 時間管理
update(deltaTime)で経過時間を管理し、ON/OFFの切り替えを行う。- コルーチンや Tween には依存せず、単純なステートマシンで完結させる。
3. インスペクタで設定可能なプロパティ
targetNode: Node | null- フラッシュ対象の
Spriteを持つノード。 - null の場合は「このコンポーネントが付いているノード」を自動で対象にする。
- フラッシュ対象の
flashColor: Color- フラッシュ時に一時的に変更する色。
- デフォルト:
Color.WHITE(白フラッシュ)。 - 赤フラッシュにしたい場合は
(255, 0, 0)などに設定。
flashDuration: number- 1回の「ON状態」の長さ(秒)。
- 例:
0.08秒など。
flashCount: number- フラッシュの ON/OFF を何回繰り返すか。
- 例:
3なら「ON/OFF を 3 回」行う。
overrideWhileFlashing: booleantrue:フラッシュ中にtrigger()が呼ばれた場合、現在のフラッシュをリセットして再スタート。false:フラッシュ中のtrigger()呼び出しは無視。
autoRestoreColorOnDisable: boolean- コンポーネントが
onDisable/onDestroyされたときに、元の色に戻すかどうか。 - 予期せぬ破棄時に色が変わりっぱなしになるのを防ぐために
trueを推奨。
- コンポーネントが
logWarningIfNoSprite: boolean- 対象ノードに
Spriteが存在しない場合にconsole.warnを出すかどうか。 - 大量のオブジェクトに付ける場合、ログがうるさいと感じたら
falseにできる。
- 対象ノードに
TypeScriptコードの実装
import { _decorator, Component, Node, Sprite, Color, CCFloat, CCInteger } from 'cc';
const { ccclass, property } = _decorator;
/**
* DamageFlash
* ダメージ時に Sprite の色を一時的に変更してフラッシュさせる汎用コンポーネント。
*
* 使用方法:
* - 対象ノード (Sprite を持つ) にこのコンポーネントをアタッチする。
* - ダメージ処理などから `getComponent(DamageFlash)?.trigger();` を呼び出す。
*/
@ccclass('DamageFlash')
export class DamageFlash extends Component {
@property({
type: Node,
tooltip: 'フラッシュ対象の Sprite を持つノード。\n未設定の場合、このコンポーネントが付いているノードを使用します。'
})
public targetNode: Node | null = null;
@property({
tooltip: 'フラッシュ時に一時的に変更する色です。\n白フラッシュ: (255, 255, 255)\n赤フラッシュ: (255, 0, 0) などに設定してください。'
})
public flashColor: Color = new Color(255, 255, 255, 255);
@property({
type: CCFloat,
tooltip: '1回のフラッシュON状態の長さ(秒)です。\n小さいほど高速に点滅します。'
})
public flashDuration: number = 0.08;
@property({
type: CCInteger,
tooltip: 'ON/OFF の切り替え回数です。\n3 なら「ON/OFF を3回」行います。'
})
public flashCount: number = 3;
@property({
tooltip: 'フラッシュ中に trigger() が呼ばれたときの挙動です。\nON: 現在のフラッシュをリセットして再スタート\nOFF: フラッシュ中の trigger() 呼び出しは無視します。'
})
public overrideWhileFlashing: boolean = true;
@property({
tooltip: 'コンポーネントが無効化/破棄されたときに、元の色に自動で戻すかどうか。'
})
public autoRestoreColorOnDisable: boolean = true;
@property({
tooltip: '対象ノードに Sprite が存在しない場合に警告ログを表示するかどうか。'
})
public logWarningIfNoSprite: boolean = true;
// 内部状態管理用
private _sprite: Sprite | null = null;
private _originalColor: Color | null = null;
private _isFlashing: boolean = false;
private _elapsedInCurrentPhase: number = 0;
private _currentFlashIndex: number = 0;
private _isOnPhase: boolean = false; // true: フラッシュ色, false: 元の色
onLoad() {
// 対象ノードが未設定なら自ノードを使う
const nodeToUse = this.targetNode ?? this.node;
// Sprite の取得を試みる
this._sprite = nodeToUse.getComponent(Sprite);
if (!this._sprite) {
if (this.logWarningIfNoSprite) {
console.warn(
`[DamageFlash] Sprite が見つかりません。` +
` ノード名="${nodeToUse.name}" に Sprite コンポーネントを追加してください。`
);
}
return;
}
// 元の色を保存
this._originalColor = this._sprite.color.clone();
}
start() {
// start 時点で Sprite がまだ無い場合、再取得を試みる(動的に追加されたケースへの対応)
if (!this._sprite) {
const nodeToUse = this.targetNode ?? this.node;
this._sprite = nodeToUse.getComponent(Sprite);
if (this._sprite) {
this._originalColor = this._sprite.color.clone();
} else if (this.logWarningIfNoSprite) {
console.warn(
`[DamageFlash] start 時点でも Sprite が見つかりません。` +
` ノード名="${nodeToUse.name}" に Sprite コンポーネントを追加してください。`
);
}
}
}
update(deltaTime: number) {
if (!this._isFlashing || !this._sprite || !this._originalColor) {
return;
}
// 時間経過の更新
this._elapsedInCurrentPhase += deltaTime;
// 現在のフェーズが終了したか?
if (this._elapsedInCurrentPhase >= this.flashDuration) {
// フェーズ終了 → 色を切り替える
this._elapsedInCurrentPhase = 0;
this._isOnPhase = !this._isOnPhase;
if (this._isOnPhase) {
// ON フェーズに入った
this._sprite.color = this.flashColor;
} else {
// OFF フェーズに入った(元の色へ)
this._sprite.color = this._originalColor;
// 1回分の ON/OFF が完了したのでカウンタを進める
this._currentFlashIndex++;
// 規定回数に達したらフラッシュ終了
if (this._currentFlashIndex >= this.flashCount) {
this._isFlashing = false;
}
}
}
}
onEnable() {
// 有効化時に Sprite がまだ取得されていなければ再取得を試みる
if (!this._sprite) {
const nodeToUse = this.targetNode ?? this.node;
this._sprite = nodeToUse.getComponent(Sprite);
if (this._sprite) {
this._originalColor = this._sprite.color.clone();
}
}
}
onDisable() {
// 無効化時に元の色へ戻す
if (this.autoRestoreColorOnDisable) {
this.restoreOriginalColor();
}
this._isFlashing = false;
}
onDestroy() {
// 破棄時にも元の色へ戻す(念のため)
if (this.autoRestoreColorOnDisable) {
this.restoreOriginalColor();
}
this._isFlashing = false;
}
/**
* 外部から呼び出してフラッシュを開始する。
* overrideWhileFlashing の設定に従い、フラッシュ中の再トリガーの挙動が変わります。
*/
public trigger(): void {
if (!this._sprite) {
if (this.logWarningIfNoSprite) {
const nodeToUse = this.targetNode ?? this.node;
console.warn(
`[DamageFlash] trigger() が呼ばれましたが Sprite が見つかりません。` +
` ノード名="${nodeToUse.name}" に Sprite コンポーネントを追加してください。`
);
}
return;
}
if (this._isFlashing && !this.overrideWhileFlashing) {
// フラッシュ中は無視する設定
return;
}
// 元の色を最新の値で保存しておく(外部で色が変えられている可能性に対応)
if (!this._originalColor) {
this._originalColor = this._sprite.color.clone();
} else {
this._originalColor.set(this._sprite.color);
}
// 状態を初期化してフラッシュ開始
this._isFlashing = true;
this._elapsedInCurrentPhase = 0;
this._currentFlashIndex = 0;
this._isOnPhase = true;
// すぐにフラッシュ色を適用
this._sprite.color = this.flashColor;
}
/**
* 現在フラッシュ中でなければフラッシュを開始する。
* フラッシュ中なら何もしません。
*/
public triggerIfIdle(): void {
if (this._isFlashing) {
return;
}
this.trigger();
}
/**
* フラッシュを強制的に停止し、元の色に戻します。
*/
public stop(): void {
this._isFlashing = false;
this.restoreOriginalColor();
}
/**
* 内部的に保持している元の色を Sprite に反映します。
*/
private restoreOriginalColor(): void {
if (this._sprite && this._originalColor) {
this._sprite.color = this._originalColor;
}
}
}
主要メソッドの解説
onLoad()targetNodeが未設定なら自ノードを対象にする。Spriteを取得し、見つかれば「元の色」を保存。- 見つからなければ設定に応じて
console.warnを出力。
start()onLoad時点で Sprite が無かった場合、動的追加されたケースを考慮して再取得を試みる。
update(deltaTime)- フラッシュ中のみ動作。
flashDurationごとに ON/OFF を切り替え、OFF に切り替わるたびにflashCountをカウント。- 指定回数の ON/OFF が完了したらフラッシュを終了。
trigger()- 外部からのフラッシュ開始API。
overrideWhileFlashingがfalseのとき、フラッシュ中の呼び出しは無視。- 元の色を「現在の Sprite の色」で更新してからフラッシュを開始するため、外部で色を変えていても正しく戻せる。
triggerIfIdle()- 「フラッシュ中なら何もしない」安全なトリガー用API。
- 連打系のダメージ処理で、点滅の重なりを避けたいときに便利。
stop()/restoreOriginalColor()- フラッシュを強制停止して元の色に戻す。
onDisable/onDestroyからも呼ばれ、色が変わりっぱなしになるのを防ぐ。
使用手順と動作確認
1. スクリプトファイルの作成
- エディタ上部の Assets パネルで、任意のフォルダ(例:
assets/scripts)を右クリックします。 - Create → TypeScript を選択し、ファイル名を
DamageFlash.tsにします。 - 自動生成されたファイルをダブルクリックで開き、内容をすべて削除して、前述の
DamageFlashコードを貼り付けて保存します。
2. テスト用ノード(Sprite)の作成
- Hierarchy パネルで右クリック → Create → 2D Object → Sprite を選択します。
- 作成された Sprite ノードに分かりやすい名前(例:
Player)を付けます。 - Inspector で Sprite コンポーネントの
SpriteFrameに任意の画像を設定します。
3. DamageFlash コンポーネントのアタッチ
- Hierarchy で先ほど作成した
Playerノードを選択します。 - Inspector の下部にある Add Component ボタンをクリックします。
- Custom カテゴリから DamageFlash を選択して追加します。
4. インスペクタでプロパティを設定
Player ノードを選択した状態で、Inspector の DamageFlash コンポーネントを確認し、以下のように設定してみます。
Target Node:nullのまま(空欄)- この場合、自ノード(Player)の Sprite が自動で対象になります。
Flash Color:- 白フラッシュ → R=255, G=255, B=255, A=255(デフォルトのまま)
- 赤フラッシュ → R=255, G=0, B=0, A=255 に変更
Flash Duration:0.08(または好みで0.05〜0.15程度)Flash Count:3(ON/OFF を3回)Override While Flashing:true(連続ダメージで上書きしたい場合)Auto Restore Color On Disable:trueLog Warning If No Sprite:true
5. ダメージ時にフラッシュを発生させるテストコード
フラッシュを確認するために、簡単なテストスクリプトを用意します(このステップは任意ですが、動作確認に便利です)。
- 再度 Assets パネルで右クリック → Create → TypeScript を選択し、
DamageFlashTester.tsというファイルを作成します。 - 以下のテストコードを貼り付けます。
import { _decorator, Component, input, Input, EventKeyboard, KeyCode } from 'cc';
import { DamageFlash } from './DamageFlash';
const { ccclass } = _decorator;
@ccclass('DamageFlashTester')
export class DamageFlashTester extends Component {
private _damageFlash: DamageFlash | null = null;
onLoad() {
this._damageFlash = this.getComponent(DamageFlash);
if (!this._damageFlash) {
console.warn('[DamageFlashTester] 同じノードに DamageFlash コンポーネントを追加してください。');
}
}
start() {
// キーボード入力を監視
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
}
onDestroy() {
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
}
private onKeyDown(event: EventKeyboard) {
if (!this._damageFlash) {
return;
}
// スペースキーでフラッシュを発生させる
if (event.keyCode === KeyCode.SPACE) {
this._damageFlash.trigger();
}
}
}
テスターのアタッチ
- Hierarchy で
Playerノードを選択します。 - Inspector の Add Component → Custom → DamageFlashTester を追加します。
実行して確認
- エディタ上部の Play ボタンを押してゲームを再生します。
- ゲームビューが表示されたら、キーボードの Space キーを押します。
- 設定した色(白 or 赤)で Sprite が数回点滅し、元の色に戻ることを確認してください。
6. 実際のゲームへの組み込み例
実際のダメージ処理スクリプトからは、以下のように呼び出すだけで利用できます。
// 例: Player.ts 内のダメージ処理
import { _decorator, Component } from 'cc';
import { DamageFlash } from './DamageFlash';
const { ccclass } = _decorator;
@ccclass('Player')
export class Player extends Component {
private _damageFlash: DamageFlash | null = null;
onLoad() {
this._damageFlash = this.getComponent(DamageFlash);
}
public takeDamage(amount: number) {
// HP 処理など...
// this.hp -= amount;
// ダメージ演出としてフラッシュ
this._damageFlash?.trigger();
}
}
まとめ
DamageFlash コンポーネントは、
- Sprite を持つノードにアタッチして、ダメージ時に
trigger()を呼ぶだけで、
「白/赤フラッシュ」の被弾演出を簡単に追加できます。 - フラッシュ色・時間・回数・上書き挙動などをすべてインスペクタから調整できるため、
敵キャラ・プレイヤー・ギミックなど、どのノードにも再利用可能です。 - 外部の GameManager やシングルトンに依存しない独立コンポーネントなので、
プロジェクト間のコピペやチーム内での共有も容易です。
このコンポーネントをベースに、
- アルファ値だけを変える「点滅(フェードイン/アウト)」
- TimeScale に影響されない「リアルタイムフラッシュ」
- シェーダーと組み合わせた「エミッション強調フラッシュ」
など、よりリッチな演出へ拡張していくこともできます。
まずはこの DamageFlash をプロジェクトに組み込んで、被弾演出の標準装備として活用してみてください。




