Warning: Cannot modify header information - headers already sent by (output started at /home/cra-log/www/index.php:1) in /home/cra-log/www/site-admin-wp/wp-includes/feed-rss2.php on line 8
Unity – CRAFT GoGo https://craft-gogo.com Raspberry Pi、3Dプリンタ、プログラミング、DIYなど、ものづくりを中心に趣味レベルで情報を発信! Tue, 15 Aug 2023 12:46:42 +0000 ja hourly 1 https://wordpress.org/?v=6.3.4 https://craft-gogo.com/site-admin-wp/wp-content/uploads/2021/05/cropped-CRAFT-GOGO-LOGO-32x32.png Unity – CRAFT GoGo https://craft-gogo.com 32 32 【Unity】ゲーム制作素人がソリティアを作ってみた https://craft-gogo.com/unity-solitaire/ Fri, 29 Apr 2022 03:09:54 +0000 https://craft-gogo.com/?p=2514

今回、Unity初心者でありますが、暇つぶしに最適なソリティアを制作したので紹介します。 制作方法を簡単に解説しますので、私と同じぐらいのUnity初心者の方は参考になるかなと思います。 Google Playにも登録出 […]]]>

今回、Unity初心者でありますが、暇つぶしに最適なソリティアを制作したので紹介します。

制作方法を簡単に解説しますので、私と同じぐらいのUnity初心者の方は参考になるかなと思います。

Google Playにも登録出来たので、興味がある人は是非ダウンロードして遊んでみて下さい。

Google Play で手に入れよう

ただし、オリジナリティはゼロであることを始めに言っておきます。

この記事はこんな人におすすめ!

  • Unity初心者の人
  • Unityでカードゲームを作ってみたい人

まずはソリティアを遊んでみよう!

今回、制作したソリティアをWebGL版にしたので遊んでみて下さい。

新しくページを開く場合はこちら

Google Playにも登録していますので、Androidユーザーの人は下記リンク先からインストールしてみて下さい。

Google Play で手に入れよう

iOS版は無いのでご了承ください。

制作方法のポイント

ソリティア制作方法のポイントを解説していきます。

解説するにあたり、山札、組札、場札という用語が出てきますが、下図の定義とします。

カードPrefabを準備する

カードスプライトの作成

カードの画像を用意して、スプライトエディタで52枚のカード + 裏面に分割し、スプライトを作成します。

①Texture TypeをSprite(2D and UI)に変更。②Sprite ModeをMultipleに変更。③Sprite Editorをクリック。

Sprite Editorで52枚のカード表面とカード裏面に分割し、スプライトを作成。

カードPrefabを作成

カードPrefabは、52枚のカードをすべて作成するのではなく、カード裏面のみを作成します。

カードを表面にするときは、スプライトを差し替えるようにします。

カード状態を設定する

52枚のカードがそれぞれどんな状態にあるか記憶するため、スクリプトを追加し、変数を設定します。

カード状態

  • cardPosX, cardPosY: カードの位置 (山札、組札、場札のどこの位置に置かれているか)
  • mark: マーク(ハート、ダイヤ、クローバー、スペード)
  • num: 数字(1~13)
  • frFlg: 表裏の状態
  • layer: カードが置かれている高さ

カードクリック時の処理を追加

カードPrefabにEvent Triggerコンポーネントを追加して、カードをクリックしたときの処理を追加します。

Event Triggerの設定方法は、別記事で解説していますので、こちらを参照下さい。

https://craft-gogo.com/unity-doubleclick/

カードの上でマウスボタンを押したときの処理 (OnClickCard)

山札の上でマウスボタンを押した時

カードを3枚めくります。

場札の上でマウスボタンを押した時

一番上のカードかつ裏であれば表にします。

カードをマウスドラッグしたときの処理 (OnDragCard)

表のカードをマウスドラッグした時

マウスクリック前の位置を記憶した後、下に繋がっているカードすべてを移動させます。

マウスボタンを離したときの処理 (UpClickCard)

マウスボタンを離した場所が場札かつ、移動中のカードとマーク色違いで数字が1つ大きいカードの上の場合

移動中のカードを、マウスボタンを離した場所に移動完了させます。

マウスボタンを離した場所がカードが1枚もない場札列かつ、移動中のカードが「K」の場合

移動中のカードを、マウスボタンを離した場札列に移動完了させます。

マウスボタンを離した場所が組札かつ、移動中のカードとマークが同じで数字が1つ小さいカードの場合

移動中のカードを、マウスボタンを離した場所に移動完了させます。

ゲーム開始したときの処理を追加

  • 52枚のカードを山札に裏返して置く
  • 52枚のカードをシャッフルして山札に置き直す
  • 28枚のカードを場札に並べる
28枚のカードを場札に並べる処理

グラフィック・ユーザーインターフェイスの作成

  • タイトル画面を作成し、ゲーム画面に移行する処理を作成する
  • リセットボタンを作成し、ボタンを押したらゲームをやり直す処理を作成する
  • やり直しボタンを作成し、ボタンを押したら1回操作を戻す処理を作成する
  • ゲーム開始からの時間表示を作成する
  • 操作回数の表示を作成する
  • ゲームクリアしたときのアニメーションを作成する
タイトル画面
リセットボタンとやり直しボタン
時間計測と操作回数

まとめ

以上、私がUnityで制作したソリティアの紹介でした。

オリジナリティはゼロですが、ソリティアとしては立派に完成させていますので、暇つぶしにはなると思います。私も電車で移動中などは、自分で作ったソリティアで遊んでいます。

Google Playにも登録出来たので、興味がある人は是非ダウンロードして遊んでみて下さい。

Google Play で手に入れよう ]]>
Unityではじめてのテトリス風落ちゲー制作 ~最終回 ベストスコアセーブ編~ https://craft-gogo.com/unity-first-puzzlegame11/ Fri, 18 Mar 2022 13:33:04 +0000 https://craft-gogo.com/?p=1951

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

最終回はベストスコアセーブ編です。

前回記事では、タイトル画面を追加し、ゲームオーバーになったらタイトル画面に戻れる機能を追加しました。

今回はベストスコアを更新したらセーブし、ゲームを再開時にベストスコアをロードする機能を追加します。

尚、データのセーブ、ロード方法は別記事で詳しく解説していますので、本記事では簡単に説明させてもらいます。

https://craft-gogo.com/unity-datasave/

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

ベストスコアを表示するテキストオブジェクト作成

