UnityでUIを作っていると、つい「とりあえず全部 Update に書いて動けばOK!」となりがちですよね。
例えば、マウスホバーの判定・ボタンの色変更・クリック処理・SE再生などを、1つの巨大なスクリプトに押し込んでしまうパターンです。
このやり方は最初は楽ですが、後から
- ボタンの見た目だけ変えたいのに、ロジックまで巻き込んで修正が必要
- 別の画面でも同じようなホバー演出を使いたいのに、コピペ地獄になる
- 「どの処理がどこで動いているのか」追いにくくてデバッグが辛い
といった問題を生みやすいです。
そこでこの記事では、「ホバーしたときに少し拡大して強調する」という機能だけを切り出した、
小さなコンポーネント HoverScale (ホバー拡大) を作ってみましょう。
ボタンでもアイコンでも、対象のゲームオブジェクトにアタッチするだけで、ホバー拡大演出を簡単に再利用できるようにします。
【Unity】ホバーでふわっと拡大!「HoverScale」コンポーネント
今回の HoverScale は、次のような特徴を持つコンポーネントです。
- マウスカーソルが乗ったときに、親の
Transformを少しだけ拡大 - カーソルが外れたら、元のスケールにスムーズに戻す
- 拡大倍率・アニメーション速度をインスペクターから調整可能
- UIボタンだけでなく、アイコンや任意のオブジェクトにも使える
「ホバーしたら拡大する」という見た目の責務だけをこのコンポーネントに任せることで、
クリック処理やゲームロジックとはきれいに分離できます。
フルコード:HoverScale.cs
using UnityEngine;
using UnityEngine.EventSystems;
namespace HoverEffects
{
/// <summary>
/// マウスホバー時に対象オブジェクトをふわっと拡大するコンポーネント
/// - IPointerEnterHandler / IPointerExitHandler を利用
/// - UI(Button, Image, etc...) はもちろん、EventSystem + Raycaster があれば3Dオブジェクトにも使用可能
/// </summary>
[DisallowMultipleComponent]
public class HoverScale : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
// 拡大対象(null の場合はこのコンポーネントが付いているオブジェクト自身を対象とする)
[SerializeField]
private Transform targetTransform;
// ホバー時の拡大倍率(1.1f なら 10% 拡大)
[SerializeField, Tooltip("ホバー時の拡大倍率(1.1 なら 10% 拡大)")]
private float hoverScaleMultiplier = 1.1f;
// スケールの補間速度(大きいほど素早く変化)
[SerializeField, Tooltip("スケールの補間速度(大きいほど素早く変化)")]
private float scaleLerpSpeed = 12f;
// ホバー中かどうかのフラグ
private bool _isPointerOver;
// 元のスケールを保存
private Vector3 _initialScale;
// 現在のスケール(補間用)
private Vector3 _currentScale;
private void Awake()
{
// 対象が指定されていなければ、自身の Transform を対象にする
if (targetTransform == null)
{
targetTransform = transform;
}
// 初期スケールを保存
_initialScale = targetTransform.localScale;
_currentScale = _initialScale;
}
private void OnEnable()
{
// 再有効化時にスケールをリセットしておくと安心
if (targetTransform != null)
{
targetTransform.localScale = _initialScale;
_currentScale = _initialScale;
}
_isPointerOver = false;
}
private void Update()
{
if (targetTransform == null)
{
return;
}
// 目標スケールを決定
Vector3 targetScale = _isPointerOver
? _initialScale * hoverScaleMultiplier
: _initialScale;
// スムーズに補間(Lerp)
_currentScale = Vector3.Lerp(
_currentScale,
targetScale,
Time.unscaledDeltaTime * scaleLerpSpeed
);
targetTransform.localScale = _currentScale;
}
/// <summary>
/// マウスカーソルが UI 要素に乗ったときに呼ばれる
/// </summary>
public void OnPointerEnter(PointerEventData eventData)
{
_isPointerOver = true;
}
/// <summary>
/// マウスカーソルが UI 要素から外れたときに呼ばれる
/// </summary>
public void OnPointerExit(PointerEventData eventData)
{
_isPointerOver = false;
}
/// <summary>
/// 実行中に倍率を変更したいケース向けの API(任意で使用)
/// </summary>
/// <param name="multiplier">新しい拡大倍率</param>
public void SetHoverScaleMultiplier(float multiplier)
{
hoverScaleMultiplier = Mathf.Max(0f, multiplier);
}
/// <summary>
/// 実行中に補間速度を変更したいケース向けの API(任意で使用)
/// </summary>
/// <param name="speed">新しい補間速度</param>
public void SetLerpSpeed(float speed)
{
scaleLerpSpeed = Mathf.Max(0f, speed);
}
}
}
使い方の手順
ここでは、典型的な「メニュー画面のボタン」と「インベントリアイコン」での使用例をベースに手順を説明します。
-
① 必要な UI 環境を用意する
- シーンに
EventSystemが存在することを確認(なければGameObject > UI > Event Systemで追加) - Canvas 上に
ButtonやImageなどの UI 要素を配置する
- シーンに
-
② スクリプトを作成してアタッチ
- プロジェクトビューで
HoverScale.csを作成し、上記のコードをコピペ - メニューの
StartButtonや、インベントリのアイコンオブジェクトなど「拡大させたいオブジェクト」にHoverScaleをアタッチ
例:
StartButton(Button コンポーネント付きの GameObject)InventoryItemIcon(Image コンポーネント付きの GameObject)
- プロジェクトビューで
-
③ インスペクターでパラメータを調整
Target Transform:
通常は空欄のままで OK(自分自身が拡大対象になります)。
もし「ボタンの中のアイコンだけ拡大したい」などがあれば、その子オブジェクトのTransformをドラッグ&ドロップで指定します。Hover Scale Multiplier:
ホバー時の拡大倍率。1.05 ~ 1.2くらいが使いやすいです。
例:1.1にすると 10% 拡大します。Scale Lerp Speed:
スケールが変化する速さ。8 ~ 16くらいが自然に感じやすいです。
値を大きくすると、ピタッと素早く拡大・縮小します。
-
④ 実際に動作を確認する
- Play モードで再生し、対象のボタンやアイコンにマウスカーソルを乗せてみる
- ふわっと拡大して、カーソルを外すと元に戻れば成功です
- 複数のボタンに同じ
HoverScaleをアタッチしても、コードは 1 つなので保守も簡単です
これだけで、プレイヤーにとって分かりやすく、クリックしたくなる UI 演出を簡単に付けられます。
メリットと応用
HoverScale のように「ホバー時の拡大」という見た目の責務だけに特化したコンポーネントを用意しておくと、次のようなメリットがあります。
- プレハブ管理が楽になる
ボタン用プレハブにHoverScaleを入れておけば、どのシーンに配置しても同じホバー演出が自動で効くようになります。
振る舞いを変えたくなったら、このコンポーネントだけを修正すれば全ボタンに反映されます。 - レベルデザイン/UIデザインの試行錯誤がしやすい
拡大倍率やスピードをインスペクターから調整できるので、デザイナーやレベルデザイナーがシーン上で直接「気持ちいい値」を探れます。
値を変えても他のロジックには一切影響しないため、安心して試行錯誤できます。 - ロジックと演出の分離
クリック処理などはButton.onClickや別コンポーネントに任せて、
見た目の演出だけをHoverScaleに担当させることで、各コンポーネントの責務が明確になります。
結果として、巨大な God クラスを避けられ、保守性・再利用性が向上します。 - UI 以外にも応用可能
PhysicsRaycasterやGraphicRaycasterを使えば、3D オブジェクトやワールド空間 UI にも同じコンポーネントを使えます。
例えば、ワールドマップ上の建物アイコンに付けて「選択候補」を分かりやすくする、といった使い方もできます。
改造案:ホバー中だけ軽く回転させる
「拡大だけだと少し物足りないな」という場合は、軽い回転を加えるのもアリですね。
HoverScale に以下のようなメソッドを追加して、Update から呼び出す形に改造してみましょう。
private void ApplyHoverRotation()
{
if (!_isPointerOver || targetTransform == null)
{
return;
}
// ホバー中だけ、Y軸にゆっくり回転を加える(UI なら Z 軸回転でもOK)
float rotationSpeed = 10f; // 1秒あたり10度回転
targetTransform.Rotate(0f, 0f, rotationSpeed * Time.unscaledDeltaTime);
}
このように、小さなコンポーネントをベースに少しずつ演出を足していくと、
プロジェクト全体が「再利用しやすい小さい部品の集合」になっていきます。
ぜひ自分のプロジェクト用にカスタマイズして、気持ちいいホバー演出を育てていきましょう。
