おもちゃラボ

Unityで遊びを作ってます

MoLMoL2 の遊び方

このたび、MoLMoL2 というゲームアプリをリリースしました!!

MoLMoL2 にはiOS版とAndroid版があり、次のリンクからダウンロードできます。MoLMoL2 は無料で遊べて、アプリ内課金、アプリ内広告もありませんので、安心してお楽しみいただけます。

f:id:nn_hokuson:20180730003407p:plain:w150 f:id:nn_hokuson:20180730003415p:plain:w135

MoLMoL2 ってどんなゲーム?

MoLMoL2 は、高校化学で習うmolの考え方が、遊んでいると勝手に身につくゲームアプリです。

遊び方は超簡単!

  1. 場にあるカードと同じ元素
  2. 場にあるカードと同じmol数

のどちらかを手札から出せます。

f:id:nn_hokuson:20180911193534p:plain:w400

制限時間内に手札をどんどん出して高得点を狙いましょう!

場にあるカードと同じ元素の場合

例えば次の場合、場には窒素(N)があるので、手札からは窒素の札をすべて出せます。

f:id:nn_hokuson:20180911194428j:plain:w450

場にあるカードと同じmol数の場合

また次の場合、 場にある札が0.5molなので、手札からは0.5molの札をすべて出せます。

f:id:nn_hokuson:20180911201129j:plain:w450

お手つきをせずに連続して正解し続ければ、コンボボーナスでどんどん得点が上昇しますよ!

f:id:nn_hokuson:20180911202236g:plain:w300

MoLMoL2 を遊ぶときの唯一の注意点!

同じmol数でも、炭素の後に気体、または気体の後に炭素は出せないので注意!

f:id:nn_hokuson:20180911202826p:plain:w300

攻略情報(というか虎の巻)

「MoLMoL2 面白そう!早速遊びたいけど・・・
すぐにmol数なんて分からないよ!」
という人も大丈夫!
チート表を用意しました!
f:id:nn_hokuson:20180911211101j:plain

場にあるカードが酸素の1mol(32.0) なら、赤枠で囲った横列のカード(同じ元素)または縦列のカード(同じmol数)が出せます!

f:id:nn_hokuson:20180911211503j:plain:w300

ポケット周期表について

MoLMoL2 では高い得点を出せば、周期表の元素がどんどん開いていきます!目指せ元素記号118番!笑

f:id:nn_hokuson:20180911211802j:plain:w300

【Unityシェーダ】Shader Graph超入門

Unity2018からシェーダをノードベースで作れる「Shader Graph」という機能が提供されています(まだPreviewですが)これまでは、ノードベースでシェーダを開発しようとするとShader Forgeとかの有料アセットを使う必要がありましたが、これからは「Shader Graph」に一本化されそうですね。

f:id:nn_hokuson:20180508212141j:plain:w700

ここでは、2018年5月の段階で、とりあえずShader Graphを触ってみる、というところまで解説したいと思います。目次は次のとおりです。

プロジェクトを作成する

「Shader Graph」はUnity2018以降で使うことができます。ということで、まずはUnity2018をインストールしましょう。

インストールができたら、早速プロジェクトを作ります。「Shader Graph」は現在のところ、Lightweightのプロジェクトでしか使うことができないようです。プロジェクトを作成するときにはTemplateでLightweight RP(Preview)を選択するようにしましょう。

f:id:nn_hokuson:20180508201418p:plain:w500

Shader Graphをインストールする

Unity2018.0f2ではまだShader GraphはPreviewの状態なので、手動でインストールしなければ使うことができません。

ツールバーのWindow→Package Managerを選択して、Allのタブを選択し、「ShaderGraph 1.1.4」をクリック、右ペインで「Install」ボタンを押してください。

f:id:nn_hokuson:20180508201701j:plain:w600

これで、ようやくUnity2018で「Shader Graph」を使うことができるようになりました。

Shaderとマテリアルを作成する

通常のシェーダと同じく、まずはシェーダファイルを作ります。プロジェクトウィンドウで右クリックし、Create→Shader→PBR Graphを選択してください。名前はblendTexとしておきましょう。

f:id:nn_hokuson:20180508202037p:plain:w600

また、このシェーダを適用するマテリアルを作ります。作成したblendTexture.shaderを選択した状態で、右クリック→Create→Materialを選択してください。作成したマテリアルは適当なオブジェクトにアタッチしておきましょう。

f:id:nn_hokuson:20180508202453j:plain:w600

Shader Graphを使ってテクスチャブレンドする

さて、いよいよ「Shader Graph」の出番です。今回は初回なので2枚のテクスチャをブレンドするだけの超簡単なシェーダプログラムにしましょう。

まずはblendeTexをダブルクリックすると、「Shader Graph」のウインドウが立ち上がります。左側にあるのは外部からシェーダへ値を入力できるプロパティウインドウ、真ん中がGUIでシェーダを作る部分、右側が出力結果のウインドウ(やたらでかい)になります。