まず、ベストスコアをゲーム画面上に表示させるため、テキストオブジェクトを追加します。

下図のようにベストスコアを表示させましょう。細かな設定は、これまで解説していますので割愛します。

GameController.csにテキスト変数を追加してテキスト変更をスクリプトで扱えるようにします。

public Text bestScoreText;

Unityに戻ってGameControllerコンポーネントにBest Score Textオブジェクトをセットします。

ベストスコアをロードするメソッド作成

まず、JSON形式でベストスコアを格納するクラスを作成します。

[System.Serializable]
class SaveData
{
    public int bestScore;
}

ベストスコアをロードするためのメソッドです。このメソッドを呼び出すことによって、savefile.jsonにセーブされているベストスコアをロードします。

private void LoadBestScore()
{
    string path = Application.persistentDataPath + "/savefile.json";
    if (File.Exists(path))
    {
        string json = File.ReadAllText(path);
        SaveData data = JsonUtility.FromJson<SaveData>(json);

        bestScore = data.bestScore;
    }
    else
    {
        bestScore = 0;
    }

    bestScoreText.text = "Best Score: " + bestScore;
}

ベストスコアをセーブするメソッド作成

スコアがベストスコアを上回ったらJSON形式でスコアを保存します。

private void SaveBestScore(){

    if(score > bestScore)
    {
        bestScoreText.text = "Best Score: " + score;

        SaveData data = new SaveData();
        data.bestScore = score;

        string json = JsonUtility.ToJson(data);

        File.WriteAllText(Application.persistentDataPath + "/savefile.json", json);
    }
}

Application.persistentDataPathの場所は、Windowsだと\usr\AppData\LocalLow\CompanyNameになります。

ゲームスタート時にベストスコアをロードする処理追加

ゲームスタート時に作っておいたLoadBestScore()メソッドを呼び出せば、ベストスコアがロードされます。

void Start()
{
    /*
    (省略)
    */

    LoadBestScore();
    
    /*
    (省略)
    */
}

ゲームオーバー時にベストスコアをセーブする処理追加

ゲームオーバー時に作っておいたSaveBestScore()メソッドを呼び出しましょう!

void Update() {
    switch(gameStat){
        /*
        (省略)
        */    
        case GAMEOVER:
            SaveBestScore();
            gameOverText.gameObject.SetActive(true);
            restartButton.gameObject.SetActive(true);
            returnTitleButton.gameObject.SetActive(true);
            break;
    }
    /*
    (省略)
    */
}

実際にゲームを動かしてみよう

ゲームオーバー時にベストスコアが更新されました。

まとめ

最終回では、ベストスコアを更新したらセーブし、ゲームを再開時にベストスコアをロードする機能を追加しました。

データのセーブ、ロード方法は簡単に説明しましたが、別記事で詳しく解説していますので参考に。

https://craft-gogo.com/unity-datasave/

最後までお読み頂きありがとうございました。

]]>
【Unity初心者】ダブルクリック Event Triggerの作り方 https://craft-gogo.com/unity-doubleclick/ Mon, 14 Mar 2022 23:46:13 +0000 https://craft-gogo.com/?p=2025

Unityで、オブジェクトダブルクリック時の処理を追加しようとしても、どうしたらよいのか困っていませんか。Event Triggerでシングルクリックはあるけど、ダブルクリックが無い・・・。 今回の記事では、オブジェクト […]]]>

Unityで、オブジェクトダブルクリック時の処理を追加しようとしても、どうしたらよいのか困っていませんか。Event Triggerでシングルクリックはあるけど、ダブルクリックが無い・・・。

今回の記事では、オブジェクトをダブルクリックしたときに色を変更するサンプルを作りながら、Event Triggerにダブルクリックを追加する方法を解説します。

こんな人におすすめ!

  • オブジェクトをダブルクリックしたときの処理が作れなくて困っている人
  • Unityを使ったゲーム制作の基本を学びたい初心者

Event Systemオブジェクトを追加する

まず初めに行うことがEvent Systemオブジェクトを追加することです。

Event Systemは、マウスクリックやディスプレイタッチしたときに、オブジェクトへイベントを送信するのを管理してくれます。

Hierarchyウィンドウから「UI」 > 「Event System」をクリックしましょう。

設定はデフォルトのままで大丈夫です。

Main CameraにPhysics 2D Raycasterコンポーネントを追加する

次にゲーム画面でオブジェクトをクリックしたときにイベントが発生出来るよう、Main CameraにPhysics 2D Raycasterコンポーネントを追加します。

Physics 2D Raycasterは画面クリックした位置から光線を発し、衝突したオブジェクトにメッセージを送信する役割です。オブジェクトが衝突を検知することによって、オブジェクトがクリックされたことが分かります。

InspectorウィンドウでAdd Componentボタンをクリックし、Physics 2D Raycasterコンポーネントを追加しましょう。

これも設定はデフォルトでOK。

ダブルクリックしたときに色が変更されるオブジェクトを追加する

続いてダブルクリックされるオブジェクトの設定に移ります。適当な2Dオブジェクトをまず追加しましょう。

ダブルクリック判定作成の流れは、次のようになります。

  • Physics 2D Raycasterからの光線との衝突を検出出来るようCollider追加
  • Colliderが衝突検知したときにEvent Triggerでクリックを判定
  • 2回連続でクリックしたことをスクリプトで判定する

Box Collider 2Dの追加

Physics 2D Raycasterからの光線と衝突したのを検知出来るようColliderを追加します。

Add Componentボタンをクリックし、Box Collider 2Dコンポーネントを追加しましょう。

設定はデフォルトのままでよいです。

Event Triggerによるクリック判定追加

Colliderが衝突を検知したときにイベントを発生出来るようEvent Triggerを追加します。

Add Componentボタンをクリックし、Event Triggerコンポーネントを追加。

「Add New Event Type」> 「PointerDown」を選択して下さい。

PointerDownの処理は後から追加するので、ここでは保留。

Double Clickスクリプトを追加

PointerDownで発生させる処理をスクリプトで書いていきます。

