【Cocos Creator】アタッチするだけ!Tooltip (ツールチップ)の実装方法【TypeScript】

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

【Cocos Creator 3.8】Tooltipコンポーネントの実装:アタッチするだけでマウスホバー時にツールチップテキストを表示する汎用スクリプト

このガイドでは、任意のノードにアタッチするだけで「マウスホバーしたときにツールチップを表示する」機能を実現する Tooltip コンポーネントを実装します。

専用のTooltipレイヤー(キャンバス上に自動生成されるノード)にテキストが表示され、マウス位置に追従しながら、マウスが離れたら自動的に非表示になります。UIボタンやアイコン、ステータス表示など、さまざまな場面で再利用できる汎用コンポーネントです。

コンポーネントの設計方針

実現したい機能

  • ノードに Tooltip をアタッチすると、そのノードにマウスカーソルを乗せたときだけツールチップテキストを表示する。
  • ツールチップは専用の「Tooltipレイヤー」ノード(UI上の最前面)に表示される。
  • マウス位置に追従し、画面端でははみ出さないように簡易的に位置調整する。
  • テキスト内容や見た目(背景色・文字色・フォントサイズ・パディングなど)はインスペクタから調整可能。
  • 外部のGameManagerやシングルトンに依存せず、このスクリプト単体で完結する。

外部依存をなくすためのアプローチ

  • Tooltipレイヤー用のノード(背景+Label)は、必要になったタイミングでスクリプトが自動生成する。
  • 既に同名のTooltipレイヤーノードが存在する場合は、それを利用する。
  • Canvasが見つからない場合はエラーログを出し、処理を中断する(エディタでCanvasを用意してもらう)。
  • イベント登録(マウス/タッチ)は、アタッチ先ノード自身に対して行う。
  • PC/モバイル両対応のため、マウスイベント+タッチイベントをサポートする。

インスペクタで設定可能なプロパティ設計

Tooltipコンポーネントに用意する主な @property は以下の通りです。

  • tooltipText: string
    • 表示するツールチップの本文。
    • 空文字の場合はツールチップを表示しない。
  • followMouse: boolean
    • オン: マウス位置に追従してツールチップを移動。
    • オフ: 表示時の位置で固定。
  • offsetX, offsetY: number
    • マウス位置(またはターゲットノード中心)からの表示オフセット(ピクセル)。
    • デフォルト: (16, -16) でマウスカーソル右下に表示されるイメージ。
  • maxWidth: number
    • ツールチップの最大幅(ピクセル)。
    • 0以下の場合は制限なし。長文で改行させたい場合に使用。
  • fontSize: number
    • ツールチップテキストのフォントサイズ。
  • paddingX, paddingY: number
    • 背景とテキストの間の余白(ピクセル)。
    • 背景サイズはテキストサイズ+パディングで自動調整。
  • backgroundColor: Color
    • 背景の色(半透明推奨)。
  • textColor: Color
    • テキストの色。
  • useTouchAsHover: boolean
    • モバイルなどマウスがない環境で、タッチ開始をホバー扱いにするか。
    • オンにすると TOUCH_START で表示、TOUCH_END/CANCEL で非表示。
  • showDelay: number
    • ホバーしてからツールチップが表示されるまでの遅延時間(秒)。
    • 0で即時表示。
  • hideDelay: number
    • ホバー解除してからツールチップを隠すまでの遅延時間(秒)。
    • 0で即時非表示。

これらをすべてインスペクタから調整できるようにし、外部の設定ファイルやマネージャに依存しない設計にします。

TypeScriptコードの実装


import {
    _decorator,
    Component,
    Node,
    Label,
    Color,
    UITransform,
    UIOpacity,
    EventMouse,
    EventTouch,
    EventTarget,
    input,
    Input,
    Vec2,
    Vec3,
    Canvas,
    Widget,
    director,
    view,
    macro,
} from 'cc';
const { ccclass, property } = _decorator;

/**
 * Tooltip
 * 任意のノードにアタッチすると、マウスホバー/タッチ時に
 * 画面上部のTooltipレイヤーにテキストを表示する汎用コンポーネント。
 */
@ccclass('Tooltip')
export class Tooltip extends Component {

    @property({
        tooltip: 'ツールチップに表示するテキスト。空文字の場合は表示されません。',
    })
    public tooltipText: string = '';

