2014年8月29日金曜日

【Unity、UniRx】クリック回数をトースト表示する


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その6。

やりたいこと

ReactiveExtensionsを使ってクリック回数をトースト表示する。

やったこと

(UniRxはインポート済み)
まずは、クリックするためのSphereを追加(Sphereじゃなくてもいい)
前回のなごりでPlaneを追加(Planeじゃなくてもいい)
トースト表示するためのText追加(せっかくなのでuGUI使いました)
それからC#Scriptを作成してコードを以下のように変更(今回もTestScriptにしました)
そしてTestScriptをSphereにドラッグ&ドロップしたら出来上がり
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;

static class ColorExt
{
  /// 
  /// Textのアルファ値をセットする拡張メソッド
  /// 
  /// uGUIのText
  /// アルファ値
  public static void setA (this UnityEngine.UI.Text text, float a)
  {
    text.color = new Color(text.color.r, text.color.g, text.color.b, a);
  }
}

public class test1script : ObservableMonoBehaviour
{
  /// トースト表示用オブジェクト
  public GameObject Toast;

  /// Scanで匿名クラス使うとなぜかエラーするので、クラス定義
  private class Delta
  {
    public float time{ get; set; }
    public float offset{ get; set; }
    public Delta(float t, float o){ time = t; offset = o; }
  }

  /// 
  /// 指定秒間だけEveryUpdateを発行する
  /// 
  /// 
  /// 秒
  private IObservable TakeSec (double value)
  {
    //0秒〜経過秒が値として発行される
    return Observable.EveryUpdate().Scan(
        new Delta( 0, Time.time)
        , (a, t)=>new Delta( Time.time - a.offset, a.offset)
      ).Select(delta => delta.time)
      .TakeUntil(Observable.Timer(System.TimeSpan.FromSeconds(value)));
  }

  ///  RXのサンプルがAwakeだったので、ここに書きました。 
  public override void Awake ()
  {
    //参考サイト:http://neue.cc/2010/07/28_269.html

    //トースト用オブジェクトからuGUIのTextを取り出して、透明にする
    var text = Toast.GetComponent ();
    text.setA(0);

    //nueuccさんのアドカレ記事をパクりました
    //クリック回数をトースト表示
    OnMouseDownAsObservable ()
      .Buffer (OnMouseDownAsObservable ().Throttle (System.TimeSpan.FromMilliseconds (250)))
      .Select (xs => xs.Count)
      .Do(cnt => text.text = string.Format ("{0} clicks", cnt))
      .SelectMany(cnt => 
        //1秒かけて0→1、また1秒かけて1→0ってなってほしいんだけど、0→1、1→2ってなる。意味不明。
        Observable.Concat(TakeSec(1).Do(t=>text.setA(t)), TakeSec(1).Do(t=>text.setA(2-t)))
      ).Subscribe (t=>Debug.Log(t));

    // If you use ObservableMonoBehaviour, must call base method ← サンプルにこう書いてますので、そのまま。
    base.Awake ();
  }

}

こんな感じ。
Hosted by UnityRoom.com

どうにか思ったとおりの動きになったんだけど、理解できない部分がいくつか。
・Scanのseedを匿名クラスにすると、なぜかCannot implicitly convert type `anonymous type' to `anonymous type'って怒られる
・1秒で終わるObservableをConcatで2つ繋げると、なぜか単体で動かすのと違う動きになる、気がする、、、

追記

neueccさんからアドバイス頂いてScanの理解できない件解決しました。
timeの型がintとfloatになってるだけでした。
seedをnew {time=0f, offset=Time.time}にしたらOKでした。はずかし。

Concatの件もいろいろ試してたら思った感じの動きになりました。
Observable.Concat(TakeSec(1).Do(t=>text.setA(t)), TakeSec(1).Do(t=>text.setA(2-t)))

TakeSec(1).Do(t=>text.setA(t)).Last().SelectMany(_=>TakeSec(1).Do(t=>text.setA(1-t)))
てしたらそれっぽくなりました。全然わからん。



2014年8月22日金曜日

【Unity、uGUI】チュートリアル見ながら触ってみる。01.Canvas

ついにUnity4.6のベータ版が来ましたね。

Unity 4.6オープンβスタート。新GUI「uGUI」の試用が可能に | テラシュールブログ

待ちに待ったuGUIがやっと使えます。