f:id:nn_hokuson:20180508202840j:plain

ノードを配置する

まずは使用する2枚のテクスチャ読み込むノードを配置しましょう。ウインドウ上で右クリックするとメニューが出てきます。Create Nodeをクリックして、Input→Texture→Sample Texture 2Dを選択してください。配置できたら、左側にあるタグの丸ポチをクリックして、テクスチャを読み込んでください。

f:id:nn_hokuson:20180508203602j:plain:w550

画面上にテクスチャ読み込み用のノードが配置されます。同様の方法で、同じノードをもう一つ追加しましょう(cmd+Dでノードを複製することもできます)追加できたら、こちらもテクスチャを読み込みましょう。

f:id:nn_hokuson:20180508203757j:plain:w550

続いてこの2枚のテクスチャをブレンドするためのノードを配置します。Create Nodeをクリックして、Artistic→Blend→Blendを選択して、Blendノードを配置してください。

f:id:nn_hokuson:20180508203916j:plain:w550

ノードを接続する

これで必要なノードを配置することができました。次はこれらのノードを接続していきましょう。1枚目のSample Texture 2Dノードの出力RGBA(4)からBlendノードのBase(1)へドラッグ&ドロップします。

f:id:nn_hokuson:20180508204254g:plain:w450

同様にして2枚目のSample Texture 2Dノードの出力RGBA(4)からBlendノードのBlend(1)へドラッグ&ドロップします。ノードを接続した結果はこんな感じになります。

f:id:nn_hokuson:20180508204918j:plain:w450

2枚のテクスチャをブレンドする割合はBlendノードのOpacityで設定します。ここではOpacityを0.5に設定して2枚のテクスチャが半分ずつ混ざるようにしておきましょう。

f:id:nn_hokuson:20180508205105j:plain:w300

最後にBlendノードのOut(1)からPBR MasterのAlbedo(3)へドラッグ&ドロップします。これで作成したシェーダの内容が出力結果に反映されるようになります。

f:id:nn_hokuson:20180508205344j:plain:w550

ここまでで、今回の「Shader Graph」の作成は終了です。最後に左上のSave Assetボタンを押して作成したシェーダを保存してください。

f:id:nn_hokuson:20180508205532p:plain:w450

もう少し便利にする

テクスチャのブレンド具合を変更する場合、いちいち値を入力するのは面倒ですね。(実はOpacityの「X」をドラッグすると値を変えられるのですが・・・笑)そんな時のためにSliderというノードが用意されています。

ウインドウ上で右クリックしてCreate Nodeを選択し、Input→Basic→Sliderを選択してください。SliderノードのOut(1)からBlendノードのOpacity(1)にドラッグ&ドロップして、これらのノードを接続してください。

f:id:nn_hokuson:20180508205916g:plain:w200

Sliderノードのスライダーをドラッグ&ドロップすることでブレンド具合を変更することができるようになります。

f:id:nn_hokuson:20180508211354g:plain:w450

インスペクタからシェーダの値を変えられるようにする

「Shader Graph」の中で指定した値をUnityのインスペクタから操作したい場合、値をPropertyに変換する必要があります。ここではSliderノードの値をインスペクタから変更したいので、Sliderノードを選択した状態で右クリックして、Convert to Propertyを選択して下さい。

f:id:nn_hokuson:20180508210711p:plain:w400

再度、ShaderGraphのウインドウ左上のSave Assetをクリックしてから、Unityエディタに戻ってインスペクタを見てみて下さい。Vector1という欄が追加されていると思います。ここの値を変更することで、ブレンド具合を変えることができます。

f:id:nn_hokuson:20180508211854j:plain:w350

結果確認

Unityのウインドウに戻ると、作成したシェーダが反映されていることがわかると思います。このように「Shader Graph」を使うことで、複雑なプログラムを書かなくても簡単にシェーダを作成することができるようになります。

f:id:nn_hokuson:20180508212141j:plain:w700

次回以降、これまでに作成したUnityのシェーダを「Shader Graph」を使って書き直していきたいと思います!その他のUnityシェーダはこちらからご覧になれます。

nn-hokuson.hatenablog.com

【Unity】iOS13で写真やスクショをカメラロールに保存する

Unityでスクリーンショットを撮影するのはとても簡単なのですが、これをiOSのカメラロールに保存するのは案外手間がかかります。ここではその方法を簡単に紹介したいと思います。

スクリーンショットをカメラロールに保存する流れは次のとおりです。

Unityでスクリーンショットを撮影する

Unityで画面のキャプチャするにはScreenCapture.CaptureScreenshotメソッドを使います。(少し前まではApplication.CaptureScreenshotでしたが、機能は同じです)

このCaptureScreenshotメソッドの引数にファイル名を渡すことで、Application.persistentDataPathが指すフォルダにスクショ画像が保存されます。

iOSでApplication.persistentDataPathは、作成中のアプリ内のDocumentフォルダを指しています。なので、カメラロールに保存したい場合には、保存したフォルダからカメラロールに画像をコピーする必要があるわけです。

