『Unity5ゲーム開発レシピ』「Part02 応用編 Chapter03 基本的な動作や設定を制御する」 学習記録

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

序文

『Unity5ゲーム開発レシピ』21日目。

昨日の夜更かしがたたって、また生活リズムが乱れそうです。
気が早いけど、来年は体力もつけたいです。来年。

進捗

  • Part02 応用編
    • Chapter03 基本的な動作や設定を制御する

(学習時間:2.5時間)

コード実装部分

\Chapter1\PART02_CHAPTER03\014\before\dungeon\assets\Scripts\VolumeSettings.cs

using UnityEngine;
using UnityEngine.Audio;
using System.Collections;

public class VolumeSettings : MonoBehaviour
{
    public AudioMixer mixer;

    void Start ()
    {
    }

    void Update () 
    {

    }
    
    public void ChangeMusicVolume (float vol)
    {
        mixer.SetFloat ("MusicVolume", vol);
    }

    public void ChangeSfxVolume (float vol)
    {
        mixer.SetFloat ("SfxVolume", vol);
    }
}

実行結果

www.youtube.com 地味

感想

やったこと。

  • Time.timescaleを使用した一時停止の仕組みの実装
  • AudioMixerを使用したBGM・SEの音量調整の仕組みの実装

音量調整のやつうまくいかないーと思って詰まってたら、参考書の説明不足の点を発見ー。

f:id:yjkym:20180703155827j:plain

サンプルデータではVoiceおよびMusicオブジェクトのAudioSourceコンポーネントのOutputの設定がNoneなので、それぞれAudioMixerのSfxグループおよびMusicグループを設定してやらないと音量の調整ができないんですが、その部分が参考書では説明されていません。

スクリーンショットのように設定してやることで正常に動作するようになります。

いい参考書だと思うんだけど、ちょこちょこいろいろ惜しいよね。

カロリーメイトください。

BGM

健康ランド / 青い果実

www.youtube.com

麻雀のアガリ判定するスクリプト書いた

麻雀ネタその2。

Rubyで麻雀のアガリを判定するスクリプトを書きました。
途中まで自力で書いてたんですけど、効率的な書き方ができそうになかったので、以下の記事を参考にしました。
というか、ほとんどRubyでリライトしただけです。

eiki.hatenablog.jp

意外とややこしいんですよねー…。

詳細は割愛しますが、ざっくり言うとまず雀頭の2枚を固定して、残りの12枚が3枚セット×4の形になってるかどうか判定するんですが…。

① 刻子(同じ牌の3枚セット)のチェック(消去)→順子(連続する3枚の牌のセット)のチェック (消去)
② 順子(3連続)のチェック→刻子(3枚セット)のチェック
③ 刻子(3枚セット)を1組だけ消去→順子のチェック

の3とおりのチェックをしてやる必要があります。

たとえば雀頭を除いた残りの12枚が「111123567999」だった場合、
①のチェックに従ってやると、
1と9に3枚のセットがあるので消去します。(この時点で残りは「123567」)
続いて、123と567が3連続になっているので消去します。
これですべての数字が消去できたのでアガリの形になっていると判定します。

大抵の場合はこのチェックだけで正しく判定できるんですが、まれにこれだけでは正しく判定できない場合があります。

たとえば、雀頭を除いた残りの12枚が「122233344777」だった場合、
①のチェックに従ってやると、
2と3と7に3枚のセットがあるので消去します。(この時点で残りは[144])
残りの3枚には3連続の形はありませんので、これ以上消去できません。
これだと[144]が残ってしまうので、アガリではないと判定されてしまいます。

この場合は、②のように先に順子(3連続)をチェックしてやらないとうまくいきません。
「122233344777」から3連続の形を探すと「123」「234」「234」が存在することがわかります。
これらを消去すると残りは「777」になります。
「777」は3枚同じ数字のセットになっているので消去できます。
これですべての数字が消去できたので、今度はアガリの形になっていると正しく判定できました。

さらに複雑なパターンもあります。
リンク先にも示されていますが「222334455567」のようなパターンです。

まず①の方法でチェックしてみます。
「222334455567」から3枚セットを探してみると2と5が3枚セットになっているので消去します。
すると「334467」が残ります。
これには3連続の形がありませんので、アガリではないと判定されます。

