【Cocos Creator 3.8】Lifesteal(吸血攻撃)の実装:アタッチするだけで「ダメージに応じて自分のHPを自動回復」できる汎用スクリプト
この記事では、攻撃がヒットしたときに「与えたダメージの一定割合を自分のHPとして回復する」Lifesteal(吸血攻撃)コンポーネントを、Cocos Creator 3.8 + TypeScript で実装します。
このコンポーネントは、
- プレイヤーや敵キャラの「HP管理ノード」にアタッチするだけ
- 外部の GameManager やシングルトン不要
- インスペクタから HP・最大HP・吸収率・自動回復のON/OFF を調整可能
という設計になっており、「ダメージ処理から簡単にライフスティールを呼び出せる」汎用スクリプトとして使えます。
コンポーネントの設計方針
1. どのように使うコンポーネントか
本記事の Lifesteal コンポーネントは、「ダメージを与えた側」のノードにアタッチして使います。
- 攻撃ロジックがダメージを計算したあとで、
lifesteal.onDamageDealt(damageAmount);を呼び出すだけで、 - そのダメージの一定割合に応じて、このノードの HP が自動で回復されます。
このとき、HP の管理も同じコンポーネント内で完結させることで、外部スクリプトへの依存を完全になくします。
2. 外部依存をなくすためのアプローチ
以下の方針で「単体で完結する」ように設計します。
- HP・最大HP・死亡状態などの管理を Lifesteal コンポーネント自身が行う。
- 他のカスタムスクリプト(GameManager、HPManager など)には一切依存しない。
- 攻撃ロジックからは「ダメージ値を渡すだけ」でよく、HP の回復ロジックはこのコンポーネントに隠蔽する。
- UI 連携が必要な場合は、インスペクタから プログレスバー(ProgressBar)などを任意でアサインできるようにする。
そのため、ダメージ処理をしている他のスクリプトからは、
// 例)攻撃がヒットしたとき
const lifesteal = attackerNode.getComponent(Lifesteal);
if (lifesteal) {
lifesteal.onDamageDealt(damage);
}
のように呼び出すだけで機能します。(この呼び出し元はプロジェクト側で自由に実装してください)
3. インスペクタで設定可能なプロパティ設計
インスペクタから調整できるプロパティと意味は以下の通りです。
- maxHp: number
- このノードの最大HP。
- 0 より大きい値を設定してください(例: 100)。
- currentHp: number
- 現在のHP。
- 起動時に 0 以下なら自動的に
maxHpで初期化します。
- lifestealRate: number
- 与えたダメージのうち、何割を回復するか。
- 0.0 ~ 1.0 の範囲を想定(例: 0.25 → 25% 吸収)。
- 1.0 を超える値も設定可能ですが、その場合「与えたダメージ以上に回復」します。
- enableLifesteal: boolean
- 吸血効果の ON/OFF。
- テスト時に効果を簡単に無効化したい場合に便利です。
- roundToInt: boolean
- 回復量を整数に丸めるかどうか。
- ON: 四捨五入して整数にする。
- OFF: 小数のまま HP を扱う。
- showLog: boolean
- コンソールにログを出すかどうか。
- ON にすると、ダメージと回復量・現在HPなどが
console.logで表示されます。
- autoClampHp: boolean
- HP を常に 0 ~ maxHp の範囲に自動クランプするかどうか。
- ON:
currentHpが範囲外になった場合、自動で補正します。
- hpBar: ProgressBar | null
- 任意の HP バー UI(
cc.ProgressBar)。 - 設定した場合、HP が変化するたびにバーの進捗が自動更新されます。
- 未設定でも動作し、その場合は UI 更新だけ行われません。
- 任意の HP バー UI(
これらのプロパティにより、
- プレイヤー用の高HP・低吸収率
- ボス用の低HP・高吸収率
など、同じコンポーネントを様々なキャラクターに再利用できます。
TypeScriptコードの実装
以下が Lifesteal コンポーネントの完全な実装コードです。
import { _decorator, Component, ProgressBar, clamp01, clamp, log, warn } from 'cc';
const { ccclass, property } = _decorator;
/**
* Lifesteal(吸血攻撃)コンポーネント
*
* - このノードの HP を内部で管理します。
* - 攻撃が命中してダメージを与えたときに onDamageDealt(damage) を呼び出すと、
* lifestealRate に応じて HP が回復します。
* - 外部の GameManager や HP 管理クラスには依存しません。
*/
@ccclass('Lifesteal')
export class Lifesteal extends Component {
@property({
tooltip: '最大HP。このノードが持つ体力の上限値です。0 より大きい値を設定してください。',
min: 1
})
public maxHp: number = 100;
@property({
tooltip: '現在のHP。0 以下の場合、起動時に maxHp で初期化されます。'
})
public currentHp: number = 100;
@property({
tooltip: '吸収率(0.25 なら与えたダメージの 25% を回復)。1.0 を超えると与えたダメージ以上に回復します。',
min: 0
})
public lifestealRate: number = 0.25;
@property({
tooltip: '吸血効果を有効にするかどうか。OFF にすると onDamageDealt を呼んでも HP は回復しません。'
})
public enableLifesteal: boolean = true;
@property({
tooltip: '回復量を整数に丸めるかどうか。ON の場合は四捨五入して整数化します。'
})
public roundToInt: boolean = true;
@property({
tooltip: 'HP を常に 0 ~ maxHp の範囲に自動クランプするかどうか。'
})
public autoClampHp: boolean = true;
@property({
tooltip: 'ログをコンソールに出力するかどうか(ダメージ量・回復量・現在HPなど)。'
})
public showLog: boolean = true;
@property({
type: ProgressBar,
tooltip: '任意の HP バー(ProgressBar)。設定した場合、HP 変化時に自動で進捗を更新します。未設定でも動作します。'
})
public hpBar: ProgressBar | null = null;
/**
* コンポーネント初期化処理。
* - currentHp が 0 以下なら maxHp で初期化
* - hpBar が指定されている場合は存在チェック
*/
onLoad() {
// maxHp が不正な値の場合は警告を出してデフォルト値に補正
if (this.maxHp ${this.currentHp}(node: ${this.node.name})`
);
}
this.updateHpBar();
}
/**
* 外部から直接 HP を減らしたい場合に使える補助メソッド。
* (ダメージを受ける側の処理用。吸血とは直接関係ありませんが、HP 管理の汎用性を高めるために用意しています)
* @param damage 受けたダメージ量(0 以上を想定)
*/
public applyDamage(damage: number): void {
if (damage ${this.currentHp}(node: ${this.node.name})`
);
}
this.updateHpBar();
}
/**
* 外部から直接 HP を回復させたい場合に使える補助メソッド。
* (ポーションなどの回復アイテム用)
* @param amount 回復量(0 以上を想定)
*/
public heal(amount: number): void {
if (amount ${this.currentHp}(node: ${this.node.name})`
);
}
this.updateHpBar();
}
/**
* 現在の HP を 0.0 ~ 1.0 の割合で取得します。
* UI 側から参照したい場合に便利です。
*/
public getHpRatio(): number {
if (this.maxHp
コードのポイント解説
- onLoad()
maxHpが 0 以下なら 100 に補正し、警告ログを出します。currentHpが 0 以下ならmaxHpで初期化します。autoClampHpが有効なら、HP を 0 ~ maxHp にクランプします。hpBarが指定されている場合、ProgressBarコンポーネントが存在するか確認し、なければ警告を出して無効化します。
- onDamageDealt(damage: number)
- 攻撃がヒットしたときに呼び出すメインメソッドです。
enableLifestealが false、またはdamage <= 0の場合は処理をスキップします。healAmount = damage * lifestealRateで回復量を計算します。roundToIntが true の場合はMath.roundで整数に丸めます。- 計算結果が 0 以下なら回復しません(小数点以下で切り捨てられた場合など)。
- HP を加算し、
autoClampHpが有効なら 0 ~ maxHp にクランプします。 showLogが true の場合、ダメージ・回復量・HP の変化をログ出力します。- 最後に
updateHpBar()で UI を更新します。
- applyDamage(damage: number)
- 被ダメージ用の汎用メソッドです。
- 吸血とは直接関係ありませんが、HP 管理をこのコンポーネントに集約するために用意しています。
- heal(amount: number)
- ポーションなど「通常の回復処理」に使える汎用メソッドです。
- getHpRatio() / isDead()
- UI や死亡判定ロジックから簡単に参照できるようにするための補助メソッドです。
- updateHpBar()
hpBarが設定されていれば、progressを HP 割合に合わせて更新します。- HP バーを使わない場合は何も行いません。
使用手順と動作確認
ここからは、実際にエディタで Lifesteal コンポーネントを使う手順を解説します。
1. スクリプトファイルの作成
- Assets パネルで右クリックします。
- Create → TypeScript を選択します。
- ファイル名を
Lifesteal.tsにします。 - 作成された
Lifesteal.tsをダブルクリックしてエディタ(VS Code など)で開き、先ほどのコードを丸ごと貼り付けて保存します。
2. テスト用ノード(プレイヤーや敵キャラ)を作成
- Hierarchy パネルで右クリック → Create → 3D Object → Node などから、テスト用のノードを 1 つ作成します。
- 分かりやすく
Playerなどの名前にしておきます。
- 分かりやすく
- 2D ゲームであれば Create → 2D Object → Sprite でスプライトノードを作成しても構いません。
3. Lifesteal コンポーネントをアタッチ
- Hierarchy で先ほど作成した
Playerノードを選択します。 - Inspector の下部にある Add Component ボタンをクリックします。
- Custom → Lifesteal を選択してアタッチします。
4. プロパティを設定
Inspector に Lifesteal のプロパティが表示されるので、以下のように設定してみましょう。
- Max Hp:
100 - Current Hp:
100(0 のままでも起動時に自動的に 100 になります) - Lifesteal Rate:
0.3(与えたダメージの 30% を回復) - Enable Lifesteal: チェック ON
- Round To Int: チェック ON(整数で扱いたい場合)
- Auto Clamp Hp: チェック ON
- Show Log: チェック ON(動作確認時は ON を推奨)
- Hp Bar: いったん「なし」のままで OK(後で UI をつなげます)
5. 簡単な動作確認用スクリプトを追加(任意)
エディタ上で「攻撃がヒットした」ところまでは作っていない場合、テスト用に簡単なスクリプトを追加して動作を確認することができます。
例として、ゲーム開始後に一定時間ごとに「ダメージ 40 を与えた」とみなして吸血を発動させるテストコンポーネントを作ります。
- Assets パネルで右クリック → Create → TypeScript。
- ファイル名を
LifestealTester.tsにします。 - 以下のコードを貼り付けます。
import { _decorator, Component, log } from 'cc';
import { Lifesteal } from './Lifesteal';
const { ccclass, property } = _decorator;
@ccclass('LifestealTester')
export class LifestealTester extends Component {
@property({
tooltip: 'テストで与えるダメージ量。'
})
public testDamage: number = 40;
@property({
tooltip: '何秒ごとにテストダメージを与えるか。'
})
public interval: number = 2;
private _timer: number = 0;
private _lifesteal: Lifesteal | null = null;
onLoad() {
this._lifesteal = this.getComponent(Lifesteal);
if (!this._lifesteal) {
log('[LifestealTester] 同じノードに Lifesteal コンポーネントが見つかりません。テストは行われません。');
}
}
update(deltaTime: number) {
if (!this._lifesteal) {
return;
}
this._timer += deltaTime;
if (this._timer >= this.interval) {
this._timer = 0;
log('[LifestealTester] テストダメージを与えます。');
this._lifesteal.onDamageDealt(this.testDamage);
}
}
}
次に、このテスターを Player ノードにアタッチします。
- Hierarchy で
Playerノードを選択。 - Inspector → Add Component → Custom → LifestealTester を選択。
- Test Damage を
40、Interval を2などに設定。
ゲームを再生すると、2 秒おきに onDamageDealt(40) が呼ばれ、
- 回復量 = 40 × Lifesteal Rate (0.3) = 12(Round To Int の場合)
- HP が 100 → 112 → 100(Auto Clamp により 100 で頭打ち)
といったログがコンソールに表示されるはずです。
6. HP バー UI と連携する
HP バーを表示したい場合は、以下の手順で ProgressBar と連携できます。
- Canvas 配下に HP バーを作成
- Hierarchy で Canvas を右クリック → Create → UI → ProgressBar を選択。
- 作成された ProgressBar ノード(例:
HpBar)の位置やサイズを調整します。
- ProgressBar を Lifesteal にアサイン
Playerノードを選択。- Inspector で Lifesteal コンポーネントの Hp Bar プロパティの右端にある「●」ボタンをクリック。
- Hierarchy から先ほど作成した
HpBarノードをドラッグ&ドロップ、または選択してアサインします。
これで、HP が変化するたびに ProgressBar の progress が自動更新されるようになります。
まとめ
本記事では、Cocos Creator 3.8 + TypeScript で、
- 攻撃ヒット時に与えたダメージの一定割合を HP として自動回復する Lifesteal(吸血攻撃)コンポーネント
を実装しました。
ポイントは以下の通りです。
- 完全独立:
- HP 管理(maxHp / currentHp)をコンポーネント内部で完結させ、外部の GameManager や HP クラスに依存しない設計としました。
- 汎用的な API:
- 攻撃ロジックからは
onDamageDealt(damage)を呼ぶだけで吸血が発動します。 - 被ダメージや回復用に
applyDamage()、heal()も用意し、HP 管理を一本化できます。
- 攻撃ロジックからは
- インスペクタで柔軟に調整:
- lifestealRate(吸収率)、enableLifesteal、roundToInt、autoClampHp、showLog などをインスペクタから変更でき、
- 同じスクリプトをプレイヤー・敵・ボスなどに簡単に再利用できます。
- UI 連携もオプションで対応:
- ProgressBar をアサインすれば HP バーが自動更新され、未設定でも問題なく動作します。
このように、1 つのコンポーネントに「HP 管理 + 吸血ロジック」を閉じ込めることで、
- 新しいキャラクターを作るたびに複雑な HP 管理や吸血処理を書き直す必要がなくなり、
- 攻撃ロジック側は「ダメージ値を渡すだけ」で済むため、ゲーム全体のコードがすっきり整理されます。
プロジェクトに合わせて、
- クリティカルヒット時だけ吸収率を変える
- 状態異常(デバフ)で lifestealRate を一時的に 0 にする
といった拡張も簡単に行えるはずです。まずはこの記事のコードをそのままコピーして、自分のプロジェクトに組み込んでみてください。