    @property({
        tooltip: 'マウス位置に追従させるかどうか。',
    })
    public followMouse: boolean = true;

    @property({
        tooltip: 'マウス(またはターゲットノード中心)からのX方向オフセット(ピクセル)。',
    })
    public offsetX: number = 16;

    @property({
        tooltip: 'マウス(またはターゲットノード中心)からのY方向オフセット(ピクセル)。\n負の値でカーソルより上側に表示されます。',
    })
    public offsetY: number = -16;

    @property({
        tooltip: 'ツールチップの最大幅(ピクセル)。0以下で制限なし。',
    })
    public maxWidth: number = 300;

    @property({
        tooltip: 'ツールチップテキストのフォントサイズ。',
    })
    public fontSize: number = 18;

    @property({
        tooltip: '背景とテキストの左右パディング(ピクセル)。',
    })
    public paddingX: number = 8;

    @property({
        tooltip: '背景とテキストの上下パディング(ピクセル)。',
    })
    public paddingY: number = 4;

    @property({
        tooltip: '背景色(半透明推奨)。',
    })
    public backgroundColor: Color = new Color(0, 0, 0, 200);

    @property({
        tooltip: 'テキスト色。',
    })
    public textColor: Color = new Color(255, 255, 255, 255);

    @property({
        tooltip: 'モバイル環境などで、タッチ開始をホバー扱いにするかどうか。',
    })
    public useTouchAsHover: boolean = true;

    @property({
        tooltip: 'ホバーしてからツールチップが表示されるまでの遅延時間(秒)。',
        min: 0,
    })
    public showDelay: number = 0.2;

    @property({
        tooltip: 'ホバー解除してからツールチップを隠すまでの遅延時間(秒)。',
        min: 0,
    })
    public hideDelay: number = 0.1;

    // 内部用: Tooltipレイヤー関連
    private static _tooltipRoot: Node | null = null;
    private static _tooltipLabel: Label | null = null;
    private static _tooltipBg: Node | null = null;
    private static _uiTransformRoot: UITransform | null = null;
    private static _uiTransformBg: UITransform | null = null;
    private static _uiOpacity: UIOpacity | null = null;

    // 内部状態
    private _hovered: boolean = false;
    private _showTimer: number = 0;
    private _hideTimer: number = 0;
    private _currentPointerPos: Vec2 = new Vec2();
    private _registeredGlobalMouseMove: boolean = false;

    onLoad() {
        // Tooltipレイヤーの初期化
        this.ensureTooltipLayer();
        // イベント登録
        this.registerEvents();
    }

    onEnable() {
        this.registerEvents();
    }

    onDisable() {
        this.unregisterEvents();
        // 自分が無効化されたらツールチップも隠す
        if (Tooltip._tooltipRoot) {
            this.hideTooltipImmediate();
        }
    }

    onDestroy() {
        this.unregisterEvents();
    }

    update(dt: number) {
        if (!Tooltip._tooltipRoot || !Tooltip._tooltipLabel || !Tooltip._uiTransformRoot) {
            return;
        }

        // 表示・非表示の遅延処理
        if (this._hovered) {
            if (this.showDelay > 0) {
                this._showTimer += dt;
                if (this._showTimer >= this.showDelay) {
                    this.showTooltip();
                }
            } else {
                this.showTooltip();
            }
            // ホバー中は非表示タイマーをリセット
            this._hideTimer = 0;
        } else {
            if (this.hideDelay > 0) {
                if (this.isTooltipVisible()) {
                    this._hideTimer += dt;
                    if (this._hideTimer >= this.hideDelay) {
                        this.hideTooltipImmediate();
                    }
                }
            } else {
                this.hideTooltipImmediate();
            }
        }

        // マウス追従
        if (this.followMouse && this.isTooltipVisible()) {
            this.updateTooltipPosition();
        }
    }