ここにチュートリアルがあるようなのでのんびり見てみようと思います。
UI チュートリアル | Unity 公式

01. UI CANVAS

動画はここ 01. UI CANVAS
実際に動画見ながら試してたらむっちゃ時間かかった

Canvas

キャンバスはUI要素を表示するための重要なコンポーネント
Hierarchy->Create->UI->Canvasで作成可能。
すべてのUI要素はキャンバスの子供にする必要がある

キャンバスは2つ以上配置することもできる

新規UI要素を配置する際、シーンに一つもキャンバスが存在しない場合は自動的に作られる。
こんな感じでいきなりボタンなどを配置するとキャンバスも作られる

RenderMode

Canvasごとに異なるRenderModeを設定できる

Screen Space Overlay : RenderMode

もっとも基本的なRenderModeであり、規定値。
これを選択するとUIはシーン上にオーバーレイ表示され、最前面に描画される。
カメラなしでも表示できる。
このモードの場合、Canvasのサイズは自動的にスクリーンサイズに合うように変更される。
また、スクリーンサイズが変更になる場合も自動的に追従する。
よくあるGUI(操作ボタンとか)はこれで問題なさそうね。

Rect Transform

Canvasを含むすべてのUI要素はこのコンポーネント(RectTransformComponent)を持ってる。
UI要素はこのコンポーネントに基づいて動作する。(らしい、よく理解できんかった)
RenderModeにScreen Space Overlayを選んでいる場合、Canvasのこのコンポーネントの値はすべて自動的に入力される。(画面サイズとかに基づいて)
Rect Transformの詳細についてはこちら

CanvasのRectTransformを変更する必要があるのは後述するWorldSpaceに置いたときだけかな?
Buttonなどの子要素を移動する場合はこのコンポーネントを操作すればいいみたい。

PixelPerfectオプションがある。選択するとUI要素は描画時に一番近いPixelに合うように調整される。より鮮明にUI要素を描画したいときに選択するといい。
NGUIにもPixelPerfectってあったけど正直いつ使うのかわからない。

Screen Space Camera : RenderMode

ScreenSpaceOverlayによく似たRenderMode。
特定のカメラに連動して動作する。
だけどカメラなしでも表示できるっぽい。
(Render Cameraをセットしない場合Overlayと同じ動作なのかな?)


こんな感じでRenderCameraにカメラをセットして使う
Perspectiveカメラとの連動が分かりやすい。
ボタンのRectTransformComponentのRotationYを30度傾けてみた。

ScreenSpaceOverlay(上)とScreenSpaceCamera(下)を並べて
同じように30度傾けてみた。違いがわかりやすい。

もちろん連動したカメラのViewPort設定などが反映される。

カメラとの距離はPlaneDistanceで設定可能
カメラごとのClearFlagsやCallingMask、カメラ深度なども適用される。
カメラについての詳細はこちら

World Space : RenderMode

これを選択するとUI要素はシーン内に他のオブジェクト同様に配置される
これはカメラ必須。
このモードのときはRectTransformを自由に書き換えることができ、Scene内の好きな場所に配置できる

イベントカメラはどのカメラがイベントを受け取るかの設定に必要。
主にクリックイベントの取得とか。
※Receives Events って項目ないな。

キャラクター上にHPバーを表示したりとか、そういうときに使うのかな。

Sorting Layer

よくわからんかった。
描画順を制御できるらしい。
詳細はこちら

描画順

キャンバス内での描画順は上から。
これは直感的でいいね



今日はここまで~。

Unity系記事まとめ

2014年8月21日木曜日

【うに部屋】Unityのゲーム投稿サイトにアセット検索機能を付けてみた

はじめに

みなさんこんにちは、@naichilab(ないち)と申します。
今回の投稿は「Unity アセット真夏のアドベントカレンダー 2014 Summer!」の記事になります。
昨日はLekさんの「スマフォで本当にオープンワールド」でした。すんごいですね!

本日の記事は
【うに部屋】Unityのゲーム投稿サイトにアセット検索機能を付けてみた
ということで、私が管理しているUnityのゲーム投稿サイトを紹介させていただきたいと思います。

※結果的にかなり露骨な宣伝になってしまいました…ごめんなさい!

Unityでゲームを作って投稿しよう

