
前回でレベルが上がるようになりましたが、上がっても強くはなりませんでした。ヴァンサバ風のゲームで一番おいしいのは、レベルアップのたびに出てくる3択の強化です。何を選ぶかで戦い方が変わっていくのが、このジャンルの面白さそのものだと思います。今回はヴァンサバ風サバイバーゲームのシリーズの7回目として、レベルアップでゲームを止めて、3枚のカードから1つ選ぶ仕組みを作ってみたいと思います!
- シリーズの目次:ヴァンサバ風ゲームの作り方
- 前回:#6 金平糖を集めてレベルアップしよう
今回作るもの
- レベルアップでゲームが止まり、3枚のカードが出る
- カードを押すと強化されて、ゲームが再開する
- 強化は4種類。同じカードは1回に2枚出ない
- 3つ目の武器ストレーナー(足元に粉をふるう範囲攻撃)が手に入る
新しく作るスクリプトが10個、直すスクリプトが4つあります。少し多いですが、1つ1つは短いです。
| スクリプト | 役割 | 付ける場所 |
|---|---|---|
| Weapon(新しく作る) | 武器に共通する部分。データのコピーを持つ | (親クラス) |
| UpgradeData(新しく作る) | 強化1つ分の親。名前・説明・アイコン | (親クラス) |
| PowerUpgrade / SpeedUpgrade / SpoonUpgrade / StrainerUpgrade | 強化の効き方。1種類につき1つ | データのアセット |
| StrainerData(新しく作る) | ストレーナーの性能 | データのアセット |
| StrainerArea(新しく作る) | 足元の丸い範囲にダメージを与える | Player |
| UpgradeCard(新しく作る) | カード1枚の見た目と、押されたときの合図 | Card(3枚) |
| UpgradeView(新しく作る) | 3枚を選んで出す。止める・再開する | Canvas |
| SpoonThrower / WhipperOrbit(直す) | Weaponを親にする。スプーンは本数を増やせるように | Player |
| SpoonData(直す) | 投げる本数と、広がる角度を足す | データのアセット |
| PlayerMove(直す) | 外から移動速度を上げられるように | Player |
前回の続きから
- Unityのバージョンは6.3 LTS
- 記事作成時点では6000.3.22f1で確認しています
- #6の状態:倒した敵が金平糖を落とし、集めるとレベルが上がる
ボタンは9-2 テキスト、ボタン、画像の基本UI要素、並べ方は9-6 ScrollViewとLayout Groupで紹介しています。
武器に共通の親を作ろう(Weapon)
強化の「攻撃力アップ」は、持っている武器ぜんぶに効いてほしいものです。武器ごとに書き分けていると、武器を足すたびに強化のほうも直すことになります。
そこで、武器に共通の親クラスを作ります。
SurvivorsLike/Scriptsに「Weapon」を作る
using UnityEngine;
// 武器に共通する部分。強化はこの型を通してまとめて効かせる
public abstract class Weapon : MonoBehaviour
{
[SerializeField] private WeaponData sourceData;
// 遊んでいる間だけのコピー。強化はこちらを書き換える
public WeaponData Data { get; private set; }
protected virtual void Awake()
{
Data = Instantiate(sourceData);
}
}
Instantiateでコピーしないと、強化がアセットに残って戻りません
ScriptableObjectはプロジェクトに保存されているファイルです。data.damage += 5とそのまま書き換えると、遊ぶのをやめてもその数字のままになります。次に再生したときは強くなった状態から始まり、遊ぶたびにどんどん強くなっていきます。
Instantiateでコピーを作れば、書き換わるのはコピーのほうだけです。再生をやめるとコピーは消えるので、アセットは元のままです。
SpoonThrowerとWhipperOrbitを、この親から作られるように直します。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
// 一定間隔で、一番近い敵に計量スプーンを投げる
public class SpoonThrower : Weapon
{
[SerializeField] private LayerMask enemyLayer;
private SpoonData spoon; // 親が作ったコピーを、スプーン用として見たもの
private ObjectPool<Spoon> pool;
private ContactFilter2D filter;
private readonly List<Collider2D> found = new List<Collider2D>();
private float timer;
protected override void Awake()
{
base.Awake(); // 先に親にコピーを作ってもらう
spoon = (SpoonData)Data;
filter = new ContactFilter2D
{
useLayerMask = true,
layerMask = enemyLayer,
useTriggers = true,
};
pool = new ObjectPool<Spoon>(
createFunc: () => Instantiate(spoon.bulletPrefab, transform.parent),
actionOnGet: bullet => bullet.gameObject.SetActive(true),
actionOnRelease: bullet => bullet.gameObject.SetActive(false),
actionOnDestroy: bullet => { if (bullet != null) Destroy(bullet.gameObject); },
defaultCapacity: 20,
maxSize: 200);
}
private void Update()
{
timer += Time.deltaTime;
if (timer < spoon.interval)
{
return;
}
timer -= spoon.interval;
Transform nearest = FindNearestEnemy();
if (nearest == null)
{
return;
}
Vector2 toEnemy = (Vector2)nearest.position - (Vector2)transform.position;
if (toEnemy.sqrMagnitude < 0.0001f)
{
return;
}
// 本数のぶんだけ、少しずつ角度をずらして投げる
for (int i = 0; i < spoon.bulletCount; i++)
{
float angle = (i - (spoon.bulletCount - 1) * 0.5f) * spoon.spreadAngle;
Vector2 direction = Quaternion.Euler(0f, 0f, angle) * toEnemy.normalized;
pool.Get().Throw(transform.position, direction, spoon, pool);
}
}
// まわりの敵を集めて、一番近いものを返す
private Transform FindNearestEnemy()
{
Physics2D.OverlapCircle(transform.position, spoon.searchRadius, filter, found);
Transform nearest = null;
float nearestDistance = float.MaxValue;
foreach (Collider2D collider in found)
{
float distance = ((Vector2)collider.transform.position - (Vector2)transform.position).sqrMagnitude;
if (distance < nearestDistance)
{
nearestDistance = distance;
nearest = collider.transform;
}
}
return nearest;
}
}
protected override Awakebase.Awake()を先に呼ぶのを忘れないでください。コピーを作るのは親の仕事です
(SpoonData)Data- 親は
WeaponDataとしてコピーを持っています。スプーンの欄(飛ぶ速さなど)を使いたいので、SpoonDataとして見直しています
- 親は
- 投げる角度をずらす
- 3本なら
-15度・0度・+15度のように、真ん中をはさんで左右に散る計算にしています
- 3本なら
SpoonDataに本数と広がりを足します。
using UnityEngine;
// 投げる武器(計量スプーン)だけの性能
[CreateAssetMenu(fileName = "SpoonData", menuName = "SurvivorsLike/Spoon Data")]
public class SpoonData : WeaponData
{
public Spoon bulletPrefab; // 飛ばすもの
public float bulletSpeed = 8f; // 飛ぶ速さ
public float searchRadius = 10f; // 狙う範囲
public int bulletCount = 1; // 1回に投げる本数
public float spreadAngle = 15f; // 本数が増えたときの、1本ごとの角度
}
WhipperOrbitも同じで、Weaponを親にして、dataと書いていたところをwhipperに置き換えるだけです。
using System.Collections.Generic;
using UnityEngine;
// プレイヤーの周りでホイッパーを回す(当たり判定は Whipper のほうが持つ)
public class WhipperOrbit : Weapon
{
[SerializeField] private Whipper headPrefab;
private WhipperData whipper; // 親が作ったコピーを、ホイッパー用として見たもの
private readonly List<Transform> heads = new List<Transform>();
private float angle;
private float timer;
private bool isOut;
protected override void Awake()
{
base.Awake();
whipper = (WhipperData)Data;
}
private void Start()
{
for (int i = 0; i < whipper.orbitCount; i++)
{
Whipper head = Instantiate(headPrefab, transform.parent);
head.Setup(whipper);
heads.Add(head.transform);
}
Switch(true);
}
private void Update()
{
timer -= Time.deltaTime;
if (timer <= 0f)
{
Switch(!isOut);
}
if (!isOut)
{
return;
}
angle += 360f / whipper.orbitSeconds * Time.deltaTime;
for (int i = 0; i < heads.Count; i++)
{
float headAngle = angle + 360f / heads.Count * i;
float radian = headAngle * Mathf.Deg2Rad;
Vector2 offset = new Vector2(Mathf.Cos(radian), Mathf.Sin(radian)) * whipper.orbitRadius;
heads[i].position = (Vector2)transform.position + offset;
heads[i].up = -offset;
}
}
private void Switch(bool next)
{
isOut = next;
timer = next ? whipper.activeSeconds : whipper.restSeconds;
angle = 0f;
foreach (Transform head in heads)
{
head.gameObject.SetActive(next);
}
}
}
Source Dataを入れ直す
SpoonThrowerとWhipperOrbitは、データの欄を親のWeaponに移したので、欄の名前がDataからSource Dataに変わりました。名前が変わった欄は空っぽになるので、このまま再生するとエラーになります。
- HierarchyでPlayerを選ぶ
- Spoon ThrowerのSource Dataに、#5で作った
SpoonDataのアセットを入れる - Whipper OrbitのSource Dataに、
WhipperDataのアセットを入れる
移動速度を外から上げられるようにしよう
PlayerMoveに、メソッドを1つ足します。
// 強化で呼ばれる。移動速度を上げる
public void AddSpeed(float amount)
{
moveSpeed += amount;
}
3つ目の武器・ストレーナーを作ろう
足元の丸い範囲に粉をふるい落として、中にいる敵ぜんぶにダメージを与える武器です。当たり判定を持たず、一定間隔でまわりを調べる作りにします。
SurvivorsLike/Scriptsに「StrainerData」を作る
using UnityEngine;
// 範囲攻撃の武器(ストレーナー)だけの性能
[CreateAssetMenu(fileName = "StrainerData", menuName = "SurvivorsLike/Strainer Data")]
public class StrainerData : WeaponData
{
public float radius = 2.5f; // 粉がかかる範囲
public float effectSeconds = 0.35f; // 粉が見えている時間
}
- 続けて「StrainerArea」を作る
using System.Collections.Generic;
using UnityEngine;
// 一定間隔で、足元の丸い範囲にいる敵ぜんぶにダメージを与える
public class StrainerArea : Weapon
{
[SerializeField] private LayerMask enemyLayer;
[SerializeField] private SpriteRenderer effect; // 粉が広がる見た目
private StrainerData strainer;
private ContactFilter2D filter;
private readonly List<Collider2D> found = new List<Collider2D>();
private float timer;
private float effectTimer;
protected override void Awake()
{
base.Awake();
strainer = (StrainerData)Data;
filter = new ContactFilter2D
{
useLayerMask = true,
layerMask = enemyLayer,
useTriggers = true,
};
effect.transform.localScale = Vector3.one * strainer.radius * 2f;
effect.gameObject.SetActive(false);
}
private void Update()
{
if (effect.gameObject.activeSelf)
{
effectTimer -= Time.deltaTime;
if (effectTimer <= 0f)
{
effect.gameObject.SetActive(false);
}
}
timer += Time.deltaTime;
if (timer < strainer.interval)
{
return;
}
timer -= strainer.interval;
Physics2D.OverlapCircle(transform.position, strainer.radius, filter, found);
foreach (Collider2D collider in found)
{
if (collider.TryGetComponent(out Enemy enemy))
{
enemy.TakeDamage(strainer.damage);
}
}
effect.gameObject.SetActive(true);
effectTimer = strainer.effectSeconds;
}
}
- 当たり判定(Collider)を使っていない
Physics2D.OverlapCircleはその瞬間の範囲を調べる命令です。#4で一番近い敵を探したときと同じものを、ダメージにも使っています- 「触れ続けている間ずっと」ではなく「3秒に1回ドン」なので、こちらのほうが素直に書けます
- 見た目は別のGameObject
- 粉が広がる絵を0.35秒だけ出しています。当たる範囲と同じ大きさにしておくと、どこまで効いたかが目で分かります
- 短すぎると、当たったことに気づけません。0.1秒台だと1コマだけ光って終わりでした
ストレーナーを置こう
- HierarchyでPlayerを右クリック>Create Empty、名前を「StrainerEffect」にする
- Add Component>Sprite Renderer、Sprite:strainer_area、Order in Layer:-1(敵より奥)
- Color のアルファ(透明度)を半分ぐらいに下げる
- HierarchyでPlayerを選び、Add Component>StrainerArea
- Source Data:
StrainerDataのアセット、Enemy Layer:Enemy、Effect:さっきのStrainerEffect - Inspectorの左のチェックを外して、最初は止めておく(強化で手に入る武器なので)
- Source Data:

SurvivorsLike/Dataで右クリック>Create>SurvivorsLike>Strainer Data、名前を「StrainerData」にする
| 項目 | 値 |
|---|---|
| Weapon Name | ストレーナー |
| Icon | icon_strainer |
| Damage | 10 |
| Interval | 3 |
| Radius | 2.5 |
| Effect Seconds | 0.35 |
強化のデータを作ろう(UpgradeData)
強化も武器と同じで、種類ごとに効き方が違うだけです。#5の武器データと同じように、共通の部分を親にします。
SurvivorsLike/Scriptsに「UpgradeData」を作る
using UnityEngine;
// 強化1つ分。どう効くかは、種類ごとの子クラスが決める
public abstract class UpgradeData : ScriptableObject
{
public string upgradeName = "強化";
[TextArea] public string description = "説明";
public Sprite icon;
// カードを押したときに呼ばれる
public abstract void Apply(GameObject player);
// 今もらえる強化かどうか(もう持っているものを出さないため)
public virtual bool CanTake(GameObject player) => true;
}
ここから4種類を作ります。どれも短いです。
using UnityEngine;
// 砂糖コーティング:持っている武器ぜんぶの攻撃力を上げる
[CreateAssetMenu(fileName = "PowerUpgrade", menuName = "SurvivorsLike/Upgrade/Power")]
public class PowerUpgrade : UpgradeData
{
public int addDamage = 5;
public override void Apply(GameObject player)
{
foreach (Weapon weapon in player.GetComponents<Weapon>())
{
weapon.Data.damage += addDamage;
}
}
}
using UnityEngine;
// バターましまし:移動速度を上げる
[CreateAssetMenu(fileName = "SpeedUpgrade", menuName = "SurvivorsLike/Upgrade/Speed")]
public class SpeedUpgrade : UpgradeData
{
public float addSpeed = 1f;
public override void Apply(GameObject player)
{
player.GetComponent<PlayerMove>().AddSpeed(addSpeed);
}
}
using UnityEngine;
// 計量スプーンを1本増やす
[CreateAssetMenu(fileName = "SpoonUpgrade", menuName = "SurvivorsLike/Upgrade/Spoon")]
public class SpoonUpgrade : UpgradeData
{
public override void Apply(GameObject player)
{
SpoonData spoon = (SpoonData)player.GetComponent<SpoonThrower>().Data;
spoon.bulletCount++;
}
}
using UnityEngine;
// ストレーナーを手に入れる(止めてあるStrainerAreaを動かす)
[CreateAssetMenu(fileName = "StrainerUpgrade", menuName = "SurvivorsLike/Upgrade/Strainer")]
public class StrainerUpgrade : UpgradeData
{
public override void Apply(GameObject player)
{
player.GetComponent<StrainerArea>().enabled = true;
}
// すでに動いているなら、もう出さない
public override bool CanTake(GameObject player) => !player.GetComponent<StrainerArea>().enabled;
}
PowerUpgradeが短い理由GetComponents<Weapon>()で、Playerに付いている武器を種類を問わず全部まとめて取り出しています- 武器を足しても、この強化は直さなくて済みます。これが親クラスを作った見返りです
CanTake- ストレーナーだけは2回もらっても意味がないので、
CanTakeを上書きして、動き出したあとは候補から外れるようにしています
- ストレーナーだけは2回もらっても意味がないので、
強化のアセットを作ろう
SurvivorsLike/DataにUpgradesフォルダを作って、右クリック>Create>SurvivorsLike>Upgradeの中のPower・Speed・Spoon・Strainerから4つ作ります。
| アセット | Upgrade Name | Description | Icon |
|---|---|---|---|
| PowerUpgrade | 砂糖コーティング | 武器ぜんぶの攻撃力が上がる | icon_power |
| SpeedUpgrade | バターましまし | 動く速さが上がる | icon_speed |
| SpoonUpgrade | 計量スプーン追加 | 投げるスプーンが1本増える | icon_spoon |
| StrainerUpgrade | ストレーナー | 足元に粉をふるって、まわりの敵を攻撃する | icon_strainer |