ダブルクリックされるオブジェクトにスクリプトを追加し、以下のようにコードを書きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DoubleClick : MonoBehaviour
{
    private int clickCount;
    private bool flg;

    void Start()
    {
        clickCount = 0;  
        flg = false;  
    }

    public void OnClickDown()
    {
        clickCount++;
        Invoke("OnDoubleClick", 0.3f);
    }

    private void OnDoubleClick()
    {
        if(clickCount != 2) {clickCount = 0; return;}
        else {clickCount = 0;}
        
        if(flg == false) {
            gameObject.GetComponent<SpriteRenderer>().color = Color.red;
            flg = true;
        }
        else
        {
            gameObject.GetComponent<SpriteRenderer>().color = Color.white;
            flg = false;
        }       
    }
}

OnClickDownメソッドはPointer Downに登録するメソッドです。OnClickDownが呼び出されたらclickCountをインクリメントします。そしてOnDoubleClickメソッドを0.3秒後に呼び出します。この時間はダブルクリックの時間間隔パラメータですので、適当に調整してもらって構いません。

OnClickDownが呼び出されたときにclickCountが2回のときにダブルクリックと判定し、処理を実行します。今回は、ダブルクリックされたときにオブジェクトの色を赤に変える処理を追加しました。

スクリプトが出来上がったのでPointer DownにOnClickDownメソッドを登録します。

以上でダブルクリック判定の出来上がり!

オブジェクトをダブルクリックしてみよう

ゲームを開始したときはオブジェクトは白です。

オブジェクトの上でダブルクリックすると

オブジェクトが赤色に!

まとめ

オブジェクトをダブルクリックしたときに色を変更するサンプルを作りながら、Event Triggerにダブルクリックを追加する方法を解説しました。

正直、Unityにダブルクリックを判定する機能が無いのが残念です。(私が知らないだけかもしれません)

今後機能が追加されることを期待します。

最後までお読み頂きありがとうございました。

]]>
Unityではじめてのテトリス風落ちゲー制作 ~その10 タイトル画面追加編~ https://craft-gogo.com/unity-first-puzzlegame10/ Sun, 20 Feb 2022 13:41:44 +0000 https://craft-gogo.com/?p=1789

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回はタイトル画面追加編です。

前回記事では、最上位列までブロックが積みあがったらゲームオーバーになる機能を追加しました。

今回は、次の機能を追加します。

  • タイトル画面を追加し、Game Startボタンを押したら、ゲームを開始する
  • ゲームオーバーになったら、タイトルに戻るかゲームをやり直すか選択出来るようにする

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

ゲームシーンの移動方法について解説

最初にゲームシーンを移動する方法について解説します。各ゲームシーンにはindexが割り当てられています。確認するには「File > Build Settings」を選択して下さい。

Scenes In Buildの右端の数字が各ゲームシーンのindexです。

ゲームシーンを移動するには、SceneManagement名前空間が必要です。usingで追加し、SceneManager.LoadSceneメソッドでゲームシーンを移動します。引数に先ほど調べたゲームシーンのindexを設定することで、指定したindexのゲームシーンに移動することが出来ます。

using UnityEngine.SceneManagement;

SceneManager.LoadScene(0);

タイトル画面を追加する

タイトル画面のデザインを作成

タイトル画面を作っていきましょう。ScenesフォルダにTitleSceneを作成します。

タイトルテキストとスタートボタンを加えます。

タイトルテキストとスタートボタンの文字大きさ、テキスト、配置を設定しましょう。

こんな感じです。

「GameStart」ボタンが押されたら「GameScene」に移動するスクリプト作成

GameSceneのindexを設定するため、「ファイル > Build Settings」を選択し、

TitleSceneのindexを「0」、GameSceneのindexを「1」にします。

次にGameSceneに移動するスクリプトを作成します。GameStartButton.csを作成し、下のメソッドを作成しましょう。GameSceneのindexは「1」なので、LoadSceneメソッドの引数は「1」に設定します。

public void OnGameStartButtonClick()
{
    SceneManager.LoadScene(1);
}

GameStartButtonスクリプトをStartButtonオブジェクトのコンポーネントに加えます。

Start ButtonオブジェクトのButtonコンポーネントに自オブジェクトをセットします。

ボタンがクリックされたときの動作を「OnGameStartButtonClick()」に設定します。

これでGameStartボタンをクリックすると、GameSceneに移動し、ゲームが開始されます。

ゲームオーバー時のリスタート機能を追加

ボタンデザインを作成

ゲームオーバーになった時、ゲームが中断したままになっていましたので、リスタート機能を追加します。GameSceneからリスタートする「RestartButton」とTitleSceneに戻ってリスタートする「ReturnTitleButton」2つのボタンを追加しました。

こんな感じ。このままだと、GameSceneに移動したときにボタンが表示されていますので、オブジェクトは非表示にしておきます。

GameController.csでこの2つのボタン設定を扱えるよう

public Button restartButton;
public Button returnTitleButton;

追記し、2つのボタンオブジェクトを下図のようにGameControllerスクリプトコンポーネントに設定します。

ゲームオーバーになった時は、リスタートボタンが表示されるようGameController.csに以下追記し、アクティブにします。


void Update() {
    switch(gameStat){
        /* 
        (省略) 
        */
    
        case GAMEOVER:
            gameOverText.gameObject.SetActive(true);
            restartButton.gameObject.SetActive(true);
            returnTitleButton.gameObject.SetActive(true);
            break;
    }
    /* 
    (省略) 
    */
}

「Return to Title」ボタンを押したら「TitleScene」に移動するスクリプト追加

GameController.csでもSceneMangement名前空間を使用するので、以下先頭に追加します。

using UnityEngine.SceneManagement;

タイトル画面に戻るメソッドを作成し、

public void OnReturnTitleButtonClick()
{
    SceneManager.LoadScene(0);
}

ReturnTitleButtonのButtonコンポーネントにセットします。

これでタイトル画面に戻るボタンを押したらタイトル画面に戻れます。

「Restart」ボタンを押したらリスタートするスクリプト作成

「Restart」ボタンが押されたときに動作させるメソッドを作成します。

public void OnRestartButtonClick()
{
    gameOverText.gameObject.SetActive(false);
    restartButton.gameObject.SetActive(false);
    returnTitleButton.gameObject.SetActive(false);
    NextBlockSet();
    setStart();
}

ゲームオーバー時に表示されたテキスト、ボタンを非表示にします。そして、ゲーム開始時の状態に戻します。

setStart()メソッドは下記の通りです。

private void setStart()
{
    gameStat = START;
    fallCountTime = 0;
    groundCountTime = 0;
    downIhbFlg = false;

    score = 0;
    ResetBlock();
}

private void ResetBlock(){
    for(int i=1; i<11; i++){
        for(int j=0; j<18; j++){
            blockStat[j, i] = 0;
        }
    }
}