うに部屋 - UnityRoom
現在136本のゲームが公開されています。
うに部屋」というUnityWebPlayerのゲーム投稿サイトを作りました。
おかげさまで投稿されたアプリケーションも100本を超えました!
100MBまでのアプリが投稿できます。公開先に迷った際はぜひご利用ください。

うに部屋の目的

Unityは初心者向けの本が多く、無料で始めることができるので新しいユーザーさんがすごい勢いで増えていますね!
そんな方たちに気軽に作品を公開できる場所を提供しようとサイトを立ち上げました。

みんなでゲームを楽しみたい」のはもちろんですが、
純粋なゲーム公開サイトは星の数ほどあるのでちょっと方向性を変えて
投稿者自身にメリットがあり楽しめるサイト」を目指しています。

各開発者さんにとって
  • 少なからず宣伝になったり
  • モチベーション維持に役立てたり
  • 他の開発者と繋がることができたり
といったメリットを提供できたら嬉しいですね。

【新機能】アセットを探す(β版)

さて、そんな「うに部屋」ですが
つい先日「アセットを探す」という機能をリリースしました。
まだ機能が不足してるので少しずつ作っていきます
ゲームに使われているアセットの詳細みたり、
使われているアセットからゲームを探したりできます。

  現在登録されているアセットは→こちら

アセット開発者さんであれば、デモの公開場所としても利用いただけますね!
いくつかアセットを販売されている@LycoRadiさんにはこんな形で利用いただいています。
販売中のアセットを使ったデモアプリを公開
ちょっと現時点では登録が面倒だったり、閲覧できる情報が少なかったりでイマイチなのでそのあたりは少しずつ改善していきます。AssetStoreへの導線が無いとか致命的…ゴメンナサイ

おわりに

うに部屋は特にUnityを始めたばかりの初心者さんに使っていただきたいサイトです。
アップロード場所に困った際はぜひ使ってみてください!


明日は@neueccさんの「A Beginners Guide to Reactive Extensions with UniRx」です。
個人的にめちゃめちゃ楽しみです!ではよろしくおねがいします。

2014年8月18日月曜日

【google+】google+(picasa)に15分を超える動画をアップロードしても、保存容量にカウントされない

@Baiteen

前から使用容量の表示がおかしいなぁとは思ってたんだけど、間違いじゃなかったみたい。

Picasaの保存容量の上限を確認するのページには
容量にカウントされるアイテム
  • Gmail: メール内のすべてのメッセージと添付ファイル([スパム] や [ゴミ箱] フォルダ内のアイテムも含む)。
  • ドライブ: ドライブに保存しているファイル(PDF、画像、動画など)。Google ドキュメント、スプレッドシート、スライドで作成したアイテムは、保存容量にカウントされません。
  • Google+ フォト: 2048x2048 ピクセルを超える写真と15分を超える動画のみが、保存容量にカウントされます。
ってなってるんだけど、Google+ フォトに15分を超える動画をアップロードしても容量にカウントされませんでした。

やり方

1.まずはgoogle+にログイン

2.google+のホーム画面にある”最近の出来事を共有しましょう”の「動画」をクリック

3.「動画をアップロード」をクリックして、ドラッグドロップかファイル選択

4.アップロードが終わったら「動画を追加」をクリック

5.共有画面が開くので、”ユーザーを追加”のとこにログインアカウントのメールアドレスを入力し「共有」をクリック

6.google+の設定画面で使用容量を確認すると、0GBのまま

PICASAウェブアルバムでも確認してみる

7.追加したアルバムのページを開くと右側にアルバムの容量が表示されてる(14817 MB)

8.PICASAウェブアルバムの設定画面で使用容量を確認しても、0GBのまま


具体的にどんな条件でこうなるのかは分からないが、とりあえず約15GBの動画をアップロードしても使用容量が0GBのままになってる。
PCの容量を気にせず、動画が取り放題だね。


2014年8月3日日曜日

【Unity、UniRx】REST APIにスコアをPOSTする


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その5。

やりたいこと

ReactiveExtensionsを使ってREST APIにスコアをPOSTする。
サーバー立ててAPI用意するのは面倒くさいので、アカウントがあるParse.comで試してみることにする。

やったこと

(UniRxはインポート済み)
1.
Parse.comにログインしてアプリ作ってスコア保存用のクラスを用意。(playerとscoreフィールドも追加)

詳しい方法は割愛。(元気が足りず諦めました)