日本語のフォントを用意しよう
強化の名前は日本語です。ところが#6で入れたTMP Essentialsのフォントは英数字しか持っていないので、このままでは□(いわゆる豆腐)が並ぶだけになります。
- 配布素材のzipに入っているNotoSansJP.ttfを、
SurvivorsLike/Fontsに入れる- 自由に使えて、再配布も出来るフォントです(SIL Open Font License)
- ProjectウインドでNotoSansJPを右クリック>Create>TextMeshPro>Font Asset>SDFで、フォントアセットを作る
- この作り方だと、Atlas Population Mode:Dynamic(使う文字をその場で足していく)のフォントアセットになります
- 元のNotoSansJP.ttfは、Dynamicのフォントアセットが文字を読み込むのに使うので、消さないでください
- Edit>Project Settings>TextMesh Pro>SettingsのDefault Font Assetに、作ったフォントアセットを入れる
- すでに作ってあるテキスト(#6のLevelTextなど)は、InspectorのFont Assetを入れ替える
日本語は文字の種類が多いので、フォントアセットはDynamicで作るのがポイントです。手順のくわしい話は9-3 TextMeshProで美しいテキストを表示しようにあります。
スライムカードの文字が□□□になっていたら、だいたいフォントのせいです・・・Default Font Assetの入れ替えを忘れがち
3択のパネルを作ろう
カード1枚ぶんのスクリプト
SurvivorsLike/Scriptsに「UpgradeCard」を作る
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
// カード1枚。中身を書き換えて、押されたら知らせる
public class UpgradeCard : MonoBehaviour
{
[SerializeField] private Image icon;
[SerializeField] private TextMeshProUGUI nameText;
[SerializeField] private TextMeshProUGUI descriptionText;
[SerializeField] private Button button;
private UpgradeData data;
private Action<UpgradeData> onChosen;
public void Show(UpgradeData newData, Action<UpgradeData> newOnChosen)
{
data = newData;
onChosen = newOnChosen;
icon.sprite = data.icon;
nameText.text = data.upgradeName;
descriptionText.text = data.description;
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => onChosen(data));
gameObject.SetActive(true);
}
}
RemoveAllListeners- カードは使い回すので、前に入れた「押したときの処理」が残っていると、2回・3回と呼ばれます
- 入れる前に消す、をセットで書きます
画面に並べる
- Canvasの上で右クリック>UI>Image、名前を「UpgradePanel」にする(暗幕)
- Anchor Presetsでstretch・stretchをAltキーを押しながら選び、画面いっぱいに広げる
- Source Image:ui_white、Color:黒、アルファ(A)を180ぐらい
UpgradePanelの上で右クリック>Create Empty、名前を「Cards」にする- Anchor Presetsでmiddle・center、Width:1500、Height:520
- Add Component>Horizontal Layout Group
- Spacing:40、Child Alignment:Middle Center
- Child Force Expandの Width・Height のチェックを外す
Cardsの上で右クリック>UI>Button – TextMeshPro、名前を「Card」にする- 中のText (TMP)は使わないので削除する
- Rect TransformのWidth:420、Height:520にする
- Add Component>Layout Element、Preferred Width:420、Preferred Height:520
Cardの中にUI>Image(名前:Icon)と、UI>Text – TextMeshProを2つ(Name・Description)を作って好きに並べるCardにAdd Component>UpgradeCard、4つの欄にIcon・Name・Description・Card自身(Button)を入れる
Cardを2回コピーして、3枚にする