    /**
     * Tooltipレイヤー(Canvas直下)を確保する。
     * 既に存在すれば再利用し、なければ自動生成する。
     */
    private ensureTooltipLayer() {
        if (Tooltip._tooltipRoot && Tooltip._tooltipLabel && Tooltip._uiTransformRoot) {
            return;
        }

        // Canvasの取得
        const scene = director.getScene();
        if (!scene) {
            console.error('[Tooltip] シーンがロードされていません。Tooltipレイヤーを作成できません。');
            return;
        }

        let canvasNode: Node | null = null;
        for (const child of scene.children) {
            const canvas = child.getComponent(Canvas);
            if (canvas) {
                canvasNode = child;
                break;
            }
        }

        if (!canvasNode) {
            console.error('[Tooltip] シーン内にCanvasが見つかりません。Tooltipレイヤーを作成できません。Canvasを追加してください。');
            return;
        }

        // 既存のTooltipRootを探す
        let tooltipRoot = canvasNode.getChildByName('TooltipRoot');
        if (!tooltipRoot) {
            tooltipRoot = new Node('TooltipRoot');
            canvasNode.addChild(tooltipRoot);

            // UITransformを追加
            const uiTrans = tooltipRoot.addComponent(UITransform);
            uiTrans.setAnchorPoint(0, 1); // 左上
            uiTrans.width = canvasNode.getComponent(UITransform)?.width || view.getVisibleSize().width;
            uiTrans.height = canvasNode.getComponent(UITransform)?.height || view.getVisibleSize().height;

            // 画面上部に張り付けるWidget(任意だが安定のため)
            const widget = tooltipRoot.addComponent(Widget);
            widget.isAlignTop = true;
            widget.isAlignLeft = true;
            widget.isAlignRight = true;
            widget.isAlignBottom = true;
            widget.top = 0;
            widget.left = 0;
            widget.right = 0;
            widget.bottom = 0;

            // 背景ノード
            const bgNode = new Node('TooltipBg');
            tooltipRoot.addChild(bgNode);
            const bgTrans = bgNode.addComponent(UITransform);
            bgTrans.setAnchorPoint(0, 1); // 左上
            bgTrans.width = 10;
            bgTrans.height = 10;

            // 背景色を出すためにUIOpacity+Colorを利用
            const bgOpacity = bgNode.addComponent(UIOpacity);
            bgOpacity.opacity = 200;

            // Labelノード
            const labelNode = new Node('TooltipLabel');
            tooltipRoot.addChild(labelNode);
            const label = labelNode.addComponent(Label);
            label.string = '';
            label.fontSize = this.fontSize;
            label.lineHeight = this.fontSize + 4;
            label.overflow = Label.Overflow.SHRINK;
            label.enableWrapText = true;
            labelNode.addComponent(UITransform);

            // 不透明度管理
            const rootOpacity = tooltipRoot.addComponent(UIOpacity);
            rootOpacity.opacity = 0; // 初期状態は非表示

            Tooltip._tooltipRoot = tooltipRoot;
            Tooltip._tooltipBg = bgNode;
            Tooltip._tooltipLabel = label;
            Tooltip._uiTransformRoot = uiTrans;
            Tooltip._uiTransformBg = bgTrans;
            Tooltip._uiOpacity = rootOpacity;
        } else {
            // 既存のTooltipRootから必要なコンポーネントを取得
            const uiTrans = tooltipRoot.getComponent(UITransform);
            const rootOpacity = tooltipRoot.getComponent(UIOpacity);
            const bgNode = tooltipRoot.getChildByName('TooltipBg');
            const labelNode = tooltipRoot.getChildByName('TooltipLabel');
            const label = labelNode?.getComponent(Label) || null;
            const bgTrans = bgNode?.getComponent(UITransform) || null;

            if (!uiTrans || !rootOpacity || !bgNode || !labelNode || !label || !bgTrans) {
                console.error('[Tooltip] 既存のTooltipRoot構成が不完全です。TooltipRootノードを削除して再生成させてください。');
                return;
            }

            Tooltip._tooltipRoot = tooltipRoot;
            Tooltip._tooltipBg = bgNode;
            Tooltip._tooltipLabel = label;
            Tooltip._uiTransformRoot = uiTrans;
            Tooltip._uiTransformBg = bgTrans;
            Tooltip._uiOpacity = rootOpacity;
        }
    }