2.
Parse.comのREST APIの仕様を確認。(見るだけ)
まずはRequestFormatを確認。ここ

なるほど。
Content-Typeをapplication/jsonにして、X-Parse-Application-IdとX-Parse-REST-API-Keyを指定すればいいのね。
IdとKeyはアプリケーションの設定画面にありました。


それからデータの登録方法を確認。ここ

なるほど。
URLで登録するクラス指定して、ポストデータで登録したいデータをjsonで渡せばいいのね。

3.
MiniJSONを使えるようにする。
JSONデータを渡すということなので、オブジェクトをJSON文字列にしてくれるMiniJSONを使うことにしました。
https://gist.github.com/darktable/1411710からMiniJSON.csをダウンロード。
UnityのAssetsフォルダ内にPluginsフォルダを作ってそこにドラッグドロップ。
これで使えるようになったはず。

4.
Unityでスクリプト書いてみる。
スコア登録用のScoringクラスを用意して、マウスダウンで登録実行するのをイメージ。
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;
using MiniJSON;

public class TestScript : ObservableMonoBehaviour
{
 /// スコアを登録してくれるクラス
  public class Scoring
  {
  /// プレイヤー名
    private string Player { get; set; }
  /// REST APIのURL
    private string ApiUrl { get { return "https://api.parse.com/1/classes/Ranking"; } }
  /// リクエストに必要なheader
    private Hashtable Headers {
      get { 
        var headers = new Hashtable ();
        headers ["X-Parse-Application-Id"] = "******";//自分のアプリのIDを入れてね
        headers ["X-Parse-REST-API-Key"] = "******";//自分のアプリのKeyを入れてね
        headers ["Content-Type"] = "application/json";
        return headers;
      }
    }

  /// コンストラクタでプレイヤー名設定
    public Scoring (string player)
    {
      this.Player = player;
    }

  /// スコア登録Observable(3回リトライしてみる)レスポンス文字列をそのまま発行
    public IObservable PushScore (int score)
    {
      var form = new WWWForm();
      form.AddField("player", this.Player);
      form.AddField("score", score);

      return ObservableWWW.Post(this.ApiUrl, form, this.Headers).Retry(3);
    }
  }

  ///  RXのサンプルがAwakeだったので、ここに書きました。 
  public override void Awake ()
  {
    //参考サイト:http://neue.cc/2010/07/28_269.html

  //マウスダウンでスコア登録
    OnMouseDownAsObservable()
      .SelectMany(_ => new Scoring("baiteen").PushScore(100))
   .Subscribe (result => {
        Debug.Log ("finish");
      });

    // If you use ObservableMonoBehaviour, must call base method ← サンプルにこう書いてますので、そのまま。
    base.Awake ();
  }
}
ん?何やらエラー発生してる。
ArgumentException: Key duplication when adding: Content-Type
調べてみると"application/x-www-form-urlencoded"か"multipart/form-data"が最初から設定されてるらしい。
消そうと思ったけど消せない。

もうちょっと調べてみたら
WWWクラスでは、WWWFormじゃなくてbyte[]でポストデータを指定できるみたい。

なぜObservableWWW.Postにはbyte[]が渡せないんだー!!

ってことでbyte[]渡せるようにオーバーロード追加してやってみた。

■追加したコード(UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs)
        public static IObservable Post(string url, byte[] content, Hash headers, IProgress progress = null)
        {
            return Observable.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, content, headers), observer, progress, cancellation));
        }

んで、スクリプトのPushScoreを以下に修正(bloggerに貼るとobjectがobject=""になっちゃう)
  /// スコア登録Observable(3回リトライしてみる)レスポンス文字列をそのまま発行
    public IObservable PushScore (int score)
    {
      var dic = new Dictionary ();
      dic.Add ("player", this.Player);
      dic.Add ("score", score);
      byte[] data = System.Text.Encoding.UTF8.GetBytes (Json.Serialize (dic));

      return ObservableWWW.Post(this.ApiUrl, data, this.Headers).Retry(3);
    }
お、今度はエラー出ない。

5.
Parse.comのDataBrowserで確認。

すばらしい。ちゃんとデータ登録されてる。

例外処理とかは置いといて、とりあえずUniRxでPOSTできることが確認できたので良かった。
良かった。



Related Posts Plugin for WordPress, Blogger...