Horizontal Layout Groupを使うと、カードの位置を1枚ずつ決めなくて済みます。Cardsの下に入れた分だけ、自動で横に等間隔で並びます。1枚だけ出すときも真ん中にそろうので、「3枚出す/2枚しか出せない」が混ざっても崩れません。
カードが小さいままのときは、Control Child Sizeを見てください。新しく付けたHorizontal Layout GroupはWidth・Heightのチェックが外れていて、Layout Elementの大きさは使われず、カードのRect TransformのWidth・Heightのまま並びます。上の手順でWidth・Heightを420・520にしてあればOKです。
レベルアップでゲームを止めよう(UpgradeView)
SurvivorsLike/Scriptsに「UpgradeView」を作る
using System.Collections.Generic;
using UnityEngine;
// レベルアップでゲームを止めて、3枚のカードから1つ選ばせる
public class UpgradeView : MonoBehaviour
{
[SerializeField] private PlayerLevel playerLevel;
[SerializeField] private GameObject panel;
[SerializeField] private UpgradeCard[] cards;
[SerializeField] private UpgradeData[] allUpgrades;
private readonly List<UpgradeData> candidates = new List<UpgradeData>();
private int waiting; // まだ選んでいないレベルアップの回数
private void OnEnable()
{
playerLevel.LevelUp += OnLevelUp;
}
private void OnDisable()
{
playerLevel.LevelUp -= OnLevelUp;
}
private void OnLevelUp()
{
waiting++;
if (!panel.activeSelf)
{
ShowNext();
}
}
private void ShowNext()
{
// 今もらえるものだけを集めて、前から3つ使う(順番はシャッフルする)
candidates.Clear();
foreach (UpgradeData upgrade in allUpgrades)
{
if (upgrade.CanTake(playerLevel.gameObject))
{
candidates.Add(upgrade);
}
}
for (int i = candidates.Count - 1; i > 0; i--)
{
int j = Random.Range(0, i + 1);
(candidates[i], candidates[j]) = (candidates[j], candidates[i]);
}
for (int i = 0; i < cards.Length; i++)
{
if (i < candidates.Count)
{
cards[i].Show(candidates[i], Choose);
}
else // 出せるものが3つ未満のとき
{
cards[i].gameObject.SetActive(false);
}
}
panel.SetActive(true);
Time.timeScale = 0f; // ゲームを止める
}
private void Choose(UpgradeData upgrade)
{
upgrade.Apply(playerLevel.gameObject);
waiting--;
if (waiting > 0)
{
ShowNext(); // 一度に2レベル上がったときは、続けてもう1回選ぶ
return;
}
panel.SetActive(false);
Time.timeScale = 1f; // 再開する
}
}
Time.timeScale = 0- 時間の進み方を0にすると、
Time.deltaTimeが0になり、物理も止まります。敵も武器もピタッと止まります - UIのボタンは止まりません。押す処理は時間と関係なく動くので、止めたままカードを選べます
- 時間の進み方を0にすると、
- 同じカードを2枚出さない
- 候補のリストをシャッフルしてから前から3つ取っています。1つのリストから取るので、同じものが2枚並ぶことはありません
waitingで数えておく- 金平糖をまとめて拾うと、1回のレベルアップ処理で2回も3回も
LevelUpが起きます - 数えておいて、選ぶたびに1つ減らし、残っていればもう1回出します
- 金平糖をまとめて拾うと、1回のレベルアップ処理で2回も3回も
- HierarchyでCanvasを選び、Add Component>UpgradeView
- Player Level:Player、Panel:UpgradePanel
- Cards:サイズを3にして、3枚のCardを入れる
- All Upgrades:サイズを4にして、作った強化のアセットを4つ入れる
UpgradePanelのInspectorの左のチェックを外して、最初は非表示にしておく