    /**
     * アタッチ先ノードへのイベント登録
     */
    private registerEvents() {
        const node = this.node;

        // すでに登録済みなら何もしない
        // (Cocosのイベントは重複登録されるため、基本的には都度offしてからonするのが安全)
        this.unregisterEvents();

        node.on(Node.EventType.MOUSE_ENTER, this.onMouseEnter, this);
        node.on(Node.EventType.MOUSE_LEAVE, this.onMouseLeave, this);
        node.on(Node.EventType.MOUSE_MOVE, this.onMouseMove, this);

        if (this.useTouchAsHover) {
            node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
            node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
            node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
        }

        // グローバルマウス座標取得のため、inputにもリスナーを登録
        if (!this._registeredGlobalMouseMove) {
            input.on(Input.EventType.MOUSE_MOVE, this.onGlobalMouseMove, this);
            this._registeredGlobalMouseMove = true;
        }
    }

    /**
     * イベント登録解除
     */
    private unregisterEvents() {
        const node = this.node;
        node.off(Node.EventType.MOUSE_ENTER, this.onMouseEnter, this);
        node.off(Node.EventType.MOUSE_LEAVE, this.onMouseLeave, this);
        node.off(Node.EventType.MOUSE_MOVE, this.onMouseMove, this);

        node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
        node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        node.off(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        if (this._registeredGlobalMouseMove) {
            input.off(Input.EventType.MOUSE_MOVE, this.onGlobalMouseMove, this);
            this._registeredGlobalMouseMove = false;
        }
    }

    // ===== イベントハンドラ =====

    private onMouseEnter(event: EventMouse) {
        if (!this.tooltipText) {
            return;
        }
        this._hovered = true;
        this._showTimer = 0;
        this._hideTimer = 0;
        this.updatePointerPosFromMouse(event);
    }

    private onMouseLeave(event: EventMouse) {
        this._hovered = false;
        this._showTimer = 0;
    }

    private onMouseMove(event: EventMouse) {
        this.updatePointerPosFromMouse(event);
    }

    private onTouchStart(event: EventTouch) {
        if (!this.tooltipText) {
            return;
        }
        this._hovered = true;
        this._showTimer = 0;
        this._hideTimer = 0;
        this.updatePointerPosFromTouch(event);
    }

    private onTouchEnd(event: EventTouch) {
        this._hovered = false;
        this._showTimer = 0;
    }

    private onGlobalMouseMove(event: EventMouse) {
        this.updatePointerPosFromMouse(event);
    }

    // ===== Tooltip表示制御 =====

    private showTooltip() {
        if (!Tooltip._tooltipRoot || !Tooltip._tooltipLabel || !Tooltip._uiOpacity || !Tooltip._uiTransformBg) {
            return;
        }

        // 既に表示済みならテキストと位置だけ更新
        if (!this.isTooltipVisible()) {
            Tooltip._uiOpacity.opacity = 255;
        }

        // テキスト設定
        Tooltip._tooltipLabel.string = this.tooltipText;
        Tooltip._tooltipLabel.fontSize = this.fontSize;
        Tooltip._tooltipLabel.lineHeight = this.fontSize + 4;
        Tooltip._tooltipLabel.color = this.textColor;

        // 最大幅設定
        const labelTrans = Tooltip._tooltipLabel.node.getComponent(UITransform);
        if (labelTrans) {
            if (this.maxWidth > 0) {
                labelTrans.width = this.maxWidth;
            } else {
                // 制限なしにしておく(適宜拡張可能)
                labelTrans.width = 0;
            }
        }

        // 一旦レイアウトを更新するために少し待つ必要がある場合もあるが、
        // ここでは簡易的にUITransformのcontentSizeを利用
        this.updateBackgroundSize();

        this.updateTooltipPosition();
    }

    private hideTooltipImmediate() {
        if (Tooltip._uiOpacity) {
            Tooltip._uiOpacity.opacity = 0;
        }
    }

    private isTooltipVisible(): boolean {
        return !!Tooltip._uiOpacity && Tooltip._uiOpacity.opacity > 0;
    }

    /**
     * 背景ノードのサイズをLabelのサイズ+パディングに合わせる
     */
    private updateBackgroundSize() {
        if (!Tooltip._tooltipLabel || !Tooltip._uiTransformBg) {
            return;
        }
        const labelTrans = Tooltip._tooltipLabel.node.getComponent(UITransform);
        if (!labelTrans) {
            return;
        }

        // ラベルの実際のサイズを取得
        const labelWidth = labelTrans.contentSize.width;
        const labelHeight = labelTrans.contentSize.height;

        Tooltip._uiTransformBg.width = labelWidth + this.paddingX * 2;
        Tooltip._uiTransformBg.height = labelHeight + this.paddingY * 2;

        // 背景とラベルの位置関係(左上基準)
        // 背景の左上をTooltipRootの基準点とし、ラベルをその内側に配置
        const bgNode = Tooltip._tooltipBg!;
        const labelNode = Tooltip._tooltipLabel.node;

        bgNode.setPosition(new Vec3(0, 0, 0));
        // ラベルは背景の内側にオフセット
        labelNode.setPosition(new Vec3(this.paddingX, -this.paddingY, 0));
    }

    /**
     * ツールチップの表示位置を現在のポインタ位置に基づいて更新する。
     * 画面端では簡易的にクランプする。
     */
    private updateTooltipPosition() {
        if (!Tooltip._tooltipRoot || !Tooltip._uiTransformRoot) {
            return;
        }

        const visibleSize = view.getVisibleSize();
        const canvasWidth = visibleSize.width;
        const canvasHeight = visibleSize.height;

        // ポインタのスクリーン座標をCanvas空間に変換
        // CocosのUIは基本的に左下(0,0)~右上(canvasWidth, canvasHeight)を想定
        let targetX = this._currentPointerPos.x + this.offsetX;
        let targetY = this._currentPointerPos.y + this.offsetY;

        const bgTrans = Tooltip._uiTransformBg;
        if (bgTrans) {
            const width = bgTrans.width;
            const height = bgTrans.height;

            // 右端にはみ出さないよう調整
            if (targetX + width > canvasWidth) {
                targetX = canvasWidth - width - 4;
            }
            // 左端
            if (targetX  canvasHeight - 4) {
                targetY = canvasHeight - 4;
            }
            // 下端
            if (targetY - height < 0) {
                targetY = height + 4;
            }
        }

        // TooltipRootのアンカーは左上(0,1)なので、Y座標を変換
        const pos = new Vec3(
            targetX,
            targetY,
            0
        );

        // 左下原点の座標を左上原点に変換
        pos.y = canvasHeight - pos.y;

        Tooltip._tooltipRoot.setPosition(pos);
    }

    // ===== 座標更新ユーティリティ =====

    private updatePointerPosFromMouse(event: EventMouse) {
        const loc = event.getLocation();
        this._currentPointerPos.set(loc.x, loc.y);
    }

    private updatePointerPosFromTouch(event: EventTouch) {
        const loc = event.getLocation();
        this._currentPointerPos.set(loc.x, loc.y);
    }
}

コードの主要部分の解説

