Windows PowerShell — 山内陽@portfolio\focus-areas\02
PS C:\Users\yamauchi\portfolio\focus-areas\02>

#

ゲームの流れと状態を、どこに持たせるか。チームで作るときは、どこに境界を置いて、どう進めるか。

§01

ドロップロップ

PS> Get-Item .\CreatorKousien | Format-List *

集めて、溜めて、まとめて敵に叩き込む見下ろし型3Dアクション。

ドロップロップ タイトル画面
10人チーム
152/ 947自分のコミット / 全体
366マージされたPR
  • 2026.04〜 開発中
  • チーム開発
  • Unity 6 / URP / Wwise

1プレイ画面

C-1ゲーム画面。収集物をたくさん抱えたプレイヤーと、敵が同じ画面に映っているもの静止画 PNG → images/works/creatorkousien/01-play.png
集めて、抱える。散らばった収集物を拾い集め、抱えたまま敵のいる場所まで運びます
C-2抱えた収集物を敵にまとめて放ち、ゲージが削れて敵がダウンするまで動画 MP4(無音・5〜10秒) → images/works/creatorkousien/02-release.mp4
まとめて叩き込む。短いあいだの命中はまとめて数えられ、敵のゲージが一気に削れます
ドロップロップの技術的な詳細を読む(設計・つまずき・コード)
C-3Waveの合間に出る、強化を選ぶ画面静止画 PNG → images/works/creatorkousien/03-roguelike.png
Waveの合間に、次の戦い方を決める強化を選びます
C-4Waveが進むとボスが登場する画面静止画 PNG → images/works/creatorkousien/04-boss.png
Waveが進むとボスが登場します
C-5リザルト画面静止画 PNG → images/works/creatorkousien/05-result.png
クリアでもゲームオーバーでも、リザルトから再挑戦できます

2作品の詳細

遊びの核は「ためる」と「叩き込む」

ただ全部を集めればいいのではなく、どれだけ抱えるか、いつ、どの敵に放つかを考えさせます。ステージごとの強化の選び方も、その判断に効いてきます。

ためる 叩き込む 収集物が出る 集める 抱えて保持 敵へ放つ 命中をまとめて集計 ゲージとダウン 撃破・崩落・演出のあと、また収集物が出る

自分が作ってきたもの

最初のコミットから、半年間でやったことを時期順に並べました。前半はチームで作るための土台、後半はゲームの仕組みと仕上げが中心。

時期やったこと
2026.04リポジトリを立ち上げ、開発ガイド・命名規則・PRテンプレートを用意。CIで .meta ファイルの抜けを検査するようにした
2026.04Issueを作ると、GitHub Projectsのボードに自動で載るようにした
2026.05敵の仕組みの基盤と、UIとのつなぎ込み
2026.07敵の状態異常のエフェクト、ボスと蔦のギミックの作り直し、タイトルとロード画面
2026.07サウンドミドルウェアのWwiseを導入
2026.08ローグライクの強化と、バランスを調整するためのエディタ
2026.08落下物を500個動かしても重くならないようにする最適化
2026.09常設のショップ、効果音とBGMをWwise経由に。ビルドからGitHub Releaseの作成、Discordへの通知までを1つのバッチにした

バランスを一か所で調整する

強化の値、Waveごとの報酬、ショップの商品、収集物の出現率が別々の場所にあり、調整するたびに探し回っていました。これをUnityのエディタ上の1つの窓にまとめました。

概要Wave報酬強化一覧ショップ商品出現物・確率特殊効果検証・確率確認難易度カーブ

「出現率アップを買っても、そのアイテムが出てこない」という不具合がありました。調べると、出現率の表とは別に、シーン上のスポナーが「出せるアイテム」の一覧を個別に持っていて、そこに無い種類には効果がありませんでした。

そこで、出現を決める処理を1か所にまとめて直しました。そのうえで、スポナーの一覧と出現率の表の食い違いを「検証」タブで見つけられるようにしました。あとから新しいスポナーを置いて登録を忘れても、次からは道具が教えてくれます。

3こだわったこと

500個落としても、重くしない

やりたかったこと

画面いっぱいに収集物が降ってきて、それを抱えて放ちます。数を減らして軽くするのではなく、数はそのままで動きを軽くしたいと考えました。

ぶつかった壁