レベルが上がるたびにワクワクしますね!



どれを取るか悩ませるのがコツだよ。全部強いけど、今いちばん欲しいのはどれか・・・って考えさせるのが楽しいんだ!
動かして確認!


#7の動作確認
- 経験値バーが満タンになると、ゲームが止まってカードが3枚出る
- 敵もスプーンもホイッパーも、選ぶまでピタッと止まっている
- カードを押すと、パネルが消えてすぐに再開する
- 同じカードが2枚並ばない
- 「ストレーナー」を取ると、足元に粉の輪が3秒ごとに広がり、中の敵が倒れる
- 「ストレーナー」は、1回取ったらもう出てこない
- 「計量スプーン追加」を取ると、スプーンが2本ずつ飛ぶ
- 金平糖をまとめて拾って2レベル上がったときは、続けて2回選ばせてくれる


バランスを考えよう
| 変えたいこと | 変える数字 |
|---|---|
| 強化の効きを強くする | 各アセットのAdd DamageやAdd Speed |
| ストレーナーの範囲を広げる | StrainerDataのRadius(見た目も自動で合います) |
| スプーンの広がりを変える | SpoonDataのSpread Angle |
| 強化の種類を増やす | UpgradeDataを継承したクラスを1つ書いて、アセットを作り、All Upgradesに足すだけ |
ホイッパーを増やす強化も、同じやり方で作れます。WhipperDataのorbitCountを1増やして、WhipperOrbitに回す本数を作り直させれば完成です。ぜひ作ってみてください。
あとがき
今回は、このジャンルの一番おいしいところ、3択の強化を作りました。武器に共通の親を作っておいたおかげで、「攻撃力アップ」が数行で書けたのが気持ちよかったです!次回は、攻撃が当たったときの手応えの演出を足したいと思います。強化で武器が強くなっても、当たったことが見えないと気持ちよさが半分になってしまうので・・・
コメント
コメント一覧 (1件)
[…] 前回:#7 レベルアップで3択の強化を選ばせよう […]