Android/iOS アプリ「二人麻雀 - 索發(そうはつ)」をリリースしました!

Android/iOS アプリ「二人麻雀 - 索發(そうはつ)」をリリースしました!

索發(そうはつ)は索子と發だけで行う二人対戦麻雀です。オンライン対戦もあります。

以下スクリーンショットになります。

f:id:kyoto-u-kohei:20170828030548p:plainf:id:kyoto-u-kohei:20170828030716p:plainf:id:kyoto-u-kohei:20170828030636p:plain

 

play.google.com

 

二人対戦麻雀 - 索發(そうはつ)

二人対戦麻雀 - 索發(そうはつ)

  • Kohei Imatomi
  • ゲーム
  • 無料

 

簡単なルール

索發(そうはつ)ついて簡単に説明すると、

・牌は索と發のみを使う

・2面子1雀頭(8枚)で構成する

・鳴きはポン、カンのみ。チーは無し

という感じになります。手牌は8枚のみで構成されるので簡単に和了れるようになっています。

 

役について

役は一部の特殊な役を除き、通常の麻雀と同じです。ただし、混一色清一色は存在しません。特殊な役として四対子という対子4つで付く役があります。

【役一覧】
一翻
立直 / 役牌 / 断幺九 / 平和 / 門前清自摸 / 一盃口 / 河底撈魚 / 嶺上開花 / ダブル立直

二翻
対々和 / 四対子 / 全帯 / 混老頭

三翻
純全帯

四飜
人和

役満
緑一色 / 紅孔雀 / 地和 / 天和 / 二暗刻単騎自摸/清老頭

 

追記

Appliv 様にアプリのレビューをしていただきました!

二人対戦麻雀 - 索發(そうはつ) [Android] - Appliv

二人対戦麻雀 - 索發(そうはつ) - Appliv

 

Appliv 様のサイトで麻雀ゲームランキング8位にランクインしました!(2017/9/13 現在)

麻雀ゲーム おすすめアプリランキング | iPhoneアプリ - Appliv

 

 

Unity + Admob を使っていて Android 実機環境で終了処理を行うコールバック関数が動かない

目次

問題点

Unity で Admob を使っていて、Androidリワード動画広告を再生後、各種コールバック関数が呼び出されない。

前提知識

Admob の Unity 向けプラグインRewardBasedVideoAd というクラスには主に以下のコールバック関数がある

OnAdRewarded リワード広告再生が成功して報酬を受け取り処理を行うときに呼び出される。
OnAdClosed 広告再生後、クローズボタンを押したときに呼び出される。

しかし、Android 実機環境で動画広告の再生はされるが、広告を閉じたあと、これらのコールバック関数が呼び出されない不具合が発生した。


原因

今回の原因は大きく2つあった。

1. コールバック関数内で Debug.Log が動いていなかった

まずコールバック関数が呼び出されたどうかの確認を Unity の標準ログ Debug.Log を使っていたが、コールバック内ではうまく動かないらしい。
github.com

なぜそうなのかは分からないが、ともかく別の手段(UI の色を変えるなど)でコールバック関数が発火されていることは確認した。
しかし、それでもその後の処理がうまくいかなかった。

2. Admob 動画広告再生後、AudioSource.Play で例外が発生していた
adb Logcat でログを確認すると AudioSource.Play 関数を呼び出していたところで例外が発生していた。
詳しくは分からないが、Unity がスレッドセーフでない関係で、Admob 動画広告を再生したあと、すぐに AudioSource.Play を呼び出すとこけるらしい。

以下のリンクが参考になった。
groups.google.com

解決策

コールバック関数内でオーディオを含む終了処理は StartCoroutine を使って少し間を開けて実行する。

// 広告が閉じられたときに呼び出されるコールバック関数
private void onAdClosed(object _sender, System.EventArgs _args) {
    StartCoroutine(_onEnd());
}

private IEnumerator _onEnd() {
    yield return new WaitForSeconds(1f);
    // オーディオを鳴らすなどの終了処理をここに書く
}

これで上手く再生後の処理が行われた。

Visual Studio で改行コードを Unix (LF) に統一する

目次

問題点

Visual Studio で開発しているとき、改行コードを Unix (LF) に統一したいときがある。
File > Advanced Save Options... から改行コードを指定するという記事がよく出てくるけど、毎回ファイルを開くたびに指定するのは大変。一度設定すれば、その後、改行コードが統一される方法を探す。

使っているのは Visual Studio 2015 です。

解決策

Trim line ends on save」というエクステンションを入れればいい。

Tools > Extensions and Updates... を開く。
左の項目の Online を選択して右上の検索窓に「Trim line ends on save」と入力する。
出現した「Trim line ends on save」を選択してダウンロードする。
ダウンロードしたファイルを実行して、エクステンションを追加する。

f:id:kyoto-u-kohei:20170801145121p:plain


Tools > Options... を開いて、左の項目の IDCT > Trim on save から改行コードを設定できる。
ここでは Unix (LF) にしている。

f:id:kyoto-u-kohei:20170801145143p:plain


これて保存するときに自動で Unix 改行コードに変換してくれるようになる。

「UNet Client Disconnect Error: NoResources」というエラーの解決方法

目次

問題点

