ハルスター・アクション(beta)

2014年~2015年にかけて作っていたゲームです。
Unity で作りました。イラストは友達が作りました。

ルール

マリオのようなアクションゲームです。
ステージにあるぶどうを集めたりしながら、ゴールを目指します。

操作方法

  • ←・→ : 移動
  • SPACE : ジャンプ
    ゲームを進めると、そのほかのアクションができるようになります。

ダウンロード

クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 – 非営利 – 改変禁止 4.0 国際 ライセンスの下に提供されています。

ダウンロード
上のリンクを開き、右上のダウンロードボタンからダウンロードしてください(Zip形式)
解凍し、 game.exe を開くと、ゲームが起動します。

※このゲームはかなりの鬼畜ゲームだそうです。
 製作者によりクリアできることは確認されておりますが(W0を除く)、
 難しいそうです。がんばってください!!

※このゲームは beta 版です。ステージに不具合がある場合があります。
 また、現在 Unity でなく、別のフレームワークでの開発を試しています。
 更新はそちらで行うかもしれません。

工夫したところ

ステージのシーン

ステージ(W1-1、W1-2)ごとにシーンを作るのではなく、
ステージの状態を CSV で保存し、それを利用するようにしました。

UnityのSceneManagerで、シーンが存在するか確認する

Unity 5.3 から追加された、Multi Scene Editingで、
シーンを追加する時、
同じシーンを何個も追加したくない!ってこと、ありますよね。

「SceneManager.Contains()」的なメソッドがあれば最高なのですが、
アクティブなシーンしか
取れなかったりとかするんですよねー(GetActiveScene 関数)。

そこで、次のようにしました。
しかし、Unity 5.3.1 くらいではOKだったのですが、
5.3.2にしたら非推奨になっちゃってw・・

using UnityEngine.SceneManagement;
using System.Linq;

void LoadMyScene()
{
    // MyScene1 というシーンが存在しなければ
    if (SceneManager.GetAllScenes().Count((scene) => scene.name == "MyScene1") == 0)
    {
        SceneManager.LoadScene("MyScene1", LoadSceneMode.Additive);
    }
}

Linqで、すべてのシーンの中から、指定された名前のシーンが 1 以上の場合は存在するとしました。
しかし、すべてのシーンを取得する、「GetAllScenes 関数」が非推奨になってしまいました。
1行で書けるのがよかったのでしたが、しょうがない。for文をつかって地道にやろう。

using UnityEngine.SceneManagement;

void LoadMyScene()
{
    if (!ContainsScene("MyScene1"))
    {
        SceneManager.LoadScene("MyScene1", LoadSceneMode.Additive);
    }
}

bool ContainsScene(string sceneName)
{
    for (int i = 0; i < SceneManager.sceneCount; i++)
    {
        if (SceneManager.GetSceneAt(i).name == sceneName)
        {
            return true;
        }
    }
    return false;
}

「using UnityEngine.SceneManagement」を追加するのを忘れずに。
これでハマったこともあります。

もっといい方法ないんですかねー・・。

【感動】UnityでC# 6.0 が使えた!!

追記:朗報
Unity 2017 からは、デフォルトで C# 6.0 および .NET 4.6 が使用可能なようです!

C#6.0時代のUnity - Qiita
## はじめにUnity2017のベータが公開されましたね!(これを書いている4月13日現在 Unity 2017.1.0b1 https://unity3d.com/jp/unity/beta#downloads)なんといっても...

この記事では Unity 5 での場合を紹介しています。

こんにちはー!!