実際に動かしてみよう

まとめ

今回は、まずタイトル画面を追加し、Game Startボタンを押したら、ゲームを開始するようにしました。次にゲームオーバーになったら、タイトルに戻るかゲームをやり直すか選択出来るようにしました。

ゲームの完成まであと少しです。

次回はハイスコアを記録し、セーブする機能を追加したいと思います。

https://craft-gogo.com/unity-first-puzzlegame11/

最後までお読み頂きありがとうございました。

]]>
【Unity初心者】JsonUtilityを使ったデータセーブ/ロード方法 https://craft-gogo.com/unity-datasave/ Mon, 14 Feb 2022 15:03:10 +0000 https://craft-gogo.com/?p=1754

Unityでゲームデータをセーブし、次のゲーム開始時にデータをロードしたいと悩んでいませんか? 今回は、JsonUtilityというクラスを使ってJSON形式でデータをセーブ、ロードする方法について解説します。 この記事 […]]]>

Unityでゲームデータをセーブし、次のゲーム開始時にデータをロードしたいと悩んでいませんか?

今回は、JsonUtilityというクラスを使ってJSON形式でデータをセーブ、ロードする方法について解説します。

この記事は

見出し
  • データセーブ、ロード方法が分からないよっていうUnity初心者
  • JSON形式って何?

っていう方に読んでもらいたいです。

ここでは、簡単な仕組みをUnityで作りながら解説していきます。

現在スコアがハイスコアより高かったときにハイスコアを更新し、セーブ。ゲーム再開時にハイスコアをロードするといった仕組みです。

それでは、始めましょう!

予備知識

JSONとは

JSONとは「JavaScript Object Notation」の略で、軽量なテキストベースのデータ交換用フォーマットです。

何を言っているんだ~と思った方は、実際の例を見て下さい。

{"bestName":"Steve","bestScore":1500}

基本的には{ }内に 変数名: 値 と記述していくフォーマットです。

今回はこれだけの知識で十分です。

JSONについてもっと詳しく知りたいと思われた方はGoogle先生で調べてみて下さい。

Unityに備わるJsonUtilityクラス

変数をJSON形式に変換するのは面倒くさいと思われた方。安心して下さい。

UnityにはJsonUtilityというクラスが備わっています。このクラスを使えば、簡単にデータをJSON形式に変換することができます。

using System.IO;

をスクリプト先頭に記述し、

JsonUtility.ToJson() // JSON形式へ変換
JsonUtility.FromJson<>(); // JSON形式から変換

JsonUtility.ToJson()を使えば、変数をJSON形式へ変換。JsonUtility.FromJson<>()を使えばJSON形式から変数に変換できます。

データセーブ/ロード方法

現在スコアがハイスコアより高かったときにハイスコアを更新しセーブ、ゲーム再開時にハイスコアをロードするといった仕組みを作りながら、データセーブ/ロード方法について解説していきます。

Unity上で現在スコアを入力、ハイスコアを表示するUIを作成

まず初めに、Unity上でUIを作成していきます。下図のように現在スコアを入力、ベストスコアを表示するUIを作成して下さい。レイアウトやデザインはお好みで。

次にInputField入力、Text表示をスクリプト上から行えるようにします。

MainManager.csというスクリプトファイルを作成し、下の記述を追加します。

public InputField currentNameIF;
public InputField currentScoreIF;
public Text bestNameText;
public Text bestScoreText;

空のオブジェクトを作り、MainManagerと名称を変更した後、先ほど作成したMainManager.csをコンポーネントに追加します。下のようにスクリプトで作成した変数にTextオブジェクト、Input Fieldオブジェクトを設定しましょう。

これでスクリプト上からInputField入力、Text表示を扱えるようになります。

ハイスコアをセーブし、ゲーム再開時にロードするスクリプト作成

セーブデータ格納クラス作成

始めにJSON形式でセーブするデータを格納するクラスを作成します。

[System.Serializable]
class SaveData
{
    public string bestName;
    public int bestScore;
}

クラスの前に記述した[System.Serializable]は、クラスデータをJSON形式に変換する際に必要となります。

JSON形式で保存するメソッド作成

次にSETボタンをクリックしたときに現在スコアがハイスコアを上回っていたら、名前とハイスコアを更新し、これらをJSON形式で保存するメソッドを作成します。

public void OnSetButtonClicked(){
    string currentName;
    int currentScore;
    currentName = currentNameIF.text;
    currentScore = int.Parse(currentScoreIF.text);

    if(currentScore > bestScore)
    {
        bestNameText.text = "Name: " + currentName;
        bestScoreText.text = "Score: " + currentScore;

        SaveData data = new SaveData();
        data.bestName = currentName;
        data.bestScore = currentScore;

        string json = JsonUtility.ToJson(data);

        File.WriteAllText(Application.persistentDataPath + "/savefile.json", json);
    }
}

JsonUtility.ToJson()は、JSON形式に変換する記述です。

File.WriteAllText()は第1引数で指定されたファイルに第2引数で指定された変数を書き込みます。

Application.persistentDataPathの場所は、Windowsだと\usr\AppData\LocalLow\CompanyNameになります。

データセーブする仕組みを実装したので、次はデータロードする仕組みです。

データロードするメソッドの作成

ゲーム再開したら、セーブしたデータをロードしたいので、Start()メソッドにデータロードスクリプトを記述していきます。

void Start(){
    string path = Application.persistentDataPath + "/savefile.json";
    if (File.Exists(path))
    {
        string json = File.ReadAllText(path);
        SaveData data = JsonUtility.FromJson<SaveData>(json);

        bestName = data.bestName;
        bestScore = data.bestScore;
    }
    else
    {
        bestName = "";
        bestScore = 0;
    }

    bestNameText.text = "Name: " + bestName;
    bestScoreText.text = "Score: " + bestScore;

}

Application.persistentDataPathのsavefile.jsonファイルをFile.ReadAllTextで読み込みます。

読み込んだJSON形式のデータをJsonUtility.FromJson<>()でSaveDataクラスの形式に変換します。

そして、ベストスコアと名前をゲーム画面に表示するといった流れです。

完成したものを動かそう

Buildして実行してみましょう。

CurrentのNameとScoreに入力し、SETボタンを押して下さい。BestのScoreよりCurrent Scoreが高ければ、BestのName、Scoreが更新されます。ゲームを中断し、再開してもBestのNameとScoreはゲーム中断前の情報が保持されているはずです。