続いて②の方法を試してみます。
「222334455567」から3連続となっている形を探してみると「234」「234」「567」が3連続の形になっているので消去します。
すると「255」が残ります。
これには3枚セットの形がありませんので、やはりアガリではないと判定されます。

①の方法でも②の方法でもうまくいかなかったので、新しい方法を考えてやる必要がありますが、それが③の方法です。
3枚セットをすべて消去するのではなく1組だけ消去してやる方法です。
「222334455567」から最初に見つかる3枚セットは2の3枚セットなので、それを消去します。
すると「334455567」が残ります。
ここから3連続の形を探すと「345」「345」「567」が見つかるので、それらを消去します。
これですべての数字を消去することができたので、めでたくアガリ形であると判定されました。

…というのが、リンク先のアルゴリズム(の一部)なんですが、このやり方で本当に網羅できているのかはよくわかりません。(-_-;;; )

まー私よりはるかに自頭のいい方が書いてるブログなので、きっと網羅されているのでしょう。(権威主義

久しぶりにしっかり頭を使った気がします。
図とか入れたほうがいいんでしょうけど、そこまでやる気力がないです。
カロリーメイトください。

『Unity5ゲーム開発レシピ』「Part02 応用編 Chapter02 フィールドとカメラを工夫して利用する」 学習記録

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

序文

『Unity5ゲーム開発レシピ』20日目。

この週末で1LDKの棲み家を丸2日かけてのんびり掃除しました。
パソコン内とか窓ガラスとか掃除し忘れていることに徐々に気づき始めています。

下半期の目標はスマホアプリを2つリリース、そして来年初リリース予定のWebアプリ2つの準備を完了させることです。
言うだけならタダですからね、とりあえず言っておきましょう。

進捗

  • Part02 応用編
    • Chapter02 フィールドとカメラを工夫して利用する

(学習時間:2.5時間)

コード実装部分

\Chapter1\PART02_CHAPTER02\011\before\dungeon\assets\Scripts\ImageBasedMap.cs

using UnityEngine;
using System.Collections;

public class ImageBasedMap : MonoBehaviour {
    // マップ2Dテクスチャ
    public Texture2D mapImage;
    // Wallプレハブ
    public GameObject chipPrefab;

    // Use this for initialization
    void Start () {
        // 画像幅と画像高を取得して1ピクセルずつ走査していく
        for (int w = mapImage.width - 1; w >= 0 ; w--) {
            for (int h = mapImage.height - 1; h >= 0; h--) {
                // ピクセルが白色なら壁
                if (mapImage.GetPixel (w, h) == Color.white) {
                    // 壁オブジェクトを生成
                    var obj = Instantiate (chipPrefab, new Vector3 (w, 0, h), Quaternion.identity) as GameObject;
                    obj.transform.parent = transform;
                }
            }   
        }
    }
    
    // Update is called once per frame
    void Update () {
    
    }
}

実行結果

f:id:yjkym:20180702155237p:plain

感想

やったこと。

  • Navigationを利用したキャラクターの移動範囲の限定、特定の地点を移動させる仕組みの実装
  • 実際のSceneの地形を簡易表示にしたミニマップの作成と表示
  • 画像からSceneのオブジェクトを生成する仕組みの実装
  • Scene全体を覆う3D空間のサイズを取得する仕組みの実装

スクリーンショットは2D画像(なぜ.psdなんだ)から3D迷路みたいなものを生成してみた図。
白と黒が元画像と3Dオブジェクトで反転しているのですごく分かりづらい。

アルゴリズム自体は割とアナログだ。
そのまま実用的かどうかはともかく、がんばれば等高線図から3D地形を生成するとか、QRコードバトラー的なものを作ってみるとか、いろいろ応用できそうな気はする。

カロリーメイトください。

BGM

調理場 / KREVA
www.youtube.com

麻雀のアガリ牌を生成するやつ書いた

今週末は大掃除のために更新ネタがなくなりそうなので小ネタです。

Rubyで麻雀のアガリ牌を生成するスクリプトを書きました。
generate_agariメソッドの引数で七対子の有効/無効、国士無双の有効/無効、ログ出力の有り/無しを設定できます。
十三不塔(シーサンプトウ)には対応してません。 (誰が分かるんだそんなネタ…)

特に効率的なアルゴリズムとか書いてないくせに、実際の打ち方をシミュレートしているわけでもないというポンコツです。
七対子有効にすると七対子ばっかりになります。国士無双もめっちゃでやすいです。

自分なりにRubyっぽい書き方を意識してみたつもりですがどうなんでしょうか。
気づいたら後置ifとか使ってて自分でもびっくりです。
あとRubyには範囲オブジェクト

(1..10)

(↑みたいなやつ)っていうのがあるんだ!ってのを認識して急に見通しがよくなった気がします。

Rubyの壁はググラビリティの低さだと思う。

カロリーメイトください。

『Unity5ゲーム開発レシピ』「Part02 応用編 Chapter01 キャラクターを制御する」 学習記録3

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

序文

『Unity5ゲーム開発レシピ』19日目。

なんだかんだで長期連載になってきましたね。
1ヶ月で終わるでしょうか。

進捗

  • Part02 応用編
    • Chapter01 キャラクターを制御する

(学習時間:1.5時間)

コード実装部分

\Chapter1\PART02_CHAPTER01\004\before\dungeon\assets\Scripts\AdjustDirection.cs

using UnityEngine;
using System.Collections;

public class AdjustDirection : MonoBehaviour
{
    public float maxDistance = 3f;
    public float maxAngle = 45f;

    void Start ()
    {
    }

    void Update ()
    {
        // Scene上でキャラクター前方に緑の線を描く
        Debug.DrawRay(transform.position, transform.forward * maxDistance, Color.green);

        // Jumpキーが押されたら
        if (Input.GetButtonDown("Jump")) {
            // キャラクター前方に向かってRayを飛ばす
            Ray ray = new Ray (transform.position, transform.forward);
            RaycastHit hit = new RaycastHit ();

            // maxDistance内でrayがhitしたら
            if (Physics.Raycast (ray, out hit, maxDistance)) {
                // hit先のオブジェクトの中心の位置情報を取得する
                Vector3 target = hit.collider.transform.position;
                // Y軸(高さ)情報をプレイヤー位置に合わせる
                target.y = transform.position.y;
                // hit先のオブジェクトがmaxAngle以内にあれば
                if (Vector3.Angle (transform.forward, target - transform.position) < maxAngle) {
                    // hit先のオブジェクトのほうを向く
                    Debug.DrawRay(transform.position, transform.forward * maxDistance, Color.red, 1f);
                    transform.LookAt (target);
                }
            }
        }
    }
}

実行結果

f:id:yjkym:20180629151553p:plain よくわからない

感想

やったこと。

  • キャラクターが認識したオブジェクトの中心方向を自動的に向く仕組みの実装
  • 移動する方向へ滑らかに回転する仕組みの実装
  • あえて不自然なゲーム的な動きを実装する仕組み

最後のやつあんまり使いみちがわかんない。

間にスワイプを感知する仕組みを実装するというすごく実践的なTipsもあったんですが、SDK関連の設定がいまだに詰まっているので保留しています。(+_+)
いろいろ不具合出てきてるので、バックアップとって一旦PCリセットしたいんだけど、Linuxの再設定を自分でできる気がしない。困った。

カロリーメイトください。

BGM

王者の休日 / KREVA
www.youtube.com

『Unity5ゲーム開発レシピ』「Part02 応用編 Chapter01 キャラクターを制御する」 学習記録2

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

序文

『Unity5ゲーム開発レシピ』18日目。

この後もくもく会です。

reedex.connpass.com

Web系のもくもく会への参加は、今回でとりあえず一区切りにしようかなと思っています。

進捗

  • Part02 応用編
    • Chapter01 キャラクターを制御する

(学習時間:1.5時間)

コード実装部分

\Chapter1\PART02_CHAPTER01\003\before\dungeon\assets\Scripts\Attack.cs

using UnityEngine;
using System.Collections;

// animatorのステートにアタッチされるクラス
public class Attack : StateMachineBehaviour
{
    public string targetTagName;
    public float start, end;
    public float size = 0.5f;

    GameObject target;
    SphereCollider hitCollision;

    override public void OnStateEnter (Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // コリダーがアタッチされていなければ
        if (!hitCollision) {
            // 特定のタグがつけられたゲームオブジェクト(左足)を取得する
            foreach (var obj in GameObject.FindGameObjectsWithTag(targetTagName)) {
                // 取得したオブジェクトがanimatorがアタッチされているオブジェクト(ユニティちゃん)の子オブジェクトなら
                if (obj.transform.IsChildOf (animator.transform)) {
                    // RidigbodyおよびSphereColliderコンポーネントを追加する
                    obj.AddComponent<Rigidbody>();                    
                    hitCollision = obj.AddComponent<SphereCollider>();
                    hitCollision.radius = size;
                    // 初期状態では無効にしておく(余計な干渉を避けるため?)
                    hitCollision.enabled = false;
                    
                    break;
                }
            }
        }
    }

    override public void OnStateUpdate (Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // 現在のステート内経過時間
        float currentTime = stateInfo.length * (stateInfo.normalizedTime % 1f);

        // 指定時間の間だけ衝突判定を有効にする
        if (currentTime > start && currentTime < end) {
            hitCollision.enabled = true;
        } else {
            hitCollision.enabled = false;
        }
    }

    override public void OnStateExit (Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // ステート終了時にはコリダーを無効にする
        hitCollision.enabled = false;
    }
}

実行結果

www.youtube.com

感想

やったこと。

  • 視界内にターゲットがいるか判定する仕組みの実装
  • 当たり判定を特定の部位のみ、特定のタイミングで有効にする仕組みの実装

応用編はソースコードの説明がほとんどないので、自力でコードを読み解いていかなければいけない。
そんなことで学習スピードがガクッと落ちました。

今ぐらいのレベルならちょうどいい難易度で読み解いていけるけど、これから難しいものも出てくるかも。

addComponent()メソッドでスクリプトからコンポーネントをアタッチすることもできるんですねぇ。
SphereColliderはどのオブジェクトにアタッチされてるんだ!?って探し回っちゃいました。

カロリーメイトください。

BGM

SPACE / KREVA

www.youtube.com

『Unity5ゲーム開発レシピ』「Part02 応用編 Chapter01 キャラクターを制御する」 学習記録

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

Unity5ゲーム開発レシピ ハマるゲーム制作のノウハウ

序文

『Unity5ゲーム開発レシピ』17日目。

これから応用編に入るんですが、応用編はまずサンプルデータありきでTipsを解説していくような構成になっているようです。
んーで、そのサンプルデータが最新版のUnity(2018)だとちゃんと開けない感じだったので、昨日は旧いバージョンのUnityをインストールしたり改めて環境構築しておりました。

進捗

  • Part02 応用編
    • Chapter01 モーションをキャンセルして次のモーションに切り替えるには

(学習時間:1時間)

コード実装部分

\Chapter1\dungeon\assets\Scripts\ChainAction.cs

using UnityEngine;
using System.Collections;

public class ChainAction : StateMachineBehaviour
{
    public float startTime;
    public float endTime;
    
    // Animator用のUpdateメソッド?
    override public void OnStateUpdate (Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // stateInfo.lengthはアニメーション全体の長さ
        // normalizedTimeはアニメーション開始時を0・再生後を1とした値
        float currentTime = stateInfo.length * (stateInfo.normalizedTime % 1f);

        // アニメーション中にスペースが押された場合、トリガーを発動させる
        if (Input.GetKeyDown(KeyCode.Space) && currentTime > startTime && currentTime < endTime) {
            animator.SetTrigger ("ChainSucceed");
        }
    }
    
    override public void OnStateExit (Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // ステートを抜ける時にトリガーをリセットする
        animator.ResetTrigger ("ChainSucceed");
    }
}

実行結果

www.youtube.com

感想

やったこと。

  • スペースキーを押すと、モーション途中でも次のモーションに切り替わる仕組みの実装

字面だけ見ると、それくらい簡単に実装できるだろ!って思っちゃうけど、割と面倒なんですねぇ。

どうやら応用編からライターの方が変わった(おそらくBATA氏→まつだす氏)ようで、コードにコメントを書かないスタイルになってしまったので、自分でしっかり調べていかないといけない。

stateInfo.normalizedTimeを1fで剰余している意味は、1.0という値にしないためだろうか。
どういう意味があるのかは正直よくわからない。

あ、応用編は基本編みたく1つのゲームを作りあげていく流れじゃなくて、各Tipsごとにその都度サンプルデータをDLして、機能を実装していくかたちになるようです。
そんなことでGitHubにあげるのは自重。

カロリーメイトください。

BGM

少年ジャンプデストラクション / THE 君に話すよ

www.youtube.com