落下物は、止まったあとも毎フレーム物理の計算と、重力をかける処理が走り続けていました。表示中の物を管理する処理も、物が増えるほど1回の追加や削除が遅くなる作りでした。

どう作ったか

物理・探索・描画の3か所で、それぞれ無駄を削りました。いちばん効いたのは、止まった物を物理の計算から外すこと。

落下物の速さ 時間 → ほぼ止まっている 少しでも動いたら数え直し 遅い状態が15ステップ続いたら 眠らせる 眠っている間は処理を飛ばす

一瞬遅くなっただけで眠らせると、転がっている途中で止まってしまいます。そこで遅い状態が15ステップ続いたときだけ眠らせ、途中で少しでも動いたら数え直すようにしました。

止まった物は、物理から外す

上の図のとおり Rigidbody.Sleep() で眠らせます。眠っている間は、重力をかける処理も飛ばします。

探索を1回で済ませる

表示中の物の管理を List から HashSet に変え、追加や削除のたびに全体をなめていた確認をなくしました。

まとめて描く

落下物のマテリアルでGPUインスタンシングを有効にし、同じ見た目の物を一度に描けるようにしました。

どうなったか

止まっている落下物は、計算に入らなくなりました。500個が画面にあっても、実際に計算するのは動いている物だけで済みます。

C-6収集物が数百個、ステージに散らばっている画面静止画 PNG → images/works/creatorkousien/06-many.png
数百個が散らばっていても、止まった物は眠っています
つまずいたところ壁ぎわで、収集物が震え続ける
起きたこと

フィールドの壁ぎわにたまった収集物が、細かく震え続けていました。

原因

壁に触れるたびに、スクリプトで位置を内側へ書き換えていました。物理エンジンが壁で止めている物を、その上からさらに動かしていたことになり、2つの処理がぶつかっていました。

しかも速度は外向きのまま残るので、次の物理の計算でまた壁へ押しつけられ、また戻されます。これを繰り返していました。

直し方

壁で止まっている物は、物理エンジンに任せます。スクリプトで戻すのは、壁を越えて、本当にフィールドの外へ出た物だけにしました。

戻すときは、速度のうち外向きの成分だけを取り除きます。速度と、壁の外向きの法線との内積をとり、外へ向かっていれば、その分を引きます。壁に沿った動きや、内側へ向かう動きは残ります。

Assets/Scripts/Gameplay/Collectibles/Entities/CollectibleObject.cs(314〜320行目)

float outwardSpeed = Vector3.Dot(
    _rigidbody.linearVelocity,
    outwardDirection);
if (outwardSpeed > 0f)
{
    _rigidbody.linearVelocity -= outwardDirection * outwardSpeed;
}

直したときのコミット:e27e14d(2026年7月17日)

要になったコード15ステップ続けて遅かったら、眠らせる

Assets/Scripts/Gameplay/Collectibles/Entities/CollectableGravity.cs(83〜96行目)

if (_rb.linearVelocity.sqrMagnitude <= SleepSpeedThresholdSqr)
{
    _stableFixedStepCount++;
    if (_stableFixedStepCount >= StableFixedStepsBeforeSleep)
    {
        _stableFixedStepCount = 0;
        _rb.Sleep();
        return;
    }
}
else
{
    _stableFixedStepCount = 0;
}

遅い状態が15ステップ続いたときだけ、Sleep() で物理の計算から外します。途中で少しでも速くなったら、数え直します。

一瞬止まっただけで眠らせると、転がっている途中の物まで止まってしまいます。「続いたら」を条件にしたのは、そのためです。

§02

コレクライト

PS> Get-Item .\UnityJam | Format-List *

カラスになってライトを頼りに財宝を集め、電池が切れる前に脱出する探索アクション。

コレクライトのプレイ画面。カラスが宝箱の前に立っていて、右下に電池の残り数が表示されている
電池が切れると、ライトが消えます
2週間開発期間
157/ 310自分のコミット / 全体
125マージされたPR
  • 2025.12
  • チーム開発
  • Unity / C# / unityroom

担当2週間のチーム開発。ステージ生成や3日間の進行、ショップ・結果画面など、ゲーム全体の骨組みを担当。

見どころ

1プレイ画面