まとめ

JsonUtilityというクラスを使ってJSON形式でデータをセーブ、ロードする方法について簡単な仕組みを作りながら解説しました。

現在スコアがハイスコアより高かったときにハイスコアを更新しセーブ。ゲーム再開時にハイスコアをロードするといった仕組みです。

作成方法おさらい

  • Unity上で現在スコアを入力、ハイスコアを表示するUIを作成
  • ハイスコアをセーブし、ゲーム再開時にロードするスクリプト作成

データをセーブ、ロードはゲーム制作の基本ですね。

最後までお読み頂きありがとうございました。

]]>
Unityではじめてのテトリス風落ちゲー制作 ~その9 ゲームオーバー機能追加編~ https://craft-gogo.com/unity-first-puzzlegame9/ Sun, 13 Feb 2022 13:02:47 +0000 https://craft-gogo.com/?p=1728

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回はゲームオーバー機能追加編です。

前回記事では、消去列数に応じてスコアを加算する仕組みを作りました。

今回は、最上位列までブロックが積みあがったらゲームオーバーになる機能を追加します。

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

ゲーム画面にGame Overと表示させるためのテキストオブジェクトを追加

まず、ゲーム画面にGame Overと表示させるため、テキストオブジェクトを追加します。

HierarchyウィンドウからUI > Textを選択し、テキストオブジェクトを作成しましょう。名称をGameOver Textに変更します。

Textコンポーネントの設定を下図のように変更しましょう。

Sceneウィンドウには、下図のようにGame Overのテキストが表示されます。

ゲーム開始時にはGame Overのテキストは非表示にしますので、下図のチェックボックスをオフにします。

続いて、スクリプト上からGameOver Textオブジェクトを操作出来るようにします。

GameControllerスクリプトにText型の変数を宣言します。

public Text gameOverText;

Game ControllerコンポーネントにgameOverText変数が追加されますので、GameOver Textオブジェクトをドラッグします。

これでスクリプト上からGameOver Textを操作出来ます。

ゲームオーバー判定メソッドの作成

最上位列がブロックで埋まったらゲームオーバーと判定するメソッドを作成します。

GameControllerスクリプトを開いて下さい。

下記メソッドを追記します。

private bool JudgeGameOver()
{
    if(blockStat[fallBlockInitPosY, fallBlockInitPosX] == 3)
    {
        return true;
    }
    else
    {
        return false;
    }
}

落下ブロックの初期位置が配置ブロック(=3)の時にJudgeGameOverはtrueを返します。

ゲームオーバーを判定し、GameOverテキストオブジェクトをアクティブ化

JudgeGameOverメソッドを使ってゲームオーバーの時にゲーム画面上に”Game Over”と表示させます。

状態遷移図を基に、GROUND状態のときにJudgeGameOverメソッドによってゲームオーバーを判定します。ゲームオーバーと判定したら、GAME OVER状態に遷移し、GameOver Textオブジェクトをアクティブにします。ここでも状態遷移図を作っておくとプログラムを書くのが楽ちんですね。

GameControllerスクリプトのUpdateメソッドに上記処理を追加します。

void Update() {
    switch(gameStat){
        case START:
            /* (省略) */
            break;

        case GROUND:
            /* (省略) */

            // 落下ブロックの着地確定
            if(groundCountTime >= 1){
                /* (省略) */

                // 1列以上ブロックが揃ったら"ERASE"に遷移
                if(JudgeEraseRow()){
                    gameStat = ERASE;
                }
                // 最上位までブロックが積みあがったら"GAMEOVER"に遷移
                else if(JudgeGameOver()){
                    gameStat = GAMEOVER;
                }
                else
                {
                    NextBlockSet();
                    gameStat = START;          
                }
                
            }
            break;

        case ERASE:
            /* (省略) */
            break;
            
        case GAMEOVER:
            gameOverText.gameObject.SetActive(true);
            break;
    }
}

実際にゲームを動かしてみよう

最上位列までブロックが積みあがったらゲーム画面にGame Overと表示されるようになりました!

まとめ

今回はゲームオーバー機能追加編として、最上位列までブロックが積みあがったらゲームオーバーになる機能を追加しました。

作り方をおさらいすると

  • ゲーム画面にGame Overと表示させるためのテキストオブジェクトを追加
  • ゲームオーバー判定メソッドの作成
  • ゲームオーバーを判定し、GameOverテキストオブジェクトをアクティブ化

です。

次回は、タイトル画面を作り、シーンを遷移させる機能を追加していきたいと思います。

https://craft-gogo.com/unity-first-puzzlegame10/

最後までお読み頂きありがとうございました。

]]>
Unityではじめてのテトリス風落ちゲー制作 ~その8 スコア加算編~ https://craft-gogo.com/unity-first-puzzlegame8/ Tue, 08 Feb 2022 15:45:35 +0000 https://craft-gogo.com/?p=1560

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回はスコア加算編です。

前回記事では、1列ブロックが揃ったのを判定し、ブロックを消去するまでのプログラムを解説しました。

今回は、消去列数に応じてスコアを加算する仕組みを作っていきます。

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

スコアを表示するTextオブジェクトを作成

まず、ゲーム画面上にスコアを表示するテキストオブジェクトを追加します。

HierarchyウィンドウからUI > Textを選択して下さい。

Canvasオブジェクトが出来、その下にTextオブジェクトが追加されます。名前をScore Textに変更しましょう。

次にInspectorウィンドウ TextコンポーネントのText、Font Size、Colorを下図のように変更します。

続いてSocre Textオブジェクトをゲーム画面左上に配置します。

Inspectorウィンドウ Rect TransformコンポーネントのAnchor Presetsを選択し、Altキーを押しましょう。すると、下図のような表示から

下図の表示に変わります。四角で囲まれた箇所をクリックして下さい。

Score Textオブジェクトがゲーム画面の左上に配置されました。

消去列に応じてスコアを加算するメソッド作成

ここでは、消去列に応じてスコアを加算するメソッドを作成していきます。

GameControllerスクリプトを開いて、下のAddScoreメソッドを追加して下さい。

private int AddScore(int rowNum)
{
    int addScore;

    if(rowNum == 1){
        addScore = 10;
    }
    else if(rowNum == 2){
        addScore = 30;
    }
    else if(rowNum == 3){
        addScore = 80;
    }
    else if(rowNum == 4){
        addScore = 200;
    }
    else{
        addScore = 0;
    }

    return addScore;
}