  • onLoad / ensureTooltipLayer()
    • シーン内の Canvas を自動で探し、その子として TooltipRoot ノードを生成または再利用します。
    • TooltipRoot 配下に背景ノード(TooltipBg)とテキストノード(TooltipLabel)を作成し、UITransformやLabel、UIOpacityを設定します。
    • Canvasが存在しない場合は console.error を出して処理を中断します(防御的実装)。
  • registerEvents / unregisterEvents
    • アタッチ先ノードに対して、MOUSE_ENTER / MOUSE_LEAVE / MOUSE_MOVE と、必要に応じて TOUCH_START / TOUCH_END / TOUCH_CANCEL を登録します。
    • グローバルなマウス位置を追跡するため、input.on(MOUSE_MOVE) も登録します。
    • onDisable / onDestroy で必ず解除し、メモリリークや意図しない動作を防ぎます。
  • update(dt)
    • _hovered フラグと showDelay / hideDelay に基づいて、ツールチップの表示・非表示を制御します。
    • 表示中かつ followMouse が有効な場合は、毎フレーム updateTooltipPosition() で位置更新します。
  • showTooltip / hideTooltipImmediate / isTooltipVisible
    • テキストやスタイル(フォントサイズ、色)を設定し、背景サイズを updateBackgroundSize() で調整します。
    • UIOpacityのopacityを 0/255 にすることで、表示・非表示を切り替えます。
  • updateBackgroundSize()
    • Labelの UITransform.contentSize を元に、背景ノードの幅・高さを計算します。
    • パディング(paddingX, paddingY)を考慮して背景を拡大し、ラベル位置を調整します。
  • updateTooltipPosition()
    • 最新のポインタ位置(_currentPointerPos)とオフセット(offsetX, offsetY)から、ツールチップの表示位置を計算します。
    • 画面端にはみ出さないように、キャンバスサイズで簡易的にクランプします。
    • Canvasの左下原点とTooltipRootの左上アンカーの違いを考慮してY座標を変換しています。

使用手順と動作確認

1. スクリプトファイルの作成