K-31日の終わりに入るショップの画面。電池の今の値段と、次の値段が映っているところ静止画 PNG → images/works/collectlight/02-shop.png
電池は、買うたびに次の1本が高くなります
K-6最終結果の画面。1〜3日目のスコアと合計が並んでいるところ静止画 PNG → images/works/collectlight/05-final-result.png
3日の合計がスコアになり、unityroomのランキングに送られます
K-5脱出ポイントに入り、画面が暗くなって「その日の結果」に切り替わるまで動画 MP4(無音・5〜10秒) → images/works/collectlight/04-escape.mp4
途中で脱出すれば、そこまでの稼ぎを持って1日を終えられます
コレクライトの技術的な詳細を読む(設計・つまずき・コード)

2作品の詳細

3日間の流れ

1日に4階まで潜ります。その日の結果の画面で稼ぎを払うと、次の日は前の日に届いた階から始められます。そのあとのショップで電池を買い足して、次の日に備えます。3日目が終わると、最終結果とエンドクレジットです。

1日目 2日目 3日目 1F2F3F4F 1F2F3F4F 1F2F3F4F その日の結果ショップ その日の結果ショップ その日の結果最終結果 エンドクレジット 買った階から始める
途中で脱出すれば、その時点の稼ぎで1日を終えられます。深く潜るか、持ち帰るかを毎日選びます。

階が変わるたびに、ステージを組み立て直す

1階ごとに、ステージとプレイヤーを、その階のプレハブから組み立てます。ゴールに着くとシーンを読み直し、次の階をまっさらな状態で組み立てます。前の階の敵や宝箱を1つずつ片付けるより、読み直すほうが取りこぼしがありません。

階をまたいで残したいものだけを、シーンを読み直しても消えないオブジェクトに置きました。何日目の何階か、その日までのスコア、電池の残りです。電池は、ライトが減るたびにそこへ書き込み、次の階のライトが最初に読み出します。

  1. 読み直すと消えるものステージ、敵、宝箱、プレイヤー(StageManager が階ごとに作る)
  2. 残るもの日と階、日ごとのスコア(GameSessionManager)、電池の本数と残量(PlayerDataManager)

状態が変わったら、それぞれが自分で反応する

ゲーム全体の状態は GameManager だけが持ちます。状態が変わったことをイベントで知らせ、画面・音・オブジェクトを受け持つクラスが、それぞれ受け取って動きます。GameManager はUIや音のことを知りません。

状態(9種類) TitleCreditsGameplay ScoreCalcResultShop FinalResultGameOverLoading GameManager OnStateChanged UIManager その状態の画面を出し直す SoundManager タイトル・クレジット・ゲーム中でBGMを切り替える GamePrefabManager その状態で使うオブジェクトを出し直す

125件のPRを回すための仕組み

2週間でIssueは103件、PRは125件。管理の手間を減らすため、GitHub Actionsで次のことを自動にしました。

  1. Issueのフォームに書いた優先度と期日を、ボードの項目に入れるGitHub ProjectsのAPI(GraphQL)で書き込みます
  2. タイトルの先頭でラベルを付ける[TASK] ならtask、[BUG] ならbug
  3. 閉じたIssueはDoneへ動かす
  4. 担当が決まったらDiscordに通知する

3こだわったこと

稼ぎを使うほど、スコアは減る

やりたかったこと

ダンジョンの中では、いつも「もう少し潜るか、いま帰るか」を迷います。この迷いを、ダンジョンを出たあとにも続けたいと考えました。

ぶつかった壁

稼ぎで次の日を楽にできるなら、稼いだ人ほど楽になり、迷う理由がなくなります。

失敗も軽すぎました。最初は、失敗したらその日を0点にして、次の日へ進む作りでした。これだと3日目は、失うものがその日の分しかありません。

どう作ったか

最終スコアは3日の稼ぎの合計です。次の日のために払った分は、そのまま最終スコアから引かれるようにしました。

  1. 近道は、その日の稼ぎで払う前の日に届いた階から始められます。代金は2日目が200、3日目が250です
  2. 電池は、買うほど高くなる1本目は10、2本目は15。そのあとは1本ごとに1.5倍になります。ショップに入るたびに10へ戻ります
  3. 失敗したら、そこで終わりその日に集めた分は残りますが、残りの日は0点になり、最終結果へ進みます
どうなったか

1日の終わりに、稼ぎを近道に使うか、電池に使うか、残しておくかを選びます。どれを選んでもスコアは減ります。