引数を消去列、戻り値を加算スコアとしています。1列揃ったら10点、2列揃ったら30点、3列揃ったら80点、4列揃ったら200点としました。

1列以上揃ったら、列数に応じたスコアを加算し、Textオブジェクトに反映するスクリプト作成

Score TextオブジェクトのTextをGameControllerスクリプト上から変更出来るように、以下をスクリプト先頭に追加します。

using UnityEngine.UI;

次にscoreText変数、score変数を追加します。

public Text scoreText;
private int score;

Unityに戻るとGame ControllerオブジェクトのGameControllerコンポーネントにscoreText変数が追加されますので、Score Textオブジェクトをドラッグします。

これでGameControlleスクリプト上からScore TextオブジェクトのTextを変更する準備が整いました。

では、消去列に応じた点数をscoreに加算し、scoreTextに反映するスクリプトを作成していきます。

まず、前回のブロック消去編で作成したBlockEraseメソッドを修正します。

消去列数eraseCountを戻り値として返すようにしました。

private int BlockErase(){
    int eraseCount;
    /*
    (省略)
    */

    return eraseCount;

}

eraseCountをAddScoreメソッドの引数とし、消去列数に応じた点数をscoreに加算します。そして、scoreTextにscoreを反映させます。


void Update() {
    switch(gameStat){
        /*
        (省略)
        */

        case ERASE:
            int n;
            n = BlockErase();
            score += AddScore(n);
            scoreText.text = "SCORE: " + score;
            NextBlockSet();
            gameStat = START;
            break;
            
    }
}

実際にゲームを動かしてみよう

1列揃ったらゲーム画面左上に、消去列数に応じて加算されたスコアが表示されます。

まとめ

消去列数に応じてスコアを加算する仕組みを作りました。

今回以下を解説しました。

  • スコアを表示するTextオブジェクトを作成
  • 消去列に応じてスコアを加算するメソッド作成
  • 1列以上揃ったら、スコアを加算し、UI表示するスクリプト作成

次回は最上位列までブロックが埋まったらゲームオーバーする仕組みを作っていく予定です。

https://craft-gogo.com/unity-first-puzzlegame9/

最後までお読み頂きありがとうございました。

]]>
Unityではじめてのテトリス風落ちゲー制作記 ~その7 ブロック消去編~ https://craft-gogo.com/unity-first-puzzlegame7/ Sat, 05 Feb 2022 07:03:17 +0000 https://craft-gogo.com/?p=1514

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回はブロック消去編です。

前回記事では、落下ブロックが着地したら、配置ブロックへ変換させるプログラムを作成しました。

今回は、 1列ブロックが揃ったのを判定し、ブロックを消去するまでのプログラムを解説します。

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

消去判定

まず、1列すべてブロックが揃った列を検索して、列を消去するかどうか判定するメソッドを作成します。

private bool JudgeEraseRow()
{
    bool eraseFlg = false;
    for(int j=0; j<18; j++){
        eraseRow[j] = false;
        bool buff = true;
        for(int i=1; i<11; i++){
            if(blockStat[j,i] != 3)
            {
                buff = false;
            }
        }
        if(buff == true){
            eraseRow[j] = true;
            eraseFlg = true;
        }
    }
    return eraseFlg;
}

戻り値として、bool型のeraseFlgを返し、trueであれば1列以上ブロックが揃っていることになります。

bool型の配列eraseRowは、何列目が揃ったかの情報を格納します。

ブロック消去し、下に詰める

揃った列のブロックを消去して下に詰めるプログラムの解説です。

private void BlockErase(){
    int i,j,k;
    int eraseCount;

    eraseCount = 0;
    for(j=0; j<18; j++){
        if(eraseRow[j] == true){
            eraseCount++;
            // 1行消去
            for(i=1; i<11; i++){
                blockStat[j, i] = 0;
            }
            // 消去分、下にずらす
            for(k=j; k>0; k--){
                for(i=1; i<11; i++){
                blockStat[k, i] = blockStat[k-1, i];
                blockStat[k-1, i] = 0;
                }
            }
        } 
    }
}

最上位からブロックが揃った列を探索していき、揃った列を見つけたら、その列すべてのブロック状態を、「3」から「0」に変換します。

そして、消去した列より上の列を1マスずつ下にずらします。

ゲーム画面更新

前回までは、ブロックのゲーム画面表示をUpdate()内に記述していましたが、配置ブロックもUpdate()内に記述すると見通しが悪くなるので、メソッド化しました。

private void UpdateDisplay()
{
    // 落下ブロックのゲーム画面表示
    for(int i=0; i<4; i++){
        for(int j=0; j<4; j++){
            Destroy(fallBlockObj[j,i]);
            if(fallBlockStat[j,i] == 2){
                fallBlockObj[j,i] = Instantiate(fallBlockPfb, new Vector3(fallBlockPosX + i + OX, -fallBlockPosY -j + OY, 0), Quaternion.identity);  
            }
        }
    }

    // 配置ブロックのゲーム画面表示
    for(int i=1; i<11; i++){
        for(int j=1; j<18; j++){
            Destroy(blockObj[j,i]);
            if(blockStat[j,i] == 3){
                blockObj[j,i] = Instantiate(placementBlockPfb, new Vector3(i + OX, -j + OY, 0), Quaternion.identity);  
            }
        }
    }
}

作成したメソッドをUpdate()に追加

ゲーム設計編で作成した状態遷移図を基に、”GROUND”状態時に消去判定し、ブロックが1列以上揃ったばあいに”ERASE”状態に遷移させます。

状態遷移図があると、プログラム作成がすいすい進みます。設計は大事ですね。

void Update() {
    switch(gameStat){
        case START:
        /*
        (省略)
        */

        case GROUND:
            /*
            (省略)
            */

            // 落下ブロックの着地確定
            if(groundCountTime >= 1){
                /*
                (省略)
                */

                // 1列以上ブロックが揃ったら"ERASE"に遷移
                if(JudgeEraseRow()){
                    gameStat = ERASE;
                }
                else
                {
                    NextBlockSet(); // 次の落下ブロックをセット
                    gameStat = START;          
                }
                
            }
            break;

        case ERASE:
            BlockErase(); // 揃った列のブロックを消去し、1列下に詰める
            NextBlockSet(); // 次の落下ブロックをセット
            gameStat = START;
            break;
            
        case GAMEOVER:
            break;
    }
    /*
    (省略)
    */
    UpdateDisplay();
}