Unityでも、最新の C# 6.0 を使って、
async、await とかカッコよくコードを書きたいんだ ლ(´ڡ`ლ)

そんなことできないかなーと思って、調べてみました。

そしたら、なんと、ありました!!ので紹介します。

1. リポジトリをダウンロード

C# 6.0関係のいろいろが入ったリポジトリをBitbucketからダウンロードします。

https://bitbucket.org/alexzzzz/unity-c-5.0-and-6.0-integration/downloads

ダウンロードしたファイルは、Zip形式で圧縮されているので、展開します。

2. プロジェクトにインポート

Unityのプロジェクトのフォルダーを開き、
「CSharp60Support」をコピーします。

unity-cs6-copy

CSharp60Support内の、「CSharp60Support for Unity 5.unitypackage」
(Unity 4だったらUnity 4の方)を開き、
プロジェクトにインポートします。
import-cs6-unity

unity-cs6-many-errs
大量にエラーが出ますが、気にせず、
「CSharp60Support」ディレクトリを右クリックし、「Reimport All」をクリック。
unity-cs6-reimport
ダイアログが出てくるので、「Reimport」を選択すると、Unityが再起動し、エラーがすべて消えます。

3. 試す

新しいスクリプトを適当に作って、C# 6.0を試してみましょう。
試す機能は、String interpolationです。


// 略

void Start()
{
    string s1 = "world";
    string s2 = $"Hello, {s1}";
    Debug.Log(s2);
}

// 略

新しく空のゲームオブジェクト(Hierarchy右クリック「Create Empty」とか)を作成し、
作ったスクリプトをアタッチしましょう。

実行すると・・・・!
unity-cs6-success

できました~~!!

4. Visual Studio、MonoBehaviourでエラーが出るときは

Unityではエラーが出なくても、
「◯◯という機能はC# 6.0で使えて、C# 4では使えないよー」的なエラーが、
Visual Studio、MonoBehaviour側で出るときは、IDEを再起動しましょう。

まとめ

これでのびのびとUnityが使える!

自分的には、C# 6.0で一番便利な機能は、↑の、$"{変数}"で、string.Formatっぽいのが使える機能です(名前忘れた -> 追記: String interpolation らしい)
これが使えるのは本当に嬉しい!

(え、async 、await 使ってみないの)→試してみます!

UnityのLoadSceneAsyncでの非同期処理

こんにちはー!!

Unity 5.3 から、Multi Scene Editing が追加されましたね。

そこで、シーンを読み込んでから、GameObject.Find をする、
次のようなコードを動かしたのですが、うまくいきません。

TestGameObject は、追加するシーン Scene2 に入っているものとします。

void LoadScene2()
{
    SceneManager.LoadScene("Scene2", LoadSceneMode.Additive);
    Debug.Log(GameObject.Find("TestGameObject"));
}

実行してみると、Null が返ってきます。

unity-loadsceneasync-ok

なぜ?

これは、Scene2 が読み込まれるまで待たないで、
GameObject.Find を呼び出してしまっているからです!

LoadSceneAsync を使おう!

お、LoadSceneAsync とかいう、それらしい名前のがあるではないか。
そこで、LoadSceneAsync を使おうとしましたが、ハマりました。
C# の、async / await でするものだと間違えていて、
あれ?Unityの C# のバージョンじゃ、async とか使えなくねー・・

(使う方法もあります)

【感動】UnityでC# 6.0 が使えた!!
追記:朗報Unity 2017 からは、デフォルトで C# 6.0 および .NET 4.6 が使用可能なようです!この記事では Unity 5 での場合を紹介しています。こんにちはー!!Unityで...

しかし、LoadSceneAsync の戻り値は、「UnityEngine.AsyncOperation」でした・・。
アシンクオペレーションってなんだっけ?(検索中)
そう、コルーチンを使うんだ。(`・ω・´)ゞ

void LoadScene2()
{
    StartCoroutine("LoadScene2Coroutine");
}
IEnumerator LoadScene2Coroutine()
{
    yield return SceneManager.LoadSceneAsync("Scene2", LoadSceneMode.Additive);
    Debug.Log(GameObject.Find("TestGameObject"));
}

unity-loadscene-null

これでシーンが読み込まれるまで待機してくれるようになりました。

Unityで、コンポーネント内のフィールドを文字列から動的に変更する

こんにちはー!!

Json からUnity2dのステージのデータを取ろうとしています。
その時、コンポーネントの値を変えたいと思い、この方法をやりました。
Reflectionを使ったりして、結構複雑でした。

ReflectionTest コンポーネントの内容は次のようにします。

これを、GameObject1 にアタッチすればできます。

安全性は・・

しかし、コンポーネント内すべてのフィールドにアクセスできるのは
ちょっとセキュリティが・・・なので、
特定の属性(ここではPermitReflection)がついたフィールドのみにアクセスできるようにします。

Reflectionに使ったしたコード(2つ上のコード)を、次のように編集します。

    Type componentType = Type.GetType(componentType);
    Attribute fieldAttribute = Attribute.GetCustomAttribute(componentType.GetField(fieldName), typeof(PermitReflectionAttribute));
    if (fieldAttribute != null)  // 属性が存在する場合のみ
    {
        Component targetComponent = GameObject.Find(gameObjectName).GetComponent(componentName);
        Type fieldType = componentType.InvokeMember(fieldName, BindingFlags.GetField, null, targetComponent, null).GetType();
        object parameter;
        // 汎用性を重視して、型がどんな場合でもstringからParseできるように
        if (fieldType == typeof(string))
        {
            parameter = fieldVal;
        }
        else if (fieldType == typeof(int))
        {
            parameter = int.Parse(fieldVal);
        }
        componentType.InvokeMember(fieldName, BindingFlags.SetField, null, targetComponent, new object[] { parameter });
    }
}