失敗すると残りの日がなくなるので、1日目の無理は重く、3日目の無理は軽くなります。日が進むほど、深く潜る理由が増えていきます。

つまずいたところ1日の終わりが2回来て、日数が飛ぶ
起きたこと

ダンジョンで力尽きると、その1回の失敗で、日数が2日以上進んでしまうことがありました。

原因

1日を終える入り口は、帰還・ゴール・失敗の3つあります。失敗のときは、その場で0点を記録してから、結果画面の状態へ移っていました。

ところが、結果画面の状態に入るときにも、その日の結果を記録していました。1回の失敗で記録が2回走り、そのたびに日数が進んでいました。

直し方

進行を管理する側と、記録する側の2か所で防ぎました。進行を管理する側では、1日を終える処理を、1日に1回しか受け付けません。記録する側では、同じ日の結果が2回届いたら、2回目を捨てます。

呼び出す側の流れがあとで変わっても、記録が重ならないようにするためです。

Assets/Scripts/Core/GameSessionManager.cs(52〜59行目)

public void RegisterDayResult(int score, Dictionary<ItemMaster, int> items)
{
    // 重複登録チェック: 既に今日のスコアが登録済みなら無視
    if (DayScores.Count > CurrentDayIndex)
    {
        Debug.LogWarning(…);
        return;
    }

直したときのコミット:9d24ed3(2025年12月28日)

要になったコード失敗したら、残りの日を0点で埋める

Assets/Scripts/Core/GameManager.cs(473〜487行目から抜粋)

if (UnityJam.Core.GameSessionManager.Instance != null)
{
    // 当日の結果登録
    UnityJam.Core.GameSessionManager.Instance.RegisterDayResult(currentScore, currentItems);

    // 2. 残りの日程を全て0点で埋める
    while (!UnityJam.Core.GameSessionManager.Instance.IsSessionFinished())
    {
        UnityJam.Core.GameSessionManager.Instance.RegisterDayResult(0, new Dictionary<ItemMaster, int>());
    }

    // 3. FinalResultへ遷移
    ChangeState(GameState.FinalResult);
}

その日の稼ぎを記録したあと、3日ぶんの記録がそろうまで0点を足していきます。最終結果の画面は、いつも3日ぶんの記録を読むだけで済みます。途中で終わったかどうかを、画面の側で気にする必要がありません。

いまの形にしたときのコミット:e22e800(2025年12月28日)

§03

そろそろ帰ろう

PS> Get-Item .\sorosoro-kaerou | Format-List *

背後で物音がしたら、スマホを持ったまま本当に振り返ってシャッターを切る、Android向けのホラー。

そろそろ帰ろう プレイ動画のサムネイル
プレイ動画(YouTubeで見る)
2日間CyberAgentの開発実習
3人チーム
56/ 136自分のコミット / 全体
  • 2026.08
  • CyberAgent 開発実習
  • 3人チーム
  • Unity / C# / Android

担当CyberAgentの2日間の開発実習で、3人チーム。Androidの層(ライト・ジャイロ・振動)、ゲームの流れの統合、暗さと怖さの演出を担当。

見どころ

1プレイ画面

R-1実機で遊んでいる様子の写真。スマホを構えたまま、後ろを振り返っている人静止画 PNG → images/works/sorosoro/01-playing.png
画面の中ではなく、自分の体で振り返る。
R-3環境音のときに振り返った画面(何もない夜道)静止画 PNG → images/works/sorosoro/03-safe.png
環境音だと何もない
R-5異常な音がしたときに振り返った画面(背後に怪異がいるところ)静止画 PNG → images/works/sorosoro/05-ghost.png
異常な音がすると、後ろには…
耳を澄ませて、振り返る。環境音だけなら何もなく、異常な音がしたときは背後に怪異が立っています
そろそろ帰ろうの技術的な詳細を読む(設計・つまずき・コード)
R-4最初に向きを合わせるキャリブレーションの画面静止画 PNG → images/works/sorosoro/04-calibration.png
始める前に、今の向きを正面として登録します
R-2夜道を歩いているゲーム画面静止画 PNG → images/works/sorosoro/02-walking.png
夜道を歩いていると、背後で物音がします
R-6ゲームオーバーの画面(到達した日数・撃退した数・理由が出ているもの)静止画 PNG → images/works/sorosoro/06-result.png
何日目まで帰れたか、何体を撃退したかが残ります

2作品の詳細

実機とエディタを、同じゲームのコードで動かす

ジャイロもライトも、エディタ上にはありません。GameManager が入力と演出をインターフェース越しに扱うようにし、実機用とエディタ用の実装を差し替えられるようにしました。ゲームの流れはエディタで確かめ、手触りだけを実機で詰められます。

GameManager IPlayerInput 振り返り・シャッター IFeedbackPresenter ライト・フラッシュ・振動 AndroidPlayerInput 実機:ジャイロで振り返り、画面のボタンで撮影 KeybordInput エディタ:キーボードで代わりに操作 AndroidFeedbackPresenter 実機:端末のライトと振動 EditorFeedbackPresenter エディタ:画面上の表示で代わりに確認
黄色の枠は、実機でしか動かない部分。端末のライトは、AndroidのCameraManagerをUnityから直接呼んで点けます。

自分が担当したところ

Androidの層

端末のライト、ジャイロでの振り返り判定、振動、最初に向きを決めるキャリブレーション。

ゲームの流れの統合

別々に作っていた3Dのプレイ部分をメインのゲームに一本化し、シャッターの入力をイベントでロジックへつなぎました。

暗さと怖さの演出

暗い部屋のポストエフェクト、怪異が近づく表示、撮影の瞬間に画面が白く飛ぶ演出。

3こだわったこと

本当に、振り返らせる

やりたかったこと

背後で物音がしたら、プレイヤーがボタンではなく、体の向きで振り返って応えます。怖さを画面の外まで持ち出したいと考えました。

ぶつかった壁

遊ぶ人によって、立っている向きも、スマホの持ち方も違います。

「何度を超えたら背後」と境目を1つだけ決めると、ちょうどその角度で持っているだけで、正面と背後の判定が行ったり来たりしてしまいます。

どう作ったか

始めるときに、今向いている方向を0°として登録します。そこからどれだけ回ったかを、ジャイロの姿勢(クォータニオン)から出します。オイラー角はジンバルロックで値が暴れるので、判定には使いません。

そして、「背後」になる範囲と、「正面」に戻る範囲を分けました。135°〜225°に入ったら背後、45°以内に戻ったら正面。そのあいだの角度では、今の状態を変えません。境目で判定が揺れることがなくなります。

正面 背後 そのまま そのまま 0° 180° 45° 135° 225° 315°

振り返ってシャッターを切ると、AndroidのカメラのライトをUnityから直接点けます。0.7秒点けて、0.1秒消して、もう一度点けます。画面の中の光と、手元の本物の光が重なります。

どうなったか

プレイヤーは本当に後ろを振り向き、手元のスマホが光ります。遊んでいる姿そのものが、ゲームの一部になりました。

R-7実機で振り返ってシャッターを押し、端末のライトが光るところ。スマホの外から撮った動画動画 MP4(無音・5〜10秒) → images/works/sorosoro/07-turn-flash.mp4
振り返ってシャッターを押すと、手元のライトが光ります
要になったコード背後に入る角度と、正面に戻る角度を分ける

Assets/_sorosoro-kaerou/Scripts/Android/PhoneOrientation.cs(185〜203行目)

if (!isBack)
{
    if (135 < relativeZ && relativeZ < 225)
    {
        isBack = true;
    }
}
else
{
    if (315 < relativeZ || relativeZ < 45)
    {
        isBack = false;

        if (feedback != null && feedback.IsLightOn)
        {
            feedback.SetLight(false);
        }
    }
}

正面を向いているあいだは、135°〜225°に入ったときだけ「背後」にします。背後にいるあいだは、315°〜45°に戻ったときだけ「正面」にします。

そのあいだの角度では、状態を変えません。境目で手が少しぶれても、判定が行ったり来たりしません。

§04

ONE MORE PLANK

PS> Get-Item .\OneMorePlank | Format-List *

使える板は、1部屋に1枚だけ。置いて、渡って、拾って、また置きます。10部屋を駆け抜けるタイムアタック。

ONE MORE PLANKのプレイ画面。緑の床の先に板が置かれ、右上にタイムが表示されている
右上がタイム、右下が手元の板の枚数
2日間ゲームジャム
27C#スクリプト。すべて自分で
  • 2025.12
  • 個人開発
  • Unity / C# / unityroom
ONE MORE PLANKの画面と技術的な詳細を読む(設計・つまずき・コード)

1プレイ画面

P-2板を置こうとしているとき、影が緑になっている画面(置ける場所)静止画 PNG → images/works/onemoreplank/01-ghost-ok.png
置ける場所
P-3板を置こうとしているとき、影が赤くなっている画面(置けない場所)静止画 PNG → images/works/onemoreplank/02-ghost-ng.png
置けない場所
板の影の色で、置けるかどうかが分かる。置ける場所では緑、置けない場所では赤
P-4板を置いて渡り、振り返って拾い、次の場所に置くまで動画 MP4(無音・5〜10秒) → images/works/onemoreplank/03-place-cross-pick.mp4
1枚しかない板を、置いて、渡って、拾って、また置きます
P-610部屋を抜けたときのタイムの画面静止画 PNG → images/works/onemoreplank/05-clear.png
10部屋を抜けたタイムが、ランキングに送られます
P-7タイトル画面静止画 PNG → images/works/onemoreplank/06-title.png
タイトル画面

2作品の詳細

遊び方

  1. Shiftを押しながらクリックで置く画面の中心の先、6mまでに置けます。床がなくても宙に置けて、壁などに重なる場所だけは置けません。右クリックで45°ずつ回します
  2. Eで拾う渡り終えた板を拾って、次の足場にします
  3. スペースでジャンプ移動はWASD、視点はマウスで動かします
  4. 落ちたら、部屋の入口から板は1枚に戻ります。Rを長押しすれば、自分から部屋をやり直せます

最初は「借金」の遊びだった

はじめは、板が足りなくなったら「もう1枚」を借りられて、借りるほど霧が濃くなり、音が暗くなる設計でした。タイトルはその名残。

2日で遊びきれる形にするため、提出版では1部屋1枚のタイムアタックに絞りました。遊びの芯を「板1枚をどう使い回すか」に決め、それ以外を削りました。

3こだわったこと

音声ファイルを、1つも使わない

やりたかったこと

暗く広い空間を、板1枚で渡っていくゲーム。その雰囲気に合う音を、2日のうちに用意したいと考えました。

ぶつかった壁

音の素材を探して、長さや雰囲気をそろえるだけで時間がなくなります。2日のゲームジャムでは、その時間が取れません。

どう作ったか

音はすべて、ゲームの中で波形を計算して作ることにしました。

音作り方
背景の和音少しだけ音程をずらしたサイン波を重ね、ゆっくり立ち上がって、ゆっくり消える
ドローンと低音背景でずっと鳴り続ける低い音
板を置く音・着地の音木を叩いたような短い音。同じ音を、高さを変えて使い分ける
足音・ジャンプ・リスポーン足音は高さの違う2種類を作っておき、鳴らすたびにどちらかを選んで、高さも少し揺らす

背景の和音は、同じ高さの音を0.1%だけ上下にずらして重ねています。わずかにずれた音どうしがゆっくりうねり、厚みが出ます。そこに2倍・3倍の高さの音を少しだけ足しています。

どうなったか

音声ファイルは0個のまま、背景の和音から足音まで、すべての音が鳴っています。

要になったコード0.1% ずらした音を、重ねる

Assets/OneMorePlank/Scripts/Core/AudioManager.cs(142〜148行目)

// コーラス効果のためにわずかにデチューンされた豊かな倍音
float wave = 0f;
wave += Mathf.Sin(2 * Mathf.PI * freq * t);
wave += Mathf.Sin(2 * Mathf.PI * freq * 1.001f * t) * 0.7f;
wave += Mathf.Sin(2 * Mathf.PI * freq * 0.999f * t) * 0.7f;
wave += Mathf.Sin(2 * Mathf.PI * freq * 2f * t) * 0.3f;
wave += Mathf.Sin(2 * Mathf.PI * freq * 3f * t) * 0.1f;

基準の高さの音に、1.001 倍と 0.999 倍の音を重ねています。わずかにずれた音どうしがゆっくりうねって、1つの音より厚みが出ます。

その上に、2倍と3倍の高さの音を少しずつ足しています。音声ファイルを使わず、背景の和音はこの5行で波形を作って鳴らしています。