プログラムを動かしてみよう

ブロックが1列揃ったらブロックが消えるようになりました。かなりゲームになってきました!

まとめ

今回は、 1列ブロックが揃ったのを判定し、ブロックを消去するまでのプログラムを解説しました。

次回は、ブロックが1列揃ったら得点を増やし、ゲーム要素を追加していく予定です。

https://craft-gogo.com/unity-first-puzzlegame8/

最後までお読み頂きありがとうございました。

]]>
Unityではじめてのテトリス風落ちゲー制作記 ~その6 ブロック配置編~ https://craft-gogo.com/unity-first-puzzlegame6/ Thu, 03 Feb 2022 14:15:50 +0000 https://craft-gogo.com/?p=1467

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回はブロック配置編です。

前回記事では、落下ブロックの当たり判定を作成し、落下ブロックが壁ブロックに接触した際の移動を拘束するプログラムを作成しました。更に壁ブロックに着地すると、次の落下ブロックが落ちてくるようにしました。

今回は、 落下ブロックが着地したら、配置ブロックへ変換させるプログラムの解説をします。

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

落下ブロックを配置ブロックに変換

落下ブロックが着地確定したら、落下ブロックを配置ブロックに変換します。配置ブロックの状態は「3」と定義しましたので、落下ブロックが着地した位置のブロック状態を「3」にします。

その後、次の落下ブロックを初期位置にセットし、落下開始させます。

void Update() {
    switch(gameStat){
        case START:
            /*
            (省略)
            */
            break;
        case GROUND:
            /*
            (省略)
            */
            if(groundCountTime >= 1){
                // 落下ブロックを配置ブロックに変換
                for(int i=0; i<4; i++){
                    for(int j=0; j<4; j++){
                        if(fallBlockStat[j,i] == 2){
                            blockStat[j +fallBlockPosY, i +fallBlockPosX] = 3;
                        }
                    }
                }

                // 次の落下ブロックを初期位置にセットし、落下開始
                fallBlockPosX = fallBlockInitPosX;
                fallBlockPosY = fallBlockInitPosY;
                blockNum = Random.Range(0, 8);
                rot = 0;
                fallBlockStat = fallBlockSet.set(blockNum, rot);
                gameStat = START;
                groundCountTime = 0;
            }
            break;
        case ERASE:
            break;
            
        case GAMEOVER:
            break;
    }
}

配置ブロックの画面表示

ゲーム画面に配置ブロックを表示させます。配置ブロックPrefabをブロック状態が「3」の位置にセットします。

public GameObject placementBlockPfb; // 配置ブロックPrefab
    
void Update() {
    // 配置ブロックの画面表示
    for(int i=1; i<11; i++){
        for(int j=1; j<18; j++){
            Destroy(blockObj[j,i]);
            if(blockStat[j,i] == 3){
                blockObj[j,i] = Instantiate(placementBlockPfb, new Vector3(i + OX, -j + OY, 0), Quaternion.identity);  
            }
        }
    }
}

Unityの画面に戻ったら、Game ControllerコンポーネントのPlacement Block Pfb欄にPlacement Blockをセットしましょう。

動作確認

まとめ

今回は落下ブロック配置編として、 落下ブロックが着地したら、配置ブロックへ変換させるプログラム 作成を解説しました。

次回はゲームの肝である、横一列揃ったら消去するプログラムの解説をしていく予定です。

最後までお読み頂きありがとうございました。

https://craft-gogo.com/unity-first-puzzlegame7/

]]>
Unityではじめてのテトリス風落ちゲー制作記 ~その5 当たり判定編~ https://craft-gogo.com/unity-first-puzzlegame5/ Fri, 12 Nov 2021 10:35:01 +0000 https://craft-gogo.com/?p=1396

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。 この連載を最後まで読め […]]]>

Unityでテトリス風落ちゲーを作ってみたいけど、何から手を付けていいか分からない。私もそんな一人です。ここでは、自分の勉強も含めて、簡単なテトリス風落ちゲーを制作していく過程を掲載していきます。

この連載を最後まで読めば、このようなテトリス風落ちゲーが1人で作れるようになります。

別ウィンドウで開く場合はこちら

今回は当たり判定編です。

本記事は4つの構成で解説していきます。

  1. 落下ブロックが壁または配置ブロックに着地したことを判定するプログラム解説
  2. 落下ブロックが壁または配置ブロックに側面当たりしたことを判定するプログラム解説
  3. 落下ブロック着地したら、一定時間経過後に次の落下ブロックを落とすプログラム解説
  4. 落下ブロック側面当たりしたら、落下ブロックの横移動を拘束するプログラム解説

まだ落下ブロック操作編を読んでない方は、こちらを先に読むことをお勧めします。

この記事はこんな人におすすめ!

  • 用意されたアセットを極力使わず、自分の力でゲームを作りたい
  • プログラミング初心者で1つ1つ丁寧に解説した記事が読みたい
  • Unity初心者がスキルを上げながらゲームを制作していく過程を見たい

本ゲーム制作方法は自己流です。もっと簡単に作る方法もあると思いますので、ご了承下さい。

落下ブロックの着地判定

落下ブロックの着地判定は、落下ブロックの1マス下が壁ブロックまたは配置ブロックの場合に判定するようにします。

各マスの状態は、落下ブロック「2」、壁ブロック「1」、配置ブロック「3」と定義しました。そのため、落下ブロック「2」の1マス下が壁ブロック「1」または配置ブロック「3」であれば、着地と判定させます。

下のjudgeGroundメソッドが落下ブロックの着地判定になります。

public bool judgeGround(int blockNum, int rot, int[,] blockStat, int x, int y){
    bool groundFlg = false;      
    int[,] block = new int[4,4];
    block = fallBlockSet.set(blockNum, rot);
    for(int i=0; i<4; i++){
        for(int j=3; j>=0; j--){
            if(block[j,i] == 2){
                if(blockStat[y + j + 1, x + i] == 1 || blockStat[y + j + 1, x + i] == 3){
                    groundFlg = true;
                    break;
                }
            }
        }
    }
    return groundFlg;
}

落下ブロックの側面当たり判定

落下ブロックの側面当たり判定は、着地判定と同様、 落下ブロックの1マス右または左が壁ブロックまたは配置ブロックの場合に判定するようにします。