  1. Assetsパネルで右クリック → Create → TypeScript を選択します。
  2. ファイル名を Tooltip.ts にします。
  3. 生成された Tooltip.ts をダブルクリックで開き、内容をすべて削除して、前述のコードをそのまま貼り付けて保存します。

2. Canvasの確認

  1. Hierarchyパネルで、シーン直下に Canvas ノードが存在するか確認します。
  2. もし存在しない場合は、+ ボタン → UI → Canvas でCanvasを作成してください。
  3. このコンポーネントはCanvas直下に TooltipRoot ノードを自動生成するため、Canvasが必須です。

3. テスト用ノードの作成

  1. HierarchyパネルでCanvasノードを選択します。
  2. 右クリック → Create → UI → Sprite(またはButton、Imageなど任意のUI)を選択し、テスト用ノードを作成します。
  3. 作成したノードの名前を TestIcon など分かりやすい名前に変更します。

4. Tooltipコンポーネントのアタッチ

  1. Hierarchyで TestIcon ノードを選択します。
  2. Inspectorの一番下にある Add Component ボタンをクリックします。
  3. Custom カテゴリの中から Tooltip を選択して追加します。

5. プロパティの設定

Inspectorに表示される Tooltip コンポーネントの各プロパティを以下のように設定してみましょう。

  • Tooltip TexttooltipText
    • 例: これはテスト用のツールチップです。
  • Follow MousefollowMouse
    • チェックを入れる(オン)
  • Offset X / Offset Y
    • offsetX = 16, offsetY = -16(デフォルトのままでOK)
  • Max Width
    • 300(長文を入れる場合はそのままでOK)
  • Font Size
    • 18 など好みのサイズに調整。
  • Padding X / Padding Y
    • paddingX = 8, paddingY = 4(背景との余白)
  • Background Color
    • RGBAで (0, 0, 0, 200) など、少し透けた黒背景がおすすめ。
  • Text Color
    • 白: (255, 255, 255, 255)
  • Use Touch As Hover
    • PCのみで確認するならオン/オフどちらでもOK。
    • スマホ向けにビルドする場合はオン推奨。
  • Show Delay / Hide Delay
    • showDelay = 0.2, hideDelay = 0.1 など、好みで調整。

6. プレビューでの動作確認

  1. エディタ右上の Play ボタンを押してプレビューを開始します。
  2. ゲームビュー上で、先ほど作成した TestIcon ノード(Spriteなど)の上にマウスカーソルを乗せます。
  3. 約0.2秒(showDelay)経過すると、画面上部にツールチップが表示され、カーソルに追従することを確認します。
  4. マウスをノードから外すと、少し遅れて(hideDelay)ツールチップが消えることを確認します。
  5. 長めのテキストを設定して、maxWidth の効果(自動折り返し)も確認してみてください。

まとめ

この Tooltip コンポーネントは、

  • Canvas以外の外部スクリプトやマネージャに依存せず、
  • 任意のノードにアタッチしてテキストを設定するだけで、
  • 共通のTooltipレイヤー上にホバー時の説明テキストを表示できる

という、再利用性の高いUIユーティリティです。

例えば、

  • インベントリアイコンにアイテム名・説明文を表示する。
  • スキルボタンにクールダウンや効果説明を表示する。
  • ステータスバーの各項目に詳細情報を表示する。

といった用途で、同じコンポーネントをそのまま使い回せます。

スタイル(色・フォント・パディング)や挙動(ディレイ・追従の有無)もすべてインスペクタから調整できるため、デザイナーやレベルデザイナーがコードに触れずにUIの使い勝手を改善できる点も大きな利点です。

このコンポーネントをベースに、アイコン画像付きツールチップやリッチテキスト対応など、さらに高機能なTooltipシステムへ拡張していくことも容易です。まずはこの汎用版をプロジェクトに組み込んで、UIの説明表示を統一・自動化してみてください。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

URLをコピーしました!