f:id:nn_hokuson:20180501200226p:plain:w380

スクショをカメラロールにコピーするPluginを作る

ただし、Unity標準のAPIを使って、アプリ内のフォルダからカメラロールに画像を移すことはできません。そこで、上の工程を行うiOS用のPluginを作成する必要があります。

それではPluginを作っていきましょう。Assetフォルダの下にPluginsフォルダを作成し、その下にiOSフォルダを作成してください。そしてiOSの中にScreenShot.mmという名前でファイルを作成します。.mmの拡張子はObjective-C++のファイルを表します。

f:id:nn_hokuson:20180501200456p:plain:w400

作成したScreenShot.mmファイルに次のプログラムを入力してください。

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>

extern "C" void SaveToAlbum (const char* path)
{
    // アルバム名を取得する
    PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
    fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", @"アルバム名"];
    PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:fetchOptions];

    // ファイルパスをURLにする
    NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]];

    // 写真を保存する
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetChangeRequest *assetChangeRequest;
        assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:fetchResult.firstObject];
        [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];

      } completionHandler:^(BOOL success, NSError *error) {
      }];
}
||< 

このプログラムでは引数で受け取ったパスにある画像ファイルを、カメラロールに保存し直しています。カメラロールに保存するにはPHPhotoLibraryクラスを利用します。「アルバム名」の部分はiPhoneに保存されているアルバム名を指定します。<b>デフォルトで用意されている「最近の項目」のアルバムは指定できないようなので、新規にアルバムを作るほうが良い</b>と思います。

このPluginではPhotosをインポートしているので、<b> Photos Frameworkをプロジェクトに追加しておかないとXcodeのリンク時にリンカエラー</b>が出ます。

Photosを追加するにはScreenShot.mmファイルを選択して、インスペクタの「Platform settings→Rarely used frameworks→ Photos」にチェックを入れます。

[f:id:nn_hokuson:20200226221814p:plain:w700]

*Pluginでスクショをアプリ内からカメラロールにコピーする
画像ファイルをカメラロールに保存するPluginが出来たので、UnityからこのPluginを呼び出す部分を作りましょう。ScreenShot.csファイルを作成(別にPluginのファイル名と対応する必要はありません)して、空のGameオブジェクトにアタッチします。

[f:id:nn_hokuson:20180501200805j:plain]

次にScreenShot.csファイルに次のスクリプトを入力してください。

>|cs|
using System.Collections;
using UnityEngine;
using System.IO;
using System.Runtime.InteropServices;

public class ScreenShot : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void SaveToAlbum(string path);

    IEnumerator SaveToCameraroll(string path)
    {
        // ファイルが生成されるまで待つ
        while(true)
        {
            if(File.Exists(path))
                break;            
            yield return null;
        }
        
        SaveToAlbum(path);
    }

    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
#if UNITY_EDITOR
#else
        string filename = "test.png";
        string path = Application.persistentDataPath + "/" + filename;

        // 以前のスクリーンショットを削除する
        File.Delete(path);

        // スクリーンショットを撮影する
        ScreenCapture.CaptureScreenshot(filename);
        
        // カメラロールに保存する
        StartCoroutine(SaveToCameraroll(path));
#endif
    }
}

このプログラムでは、上で紹介したCaptureScreenshotメソッドを使ってスクリーンショットを撮影しています。撮影したパスをPluginのSaveToAlbumメソッドに渡すことで、アプリ内にあるスクリーンショットをカメラロールにコピーしています。

注意点として、CaptureScreenshotはコールしたタイミングで画像を保存するわけではなく非同期に画像を保存します(ヤヤコシイ・・・)従って、画像の保存が完了するまでは、Pluginで画像をコピーするのを待つ必要があります。

これをやっているのがSaveToCamerarollコルーチンです。File.Existsメソッドを使って毎フレームスクショ画像が保存されたかをチェックして、保存されていればPluginを使って画像をカメラロールにコピーします。

Photo Library Additions Usage Descriptionを追加する

iOS11以降では、Photo LibraryにアクセスするためにはInfo.plistに「Privacy - Photo Library Additions Usage Description」を追加する必要があります。

これを設定し忘れると、フォトライブラリにアクセスしようとした時点でアプリがクラッシュします(クラッシュさせなくても、コンパイルエラーで良いと思うのですが・・・)

Unityでビルドしたプロジェクトファイルを開き、Info.plistに「Privacy - Photo Library Additions Usage Description」追加してからXcodeでビルドしましょう。

f:id:nn_hokuson:20180501201158j:plain:w600

これで、Unityで撮影したスクリーンショットを、iOSのカメラロールに保存することができるようになります。

注意点

また、Xcodeからデバッグ中だとカメラロールに正しく保存されずに、実行時エラーになることがあります。その場合は、一度Xcodeのデバッグを停止して、iPhoneのアプリ画面からアプリを起動してみてください。