下のjudgeContactRightメソッドが落下ブロックの右側面当たり判定、judgeContactLeftメソッドが左側面当たり判定になります。

public bool judgeContactRight(int blockNum, int rot, int[,] blockStat, int x, int y){
    bool contactFlg = false;      
    int[,] block = new int[4,4];
    block = fallBlockSet.set(blockNum, rot);
    for(int j=0; j<4; j++){
        for(int i=3; i>=0; i--){
            if(block[j,i] == 2){
                if(blockStat[y + j, x + i + 1] == 1 || blockStat[y + j, x + i + 1] == 3){
                    contactFlg = true;
                    break;
                }
            }
        }
    }
    return contactFlg;
}
public bool judgeContactLeft(int blockNum, int rot, int[,] blockStat, int x, int y){
    bool contactFlg = false;      
    int[,] block = new int[4,4];
    block = fallBlockSet.set(blockNum, rot);
    for(int j=0; j<4; j++){
        for(int i=0; i<4; i++){
            if(block[j,i] == 2){
                if(blockStat[y + j, x + i - 1] == 1 || blockStat[y + j, x + i - 1] == 3){
                    contactFlg = true;
                    break;
                }
            }
        }
    }
    return contactFlg;
}

落下ブロックが着地したら、一定時間経過後に次の落下ブロックを落とす

落下ブロックの着地判定プログラムが完成したので、着地判定したら一定時間経過後に次の落下ブロックを落とすプログラムを作成していきます。

企画編でゲームの状態遷移を設計しました。

これに則ってプログラムを書いていきましょう。

下のプログラムが 落下ブロックが着地判定したら一定時間毎に落下ブロックを落とすプログラムです。GameControllerスクリプトのStartメソッド、Updateメソッドにプログラムを追加します。既に説明した内容については省略していますので、 ご了承を。

private int gameStat; // ゲームステータス
private const int GAMEOVER = 0;
private const int START = 1;
private const int GROUND = 2;
private const int ERASE = 3;
private bool downIhbFlg; // 0:下移動許可、1:下移動禁止
private float fallCountTime; // 落下ブロックが1マス落下してからの経過時間
private float groundCountTime; // 落下ブロックが着地してからの経過時間
/*
... (省略)
*/
void Start()
{
    gameStat = START;
    fallCountTime = 0;
    groundCountTime = 0;
    downIhbFlg = false;
  /*
    ... (省略)
    */
}
void Update()
{        
    switch(gameStat){
        case START:
            downIhbFlg = false;
            // 落下ブロックを1秒毎に落下
            fallCountTime += Time.deltaTime;
            if(fallCountTime >= 1){
                fallBlockPosY++;
                fallCountTime = 0;
            }
            // 落下ブロックの着地判定
            if(judgeGround(blockNum, rot, blockStat, fallBlockPosX, fallBlockPosY) == true){
                gameStat = GROUND;
            }
            break;
        case GROUND:
            fallCountTime = 0;
            groundCountTime += Time.deltaTime;
            downIhbFlg = true;
            // 落下ブロックの非着地判定
            if(judgeGround(blockNum, rot, blockStat, fallBlockPosX, fallBlockPosY) == false){  
                groundCountTime = 0;
                gameStat = START;
            }
            if(groundCountTime >= 1){
                fallBlockPosX = fallBlockInitPosX;
                fallBlockPosY = fallBlockInitPosY;
                blockNum = Random.Range(0, 8);
                rot = 0;
                fallBlockStat = fallBlockSet.set(blockNum, rot);
                gameStat = START;
                groundCountTime = 0;
            }
            break;
        case ERASE:
            break;
            
        case GAMEOVER:
            break;
    }
    // 下キー or Sキーを押したとき落下ブロックを1マス下に移動
    if(Input.GetButtonDown("Vertical") == true && downIhbFlg == false){
        if(Input.GetAxis("Vertical") < -0.01f)
        {
            fallBlockPosY++; 
            fallCountTime = 0;
        }
    }
}

ゲームが開始したら、ゲームステータスを”START”にします。”START”では、落下ブロックの着地判定を行い、判定したら一定時間後にゲームステータスを”GROUND”に遷移させます。”GROUND”では、着地時間を計測し、一定時間経過したら次の落下ブロックを表示させ、”START”状態に戻します。もしプレイヤーが落下ブロックを左右に移動させ、着地判定から抜けたら何もせず”START”状態に戻します。

落下ブロック側面当たりしたら、落下ブロックの横移動を拘束する

落下ブロックの側面当たり判定を使って、落下ブロックの横移動を拘束するプログラムを作っていきます。

if(Input.GetButtonDown("Horizontal") == true)
{
    // 右キー or Dキーを押したとき落下ブロックを1マス右に移動
    if(Input.GetAxis("Horizontal") > 0.01f && judgeContactRight(blockNum, rot, blockStat, fallBlockPosX, fallBlockPosY) == false)
    {
        fallBlockPosX++; 
    }
    // 左キー or Aキーを押したとき落下ブロックを1マス左に移動
    if(Input.GetAxis("Horizontal") < -0.01f && judgeContactLeft(blockNum, rot, blockStat, fallBlockPosX, fallBlockPosY) == false)
    {
        fallBlockPosX--;
    }
}

キー入力で左右移動するプログラムは既に作成済ですので、キー操作判定内に側面当たり判定を追加することで落下ブロックの横移動を拘束させました。

出来上がったプログラムを動かしてみよう!

落下ブロックを左右に移動し、側面が壁ブロックに接触した際、左右移動が拘束出来ていることが確認出来ましたね。

更に壁ブロックに着地すると、次の落下ブロックが落ちてくるようになりました。

まとめ

今回は当たり判定編として以下内容について解説しました。

  1. 落下ブロックが壁または配置ブロックに着地したことを判定するプログラム解説
  2. 落下ブロックが壁または配置ブロックに側面当たりしたことを判定するプログラム解説
  3. 落下ブロック着地したら、一定時間経過後に次の落下ブロックを落とすプログラム解説
  4. 落下ブロック側面当たりしたら、落下ブロックの横移動を拘束するプログラム解説

現状では、落下ブロックが下壁まで落下してもブロックが配置されず、次の落下ブロックが表示されるだけです。次回は、落下ブロックを配置ブロックへ変換させる方法について解説する予定です。

https://craft-gogo.com/unity-first-puzzlegame6/

最後までお読み頂きありがとうございました。

]]>