// 属性を追加
[AttributeUsage(AttributeTargets.Field)]
public class PermitReflectionAttribute : Attribute
{
}

ReflectionTest コンポーネントは次のように変更します。

PermitReflectionAttributeですが、属性として指定する場合は、
Attributeを抜いて、PermitReflectionとします。

Unityで二次元配列のJsonを読む

こんばんはー。

Unityのステージ内容を Yaml で作ろうと思っていました。

UnityでYAMLをパースする
※ UnityYamlMerge のことではありません!Unity で、2D ステージの内容を YAML で作って、それをパースする方法です。yaml-net を入れるhttp://sourceforge.net/project...

しかし、よく考えてみれば、Unity 公式でサポート(5.3から)されている、
Json で十分じゃね?と思いました。
ステージの内容は、次のようなJsonにしました。

{
  "version": 1,
  "stage": [
    ["block1", 2, 4],
    ["block1", 4, 4]
  ]
}

しかし、JsonUtilityでParseしても、うまくやってくれませんでした。

■配列のネストは1つまで

多次元配列、配列内配列(ジャグ配列)、配列のコレクションなどは、JSONにシリアライズしてくれない。
多次元配列(int[,] とか)は、.NET標準のシリアライザも対応してないので仕方ない。
しかし int[][] や List<int[]> 、 List<List>なども、JsonUtilityは華麗にスルーする。

http://ch.nicovideo.jp/ntmi/blomaga/ar927398より)
とのことです。

というわけで、LitJSON というライブラリを使うことにしました。

ダウンロード

http://lbv.github.io/litjson/から、
Download で dll をダウンロードすると楽。
litjson-download-dll

ダウンロードした dll を、Plugins/ ディレクトリにドラッグ&ドロップ。
Drag-litjson-Unity

次のように書く。

using LitJson;

// 省略

void MakeStageJson(string data)
{
    JsonData jsonData = JsonMapper.ToObject(data);
    Debug.Log((string)jsonData["stage"][0]);
}

実行結果:
unity-debuglog-litjson

このように、jsonData["stage"][0] と、ただインデックス(?)をたどるだけで、
二次元配列も使えます!

LitJSON便利です!

UnityでYAMLをパースする

※ UnityYamlMerge のことではありません!

Unity で、2D ステージの内容を YAML で作って、
それをパースする方法です。

yaml-net を入れる

http://sourceforge.net/projects/yaml-net-parser/files/から、
フォルダーをたどっていくと、snapshot.zip があるので、ダウンロードし、展開してください。

Code ディレクトリ内にある、「Yaml.dll」を、Unityの Assets/Plugins に突っ込みます。
yaml-dllunity-plugins-folder-yamldll-import

スクリプトを追加

新しいスクリプトを作成し、次のように書きます。

using Yaml;

// 省略

void Start () {
    Node yamlNode = Node.Parse("- item1\n- item2");
    Debug.Log(yamlNode);
}
  • Yaml 名前空間が見つからない? Plugins/ ディレクトリに Yaml は入っていますか?
  • Node クラスは、Yaml.Node です。

これで、パースができました。
このスクリプトを、シーン内の空のオブジェクトにアタッチして、実行してみましょう。

yaml-unity-parse

成功です!

yaml-net の詳細情報は、公式サイトを参照してください!

SceneManager.Unloadを、OnTriggerEnter時に呼ぶと凍る

こんにちは。
昨夜、Unityがフリーズしてしまって、結構大変でした。

Unity 5.3.1です。

次のように実行すると、フリーズしました。

void OnTriggerEnter2D(Collider2D col2d)
{
    if (col2d.tag == "Player")
    {
        SceneManager.UnloadScene("MainMenu");
    }
}

なぜか、

  • SceneManager.LoadSceneではフリーズせず、
  • FixedUpdateUpdateのタイミングでやってもフリーズしない

です。

というわけで、次のようにしたら直りました。

続きを読む →

RectTransformのoffsetMinとoffsetMaxについて

こんにちは。

Unity 4.6で、新しいUI Systemとして、
「uGUI」が追加されました(結構前だけど)。

New UI System: Design UIs for your game or application using Unity’s powerful new component based UI framework and visual tools.

そのUIの座標の指定なのですが、
Rect Transformというものを使っていて、
結構複雑です。

ここでは、座標・サイズの指定ができるプロパティ、
「offsetMin」「offsetMax」について調べたので、紹介します。

続きを読む →