Unity の通信モジュール UNet の NetworkServerSimpleNetworkClient を使って通信するとき、クライアントから 9回目の接続で以下のような謎のエラーがクライアント側で発生して、それ以降通信できなくなる。

UNet Client Disconnect Error: NoResources

docs.unity3d.com
docs.unity3d.com

Unity のバージョンは 5.6.1f1 です。

原因

サーバー側の maxConnecitons の値がデフォルトで(恐らく)9 になっているため。

解決策

NetworkServerSimple の Configure 関数を使って maxConnections の値を大きくする。

using UnityEngine;
using UnityEngine.Networking;

public class ServerTest : MonoBehaviour {
    public int port;

    void Start () {
        NetworkServerSimple server = new NetworkServerSimple();
        ConnectionConfig config = new ConnectionConfig();
        server.Configure(config, 100);
        server.Listen(port);
    }
}

しかしこのままでは Client と Server 側で ConnectionConfig の設定が違うものになってしまうから以下のエラーが発生してしまう。

UNet Client Disconnect Error: CRCMismatch
UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()

以下のようにして Client でも同じ設定をしてあげる必要がある。

using UnityEngine;
using UnityEngine.Networking;

public class ServerTest : MonoBehaviour {
    public string ip;
    public int port;

    void Start () {
        NetworkClient client = new NetworkClient();
        ConnectionConfig config = new ConnectionConfig();
        client.Configure(config, 10);
        client.Connect(ip, port);
    }
}
おわりに

このエラーログの非常によくないのが、クライアント側で発生して、あたかもクライアントのリソースがないような書き方をしているが、実はサーバー側の問題ということ。
しかも1回発生するとすべてのクライアントで通信が出来なくなるという致命的なエラー。

このエラーについては以下でもっと詳しく議論されている。
https://forum.unity3d.com/threads/about-networkerror-noresources.440642/forum.unity3d.com

UNet の記事は検索してもあまり出てこないし、未知のバグがいっぱいありそう。

スマホアプリ 「二人対戦麻雀 - 索發(そうはつ)」を8/1に公開予定!

スマホアプリ 「二人対戦麻雀 - 索發(そうはつ)」を8/1 に公開予定です!
OS は iOS, Android の2つを予定しています。

索發は京都大学吉田寮で行われている麻雀のローカルルールです。
通常の麻雀との最大の違いは使われる牌が索子と發のみで2面子1雀頭和了になるという点です。


また情報が更新されたら記事に追記していきたいと思います!

追記

少し作業が遅れてまして、8月中旬頃の公開になりそうです...
楽しみにしてくれていた方はごめんなさい。

Unity で作成して開いた cs ファイルが Visual Studio で認識されない

目次

問題点

Unity と Visual Studio が開いている状態で、Unity 側で新しく C# スクリプトを追加すると Visual Studio に反映されないことがある。
Visual Studio の Solution Explore にも作成したファイルが表示されず、補完も効かない。

Visual Studio をアクティブにした段階で下のようなダイアログが出れば、 "Reload All" をクリックすればよいのだが、出ないときがある。

f:id:kyoto-u-kohei:20170626193743p:plain

原因

Visual Studio 以外の箇所からファイルを作成したり、削除したりした場合に Visual Studio がそれを感知できない場合があるのが問題らしい。

解決策

Unity で作成したファイルを Unity 上で開くのでなく Visual Studio をアクティブにする。そうすれば上画像のようなダイアログが出る。
それでも駄目な場合は Visual Studio のメニュー File > Open > Project/Solution を選択し、プロジェクトを開き直せばよい。

参考URL
kanonji.info

Unity で EventSystem.current が null になってる問題

目次

はじめに

EventSystem は GUI におけるユーザーからの受付を管理するためのクラスで、EventSystem.enabled を false にすることでボタン入力などを受け付けないようにできます。
EventSystem はシーンに1つしかないので、EventSystem.current という static フィールドを利用することで EventSystem の参照を取れます。

docs.unity3d.com

問題点

EventSystem.current.enabled を false にするとその後 EventSystem.current.enabled = true として戻そうとしても、current が null といって怒られてしまう。

原因

EventSystem.current は enabled が false のときは取得できない(と思う)。

解決策

一時的に別の変数に入れておく。

using UnityEngine;
using UnityEngine.EventSystems;

public class Test : MonoBehaviour {
    private EventSystem es;
    
    public void Start() {
        es = EventSystem.current;
    }

    public void Lock() {
        es.enabled = false;
    }
    
    public void Unlock() {
        es.enabled = true;
    }
}
応用

今回の話とはちょっと関係ないですが、ロックの数を数えとくと、複数の箇所からのロック・アンロックに対応できるので便利です。

using UnityEngine;
using UnityEngine.EventSystems;

public class UIManager : MonoBehaviour {
    private int eventSystemLockCount = 0;

    public bool isEventSystemLocked
    {
        get
        {
            return eventSystemLockCount > 0;
        }
    }

    private EventSystem eventSystem;

    public void Start() {
        eventSystem = EventSystem.current;
    }

    public void LockEventSystem() {
        eventSystemLockCount++;
        eventSystem.enabled = false;
    }

    public void Unlock() {
        eventSystemLockCount--;

        if (eventSystemLockCount <= 0)
        {
            eventSystem.enabled = true;
        }
    }
}