2013年6月30日日曜日

【Unity,NGUI2.x】【お勉強】NGUI Basic Tutorialを見た

NGUI

[追記2013/11/01]
こちらの記事はNGUI2.xを扱ってます。
最新の3.0のチュートリアル動画を見たときに書いた記事はこちら。
http://naichilab.blogspot.jp/2013/11/unityngui30.html

Unityでなんか作りたいけどUnityに関する知識が乏しすぎるので勉強中。
先日半額セールで買ったNGUIもほったらかしなのでそれから調べてます。

覚えたことメモしとこうと思う。

NGUI Basic Tutorial

見た動画はこれ。
20分ちょいの動画だけど実際に操作しながら進めたら1時間半かかった…
NGUIってUnityを使うためのGUIかと思ってたけど
GUIを作るためのGUIなのかな?いまだによくわからんw

動画を見て覚えたこと

  • NGUIのインポート方法(00:20~)
    ・動画はExamples抜きでインポートしてる
  • サンプルリソース(GUI用の画像)のダウンロードとインポート(00:50~)
    http://www.tasharen.com/ngui/atlas.zip
    ・Textureフォルダを作って管理
  • NGUI->Create a Textureでテクスチャの追加(01:20~)
  • テクスチャのサイズ変更、移動、回転
    ・回転軸(Pivot)の利用方法
    ・Shift+回転で自由回転(既定は15度刻み)
  • テクスチャの色変更方法(02:20~)
    ・シェーダはTransparent Colored
    ・モバイルならPremultipled Coloredの方がパフォーマンスがいいらしい
    ・色のコピーとペースト
  • テクスチャの表示順(Depth)(03:45~)
    ・動画では同じマテリアルの場合Depthではダメだと言っているけど
    ・自分の環境は行けた。修正されたのかな。
  • NGUI->Open the Atlas MakerでAtlasの作成(04:30~)
    ・画像の追加、削除、修正も簡単
  • NGUI->Create a Spriteでスプライトの作成(06:45~)
  • スプライト表示タイプの変更(07:10~)
    ・Simple
    ・Sliced
    ・Tiled
    ・Filled
    Filledとか面白い
  • スプライト拡大時のエッジボケの対応(07:50~)
    9Sliceスプライト
  • NGUI->Create a Labelでラベル作成(09:00~)
  • BMFontでビットマップフォントを作成し取り込み(09:05~)
  • NGUI->Open the Font MakerでAtlasにフォント追加(11:00~)
  • ラベルでフォント選択、色の変更(11:30~)
  • テキストの変更方法
  • テキストの一部を画像に置き換える方法(11:45~)
    これすごいな
ここまでが基本の使い方?
こんなことしなくても簡単に作れるよってのがここからな気がする。
  • NGUI->Open the Widget Wizard
  • Buttonテンプレート
    既定でエフェクトついてる
    色の変更
    エフェクトの変更などなど
  • Sliderテンプレート
    画像の変更
    BackGroundとForeGroundとか
    Thumbとか
  • Checkboxテンプレート
    複数チェックボックスのグループ化(ラジオボタン的な動作)
  • PopupLitテンプレート
    リサイズしたときのクリック判定範囲の変更は
    NGUI->Attach a Colliderで簡単に反映可能
  • 違うマテリアルの描画はDepthじゃなくてZOrder変更してね(21:00~)


2013年6月23日日曜日

6/22 大阪 Unityクリエイターズ勉強会に行ってきました。


6/22に大阪で開催された「Unityクリエイターズ勉強会」に行ってきました。
聞いた内容を忘れないうちにメモ。
うろ覚えの内容多いです。間違ってたらスイマセン。

タイムテーブルなどATNDはこちら

発表内容

BlenderとUnityのいろいろ(仮) 松田さん 14:00~

終始ワケワカウッヒャーでしたがデモを見て純粋にすごい!って思えました。
Blenderを知るきっかけを頂けたことに感謝。

Blenderって

  • 3DCGやアニメーション作成ソフト
  • オープンソースのフリーソフト
  • 3DCG作成ソフトは数あれどフリーなのはBlenderだけ

BlenderとUnityは親和性 大

  • Blenderで作った.blenderという拡張子のファイルをUnityでそのまま見ることができる
  • Unityプロジェクトのアセットフォルダ内にBlenderプロジェクトを作り始めると楽
  • でも最新のBlender使うと自動インポート機能に不具合あり
  • 現時点ではまだBlender2.66aをオススメ

Unityのアニメーションの仕組み

  • Unityは4.0でアニメーションの仕組みが変わった
  • 新アニメーションのことをメカニムと呼ぶ
  • Unity4.xでは旧アニメーションを使わない方がいいとはっきり書かれている

スカルプト

  • Blenderの機能の一つ
  • マウスで粘土のようなものを積んだり削ったりして3DCDを描く機能
  • 10時間ほどで作ったという50万ポリゴンのトカゲを見せていただきました。

ポリゴン

  • スカルプトでどんどん作りこむとポリゴンが増える=重たい
  • ポリゴンを減らすことで軽くする
  • プレゼンでは50万→10万→1000まで減らして変化を表示
  • ポリゴンが減るほどのっぺりツヤツヤした感じになる
  • モバイルでも1000ポリゴンぐらいなら問題なく動くらしい

ノーマルマップ

  • ポリゴンが多い状態からテクスチャを作る(これがノーマルマップ?)
  • ポリゴンを減らして動作を軽くする→見た目がのっぺりする
  • のっぺりしたものにノーマルマップを貼り付ける
  • →動作軽くて見た目もいい。バンザイ。
  • UnityだとMaterial->Shader->Bumped SpecularにNormalmapという項目がある。
  • Mobole->Bumped Specularの方が軽い(かもしれない)とかなんとか

  • よりリアルに見せるために影をつける
  • 影の付け方も色々
  • モバイルだとリアルタイムにつけるのは厳しい
  • ノーマルマップに影をつけておくのが簡単?
  • AO(Ambient Occlusion)でへこんだ部分に影を付ける?
  • AOはローポリで描けるの方が綺麗だとか
  • BlenderでローポリにAO!ってのは聞き取れた。あとワケワカウッヒャー

クロスシミュレーター

  • Blenderで物の動きをシミュレーションできる?
  • 箱の上に布が落ちる動きを実演
  • 箱にコリジョン、布にクロスって設定してベイク→再生
  • ベイクっていうのが一定時間ごとの動きを計算する操作らしい
  • これで作ったアニメーションをUnityに取り込み?してたけどついてけなかった。

Unity freeについて色々 高橋さん 14:50~

Unityの中の人、黄本の著者さん。
動画マニュアルに日本語解説がついてると聞いて驚きました。少しずつ見ていこう。
勉強方法やPro,Freeの違いなどとても分かりやすかった!

Unity freeって?

  • UnityiOS/Android無料になりましたよー
  • iOS developer(年8400円)払ってなくてもエミュならすぐ試せますよー
  • 簡単ですよー
  • AndroidもSDKとかめんどいけどできますよー
  • 今後のモバイルプラットフォームも無料で提供予定ですよー

Unityの勉強方法

  • Unity公式Web->Learn->Tutorialsに大量の動画マニュアルがある
    http://unity3d.com/learn/tutorials/modules
    各動画再生中にコメント機能をオンにすると日本語字幕が表示できる
    ↑公式Webが日本語表示だとLearnが表示されないようですね。
  • Unityアセットストアからプロジェクトをダウンロードして参考にする
    Unity->Window->Asset Storeでアセットストア起動
    さらにCategories->Complete Projects->Tutorials

ProとFreeの違い

Unity freeに向いているジャンル

  • 2Dゲーム
  • デバイス系一発ネタ(カメラ、マイク、ジャイロ、GPS、etc...)
  • 買い切りタイプの昔ながらのゲーム(追加コンテンツのないものって意味)

Unity freeに向いていないジャンル

  • DLC(ダウンロードコンテンツ)
    追加ダウンロード系はProじゃないとできない
  • 容量の極端に大きなアプリ
    appleStoreは50MBまで。それ以上は追加ダウンロードとなるため
  • 見た目にすごいこだわってるアプリ
    Proじゃないと使えないエフェクトとかがあるため

Unityはどうやって勉強したらいいの? 荒川さん 16:00~

チキンウォーズの作者さん
自身がされてきた勉強法をもとに、とても分かりやすくまとめてみえました。
Unityの勉強はソフトバンククリエイティブの本がいいらしい。

Unity本の紹介

  • Unity本はいくつも出てる
  • Unity本にハズレはほとんどない
  • まずは一冊読んでみて

チュートリアルで勉強する

  • アセットストアにサンプルは落ちてる
  • 「C# Game Examples」 free
  • 「Crusher Baloons」 $25.0
  • 「Match-3 Starter Kit」 $45.0
  • などなど

プログラムを書かずに遊んで覚える

  • Unityにはプログラムを書かなくても使える機能がたくさん
  • CharacterController
  • Terrain
  • Particle(Shuriken)
  • Mecanim

説明サイトとか

まとめ

  1. まずは1冊読もう
  2. 実際になんか作ろう
  3. 外部勉強会やGameJamで仲間を作ろう

LT(Lightning Talk) 16:50~

  • Takarabako18さん
    卒研で作ったアプリの紹介
    ボードゲームを2D、3D等どのように見せるかを試したらしい。
    モデリングも自前らしい。すごい。
  • Ligha(ライハ)さん
    個人で作っている3Dロボットゲームの紹介
    跳んだり撃ったり撃たれたり。こちらもすごい。
  • moririringさん
    C#の便利機能、LINQについて。
    LINQを使えば10行弱のループを1行にできることを紹介。
    C#を肴に4時間は軽く呑めるらしい。
    自分もLINQ大好きです。
  • 暇人さん
    Unity+VuforiaでARカメラソフトを作る手順を紹介
    コーディングゼロ!すごすぎ!
    手順の載った資料はこちら


勉強法とかとても為になった。
自分の中にうっすらと進め方の指針が出来たかな。
マイペースにやっていこう。

発表された方、運営の方々、参加者の皆さんお疲れ様でした!!

2013年6月21日金曜日

【Unity】タッチ操作で特定のオブジェクトを中心にカメラを回す

タッチでグリグリしたい。その2 (その1はこちら)
特定のオブジェクトを中心にカメラを旋回させたい。

↓こんな感じ。
  • 左右に指を動かすとカメラが左右に旋回
  • 上下に指を動かすとカメラが上下に移動

方法

カメラと親子関係になるオブジェクトを用意することで実現できました。

まずはオブジェクトを準備
  • CameraAxis(空のGameObject)
    座標(0,5,0)
  • カメラをCameraAxisの子供に設定
    座標(0,5,-20)
  • 適当なCube
    カメラの旋回が分かりやすいように置いただけ
こんな感じ
CameraAxisスクリプトの追加
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class CameraAxis : MonoBehaviour
{
    public float RotateSpeed = 0.1f;
    public float UpDownSpeed = 0.01f;

    void Update()
    {
        int touchCount = Input.touches
             .Count(t => t.phase != TouchPhase.Ended && t.phase != TouchPhase.Canceled);
        if (touchCount == 1)
        {
            Touch t = Input.touches.First();
            switch (t.phase)
            {
                case TouchPhase.Moved:

                    //移動量
                    float xDelta = t.deltaPosition.x * RotateSpeed;
                    float yDelta = t.deltaPosition.y * UpDownSpeed;

                    //左右回転
                    this.transform.Rotate(0, xDelta, 0, Space.World);
                    //上下移動
                    this.transform.position += new Vector3(0, -yDelta, 0);

                    break;
            }
        }
    }
}
スクリプト説明…は要らないかな
カメラの親となるCameraAxisオブジェクトを回転・上下移動するだけです。

スクリプトの適用

  • CameraAxisオブジェクトにCameraAxisスクリプトを適用
ドラッグ&ドロップ

実行

見まわせるようになった
いい感じー。




2013年6月19日水曜日

【Unity】タッチ操作でオブジェクトをグリグリ回す

タッチでグリグリしたい。

方法

まずはオブジェクトを準備
  • グリグリする対象となるCube配置
  • Script(TouchController.cs)作成
  • Scriptを適用する空のGameObject(TouchController)作成
構成
スクリプトの中身

using UnityEngine;
using System.Collections;
using System.Linq;

public class TouchController : MonoBehaviour
{

    /// <summary>回転対象</summary>
    public GameObject Cube;
    /// <summary>回転速度</summary>
    public float Speed = 0.01f;

    void Update()
    {
        //タッチ数取得(Linq使えた)
        int touchCount = Input.touches
            .Count(t => t.phase != TouchPhase.Ended && t.phase != TouchPhase.Canceled);

        if (touchCount == 1)
        {
            Touch t = Input.touches.First();
            switch (t.phase)
            {
                case TouchPhase.Moved:

                    //移動量に応じて角度計算
                    float xAngle = t.deltaPosition.y * Speed * 10;
                    float yAngle = -t.deltaPosition.x * Speed * 10;
                    float zAngle = 0;

                    //回転
                    Cube.transform.Rotate(xAngle, yAngle, zAngle, Space.World);

                    break;
            }

        }
    }
}
簡単なスクリプト説明
  • タッチされた内容はInput.touchesに入る(マルチタッチ対応)
  • EndedとCanceledを除いたタッチ数を取得(めんどうなのでLinq使いました)
  • シングルタッチの場合、移動量計算して回転
実行する前に忘れず
  • TouchControllerオブジェクトへスクリプト適用
  • TouchControllerコンポーネントに回転対象Cube適用
いつも忘れる

実行

グリグリできた

簡単だなー。Unityすごい。

おわり。

タッチについて詳細は↓


Unity系記事まとめ

【Unity】スクリプトから動的にPrefabのインスタンスを生成

プレハブのインスタンスを動的に作る方法を調べた。

方法

using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour {

    public GameObject BlockPrefab;

 void Start () {
            Instantiate(this.BlockPrefab, new Vector3(0, 5, 0), Quaternion.identity);
 }

}

  • Instantiateで動的に生成できる。
  • 引数1:コピー元
  • 引数2:座標
  • 引数3:回転

遊んでみた

using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour
{
    /// <summary>
    /// ブロックプレハブ
    /// </summary>
    public GameObject BlockPrefab;

    /// <summary>
    /// 最下面中心ブロックの底面中心座標
    /// </summary>
    public Vector3 BasePos;

    /// <summary>
    /// 最大ブロック数
    /// 1段3個*18段
    /// </summary>
    private const int MAX_BLOCKS = 3 * 18;

    void Start()
    {
        //ブロック幅(長手方向)
        float w = this.BlockPrefab.transform.localScale.x;
        //ブロック幅(短手方向)
        float d = this.BlockPrefab.transform.localScale.z;
        //ブロック高さ
        float h = this.BlockPrefab.transform.localScale.y;

        for (int i = 0; i < MAX_BLOCKS; i++)
        {
            //何段目か
            int step = Mathf.FloorToInt(i / 3) + 1;
            //奇数段目
            bool isOddStep = step % 2 == 1;
            //短手方向オフセット
            float depthOffset = ((i % 3) - 1) * d;

            float x = isOddStep ? this.BasePos.x : this.BasePos.x + depthOffset;
            float z = !isOddStep ? this.BasePos.z : this.BasePos.z + depthOffset;
            float y = this.BasePos.y + (h / 2.0f) + (step - 1) * h;
            Quaternion quat = isOddStep ? Quaternion.identity : Quaternion.Euler(0, 90, 0);

            Instantiate(this.BlockPrefab, new Vector3(x, y, z), quat);
        }

    }

}
適当にブロックのプレハブ作って実行
実行
ジェンガどーん。
ジェンガっぽい何か

おわり。

Unity系記事まとめ

2013年6月17日月曜日

Google Maps Android API v2 のマップ上にTextViewでテキストを表示する


マップ表示するだけだとちょっとあれなので、なんかテキスト表示したくなった。

やりかた

まずは表示するTextViewを持つレイアウトファイルを作成
map_overlay.xml

    
 


そしてMapFragment継承してマップ表示するフラグメント作成
onResumeでレイアウトViewをActivityに追加する。
MyMapFragment.java
public class MyMapFragment extends MapFragment {
    private GoogleMap mMap;
    private View mLayout;
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = super.onCreateView(inflater, container, savedInstanceState);
        return root;
    }
 
    @Override
    public void onResume()
    {
        super.onResume();

        //マップにレイアウトを上かぶせ
        if(mLayout==null){
            //新規はレイアウトファイルからインスタンス化
            mLayout = getActivity().getLayoutInflater().inflate(R.layout.map_overlay, null);
        }else{
            //すでにある場合もそのままではなぜか表示されないので、一旦削除
            ((ViewGroup)mLayout.getParent()).removeView(mLayout);
        }
        getActivity().addContentView(mLayout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
 TextView textView = (TextView)mLayout.findViewById(R.id.textView);
 textView.setText("てすと");
    }
}

はまったこと

なぜかタブを切替してまた戻すとテキストが消えてしまう。
なので、一旦Viewを削除してまた追加するようにしたら消えなくなった。
むずかし



2013年6月16日日曜日

Google Maps Android API v2 をActionBarのタブに表示する


見た目がかっこいいからActionBarのタブを使うことにした。

必要なファイル

・MyMapFragment.java : タブ選択時に表示されるフラグメント
・MyTabListener.java : タブリスナー
・MainActivity.java : タブ表示するアクティビティ
・activity_main.xml : タブ表示するアクティビティのレイアウト

やりかた

とりあえずMapFragment継承してマップ表示するフラグメント作成
MyMapFragment.java
public class MyMapFragment extends MapFragment {
    private GoogleMap mMap;
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = super.onCreateView(inflater, container, savedInstanceState);
        return root;
    }
}

次にActionBar.TabListenerを継承してタブとフラグメントを関連付けるためのタブリスナーを作る。
MyTabListener.java
public class MyTabListener implements ActionBar.TabListener {
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class mClass;
    private final Bundle mArgs;

    /** Constructor used each time a new tab is created.
      * @param activity  The host Activity, used to instantiate the fragment
      * @param tag  The identifier tag for the fragment
      * @param clz  The fragment's Class, used to instantiate the fragment
      */
    public MyTabListener(Activity activity, String tag, Class clz, Bundle args) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
        mArgs = args;
    }

    /* The following are each of the ActionBar.TabListener callbacks */

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // Check if the fragment is already initialized
        if (mFragment == null) {
            // If not, instantiate and add it to the activity
            mFragment =  Fragment.instantiate(mActivity, mClass.getName());
            mFragment.setArguments(mArgs);
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            // If it exists, simply attach it in order to show it
            ft.attach(mFragment);
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            // Detach the fragment, because another one is being attached
            ft.detach(mFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // User selected the already selected tab. Usually do nothing.
    }
}

そしてタブバーを表示するためのActivityを作る。
適当にMyMapFragmentのタブを3つ追加する。
MainActivity.java
public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
  
   setContentView(R.layout.activity_main);

     ActionBar actionBar = getActionBar();
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
     
     for (int i = 0; i <= 2; i++) {
         Bundle args = new Bundle();
         // 必要ならここでパラメータ追加
  String tag = String.valueOf(i);
  actionBar.addTab(actionBar.newTab()
        .setIcon(R.drawable.tab)
        .setText(tag)
        .setTabListener(new MyTabListener(this, tag, MyMapFragment.class, args)));
  }
 }
}

レイアウトはデフォルトでOK。
activity_main.xml



これでできるはず。



Unityアプリをリリースしました。「ボールラン」 アプリ紹介と作った感想とか

久々にGooglePlayにアプリをリリースしました。
今回はUnity使いました。作ってて楽しかった!

アプリ紹介

ボールラン

よくある端末を傾けて玉を転がすアレです。
電車とかじゃ絶対できないタイプのゲームです。

操作方法

操作はシンプルに2つだけに搾りました。
  • 端末を傾けて移動
  • 画面タップでジャンプ
かんたんですね。

ステージ奥の方にあるキラキラしてるところがゴールです。
がんばってたどり着きましょう!

特徴

  • ちょっと難しめにしてあります。(慣れれば簡単ですけど)
    何度も落ちながら少しずつ操作がうまくなっていく感じを楽しんでもらえればと思います。
    落ちること前提に作ってるのでサクサクリスタートできるようにしてあります。
  • 時間とかリトライ回数をつぶやけます。
    クリアできた方もできない方も是非。

開発にあたって

Unity

先月無料になってから使い始めました。
Twitterでオススメされた入門本(黄本)ですがこれが本当によかった。
まだChapter5までしかやってないですけどとにかく分かりやすい。
javascript知らないんですけど問題なく読めました。

その他、今回のアプリを作るにあたって調べたことは
ぐらいでしょうか。

板の継ぎ目がモヤモヤしてたり、たまにClearedの文字がでなかったりと
不具合はいくつかあるんですが諦めました。とりあえずリリース!

開発期間

黄本の写経も含めたら4~50時間かかったのかなぁ?
色々脱線してたのでよくわかんない。
今回は素材作りがあまり必要ないのでその点楽でした。Unity万歳。

自分が操作して納得できるまでひたすら調整してたんですが
これが一番大変…

その他

今日の夕方にリリースしてツイッターで呟いたんですが
15人もの方にリツイートしていただけました。
(今までのリリース時は7~8人だったので倍ぐらいに増えました)
嬉しかったです!ありがとうございました。

やっぱりみなさんUnityに興味持たれてるんですかね?
Unity使いが増えたら楽しいな!

次は何つくろうかなー。


よろしければ遊んでみてください。
ボールラン

2013年6月15日土曜日

【Unity】Intentを使ってTwitterにつぶやく方法。 for Android

Unityで遊びながら簡単なAndroidアプリ作ってます。
Tweet機能をつけるために調べたことをメモ。

なんか便利なプラグインがあるみたいですけど
つぶやくときに認証が必要(OAuthっていうの?)だったりするんですよね。
あれ嫌いなんです…いちユーザーとして使うのがめんどくさい。

前のアプリでIntentを使ってつぶやけるようにしたので
それをUnityでもできるようにしました。

iOSとかはこんなことする必要なくてメソッド1つ呼ぶだけでいいみたいなんですけどね・・・
Androidメンドクサス

やりたいこと

前作ったアプリ(Eclipse+Java)では下記のような書き方をしていました。

//Activityクラス内に記述
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT,"つぶやく内容");
intent.setType("text/plain");
this.startActivity(intent);

Tweetボタンを押すと、アプリ選択が出て、つぶやける。
こんな感じ。
これと同じことをUnityでやりたかった。

方法

Tweet用クラスの用意

・Create->C#Script
・Twitterとか適当に名前つける。
スクリプト追加
中身はこんな感じ。

using UnityEngine;

public static class Twitter
{

#if UNITY_ANDROID
    private static AndroidJavaObject unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    private static AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

    private static void tweet(string text)
    {
        AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.intent.action.SEND");
        intent.Call<AndroidJavaObject>("putExtra", new object[] { "android.intent.extra.TEXT", text });
        intent.Call<AndroidJavaObject>("setType", "text/plain");
        currentActivity.Call("startActivity", intent);
        intent.Dispose();
    }
#else
    static void tweet(string text) {
        throw new System.NotImplementedException();
    }
#endif

    public static void Tweet(string text)
    {
        tweet(text);
    }
}

  • どこからでも呼び出せるTweetメソッドを用意。
  • ANDROIDの場合のみIntentを使った処理。
  • JavaクラスはAndroidJavaObjectっていうのを使うと利用できるみたいです。
  • 文字列定数はここみて書き換えました。
  • このScriptはGameObjectに紐づけないのでMonoBehaviourの継承は外しました。
Androidじゃない場合の処理は調べてないので例外投げてます。
※C#の例外なげるとUnityどうなるかは知りません。

呼び出し用スクリプト

適当なボタン置いて押されたらTweetできるようにしてみた。
・空のGameObject追加
・C#スクリプト追加
・GameObjectにスクリプト適用
ボタン用スクリプト追加
中身
using UnityEngine;

public class TweetButton : MonoBehaviour
{
    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 10, 200, 200), "Tweet"))
        {
            Twitter.Tweet("つぶやきシロー元気かな");
        }
    }
}

実行

でけたー。


参考サイト

Unity系記事まとめ

2013年6月9日日曜日

【Unity】スクリプトの変数をInspecterビューで編集する

今日はスクリプトの変数についてちょっと。

スクリプトにpublicな変数を宣言するとInspectorビューに表示されるんだって!
GUI上で編集できる!すごい!

ためしてみた

適当なスクリプトを作ってGameObjectに適用。
C#スクリプトを適用
スクリプトはこんな感じ。
using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    public int X;
}
その状態でGameObjectのInspectorビューを見ると
変数が表示されてる
変数Xが表示されてる。しかもこのまま変更できる。
知ったときはすごい衝撃でした。Unityすげー。



ここから興味本位で調べた内容。
ほとんどの人は興味ないと思うけど書いちゃう!

どこまで表示されるんだろう

ちょっと遊んでみた。
using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    private int privateVariableInt;
    public int PublicVariableInt;
    public string PublicVariableString;
    public object PublicVariableObject;
    public int PublicPropertyInt { get; set; }
    public System.DayOfWeek PublicDayOfWeek;
    public event System.EventHandler PublicEvent;
    public System.Collections.Generic.List<int> PublicList;
    public MyClass MyClass;
    public MyClass2 MyClass2;
    public MyClass3<int> MyClass3;
    public UnityEngine.GameObject GameObject;
    public UnityEngine.Joint Joint;
    public UnityEngine.Color Color;
    public UnityEngine.Vector3 Vector3;
}

public class MyClass 
{
    public string Name;
}

public class MyClass2 : MonoBehaviour
{
    public string Name;
}

public class MyClass3<T> : System.Collections.Generic.List<T>
{
}

結果
結構でた
  • Privateな変数はダメ。
  • Publicな変数はOK。
  • プロパティはダメ。
  • 列挙型はOK。
  • イベントはダメ。
  • ListはOK。
  • 自作クラスはMonoBehaviourを継承すればOK。
むーん。
UnityEngine以下のクラスと基本型だけかと思ったらListとかも行けるのね。
でも自作クラスはMonoBehaviour継承しないとでないのか。
どーなってんだろ。よくわかんね。

Listが気持ち悪い

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    public System.Collections.Generic.List<string> MyList;
}
こんなスクリプトをかくと

Listの編集
こんな感じで編集できるんです。
using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    public System.Collections.Generic.List<string> MyList;

    void Start()
    {
        MyList.ForEach(text => print(text));
    }
}
こんな風に書けば
実行結果
動いちゃう!

これはすんごい!

でも…
いつ誰がインスタンス作ってんだろ?すごい気持ち悪いな。

初期化タイミング

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    public System.Collections.Generic.List<string> MyList 
        = new System.Collections.Generic.List<string>() { "Unity" };

    void Start()
    {
        MyList.ForEach(text => print(text));
    }
}
こう書いても結果変わらないから、
クラスのInitialize後、Start()呼ばれる前にUnityがインスタンス上書きしてるんだなぁ。

Publicな参照型はUnityが勝手にインスタンスを作るのか???

GameObjectだと

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
    public GameObject MyGameObject;

    void Start()
    {
        print(this.MyGameObject.name);
    }
}
これを動かしたときエラーする。
null参照エラー
だよねぇ。
Listが特別扱いされてる?
やっぱりよくわかんない。

ま、そういうもんだと思っておこう。
いずれ調べてみるか。


Unity系記事まとめ

2013年6月5日水曜日

ボールを浮かしたい。その3。挙動が変。

昨日の続きです。

おさらい

昨日は端末を振るとFloorが上下し、ボールが上に跳ねあがるのを確認できました。
スマホを振るとボールが跳ねる。

適用してみる

それを黄本の迷路サンプルに適用。
スマホを振るとボールが跳ねるはず。
ここでFloorとWallはMaze(空GameObject)の子供にしてあります。
Maze、Floor、Wallは全てRigidbodyがついており、isKinematicもONです。
Mazeと階層構造に
上下に動かすスクリプトは昨日と同じ

実行するも

全然跳ねない…
昨日はポンポン跳ねたのにほんっと跳ねない。
それだけじゃなくすぐにFloorすり抜けて落ちてくし全く別物の挙動。

訳が分からないもののひたすら違いを探して小一時間、
やっと原因個所を見つけました。

スクリプトでMazeのZ座標を動かしてたんですが
Floorを動かすようにしたら昨日と同じ挙動になりました。

親オブジェクトのMazeを操作するか、Floorオブジェクトを操作するかで全く挙動が違いました。

この違いはなんなんだろう…

まとめ

  • オブジェクトの座標をスクリプトで操作した場合の物理挙動が
    親・子オブジェクトのどちらを操作するかによって違う。

どなたか理由分かる人いたら教えてください…

2013年6月4日火曜日

ボールを浮かしたい。その2

一日開いちゃいました。
前回の続き。

ボールを浮かしたい

コースは固定されてて重力が変化する空間の中でボールだけ浮かしたい…とか
書くだけでややこしいですね。

この考えでは進みそうにないのでちょっと考え切り替えました。
めんどくさいから物理エンジンに任せようって。
コースが上下に動けば勝手にボールは跳ねるだろうと。

どうやろうか

なんとかしてスマホの上下移動をコースの高さに反映すればいいんだよね。

Input.accelerationは常に重力加速度を受けてるから
スマホが固定されていれば1G(単位ベクトル)がかかった状態。

ここでスマホを上下に動かすとベクトルサイズが変わるはず。

やってみた

てきとーにInput.accelerationのベクトルサイズを計算して表示

float g = Input.acceleration.magnitude;
print(string.Format("DEBUG {0}", g));

動かさないとおおむね1前後
スマホ机に置いた状態
動かすとそれなりにばらつく
上下に動かした状態


でもこれだと左右に動かすだけでも1G以上がかかるよね。
まぁ傾けて遊ぶゲームだし急に左右に振るのは考えなくていいか。
無視しよ。

とりあえず使えそう!

ちょっと修正

Floorタグを持つオブジェクトのZ座標を動かすように書いてみた。
どんどんずれてどっか行っちゃうので自然と0近くに収束するようにした。

こんな感じ。

using UnityEngine;
using System.Collections;

public class Sensor : MonoBehaviour
{
    /// <summary>
    /// スマホの移動に連動させるオブジェクト
    /// </summary>
    GameObject floor;

    /// <summary>
    /// 前フレームでのZ座標
    /// </summary>
    float lastZ;

    // Use this for initialization
    void Start()
    {
        this.floor = GameObject.FindGameObjectWithTag("Floor");
        this.lastZ = 0;
    }


    // Update is called once per frame
    void Update()
    {
        //端末が上下に動いた量 +↑、-↓
        float g = Input.acceleration.magnitude - 1.0f;

        this.lastZ = (this.lastZ + g) * 0.9f;


        Vector3 lastPos = floor.transform.position;
        Vector3 newPos = new Vector3(lastPos.x, lastPos.y, this.lastZ);

        floor.transform.position = newPos;
    }
}

追記

黄本読んでたら気になる記述見ちゃった。

  • プログラム制御するオブジェクトはRigidbodyコンポーネントを付ける
  • そのうえでIsKinematicプロパティをONにする
  • Update関数ではなくFixedUpdate関数内で更新する
  • transformを直接操作せず、RigidbodyクラスのMoveRotation、MovePositionを使う
だそうな。


急きょ書き換え

  • floorオブジェクトにrigidbodyを付加、isKinematicをON
  • スクリプトも変更

using UnityEngine;
using System.Collections;

public class Sensor : MonoBehaviour
{
    /// <summary>
    /// スマホの移動に連動させるオブジェクト
    /// </summary>
    GameObject floor;

    /// <summary>
    /// 前フレームでのZ座標
    /// </summary>
    float lastZ;

    // Use this for initialization
    void Start()
    {
        this.floor = GameObject.FindGameObjectWithTag("Floor");
        this.lastZ = 0;
    }


    // Update is called once per frame
    void FixedUpdate()
    {
        //端末が上下に動いた量 +↑、-↓
        float g = Input.acceleration.magnitude - 1.0f;

        this.lastZ = (this.lastZ + g) * 0.9f;

        Vector3 lastPos = floor.transform.position;
        Vector3 newPos = new Vector3(lastPos.x, lastPos.y, this.lastZ);

        floor.rigidbody.MovePosition(newPos);
    }
}

FixedUpdateだと更新間隔を指定できるみたいね。
指定方法はまた調べよう。

transporm.positionとrigidbody.MovePositionの違いはまだ分かんない。

ていうかボールの跳ねあがり方まったく別物になったんだけどw

Unity系記事まとめ

2013年6月3日月曜日

Google Maps Android API v2 で現在地をマップ中心に表示し続ける


v2になったってことでGoogle Mapを使ってみることにした。
とりあえず現在地表示。

やりかた

やり方としては、OnMyLocationChangeListenerをセットしてあげて、onMyLocationChangeを拾ったらカメラをその場所に移動させてあげるだけ。
もうちょっとめんどくさいイメージあったけど、簡単にできて良かった。
public class MyMapFragment extends MapFragment {
    private GoogleMap mMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = super.onCreateView(inflater, container, savedInstanceState);
        return root;
    }

    @Override
    public void onResume()
    {
        super.onResume();

        if (mMap == null){
     // MapFragment から GoogleMap を取得する
     mMap = getMap();
     if (mMap != null){
         // 現在地更新
  mMap.setOnMyLocationChangeListener(new OnMyLocationChangeListener(){
      @Override
      public void onMyLocationChange(Location loc) {
   LatLng curr = new LatLng(loc.getLatitude(), loc.getLongitude());
   mMap.animateCamera(CameraUpdateFactory.newLatLng(curr));
      }
  });    
     }
 }
    }



2013年6月2日日曜日

SQLiteでInsertされた行のAutoIncrement列の値を戻り値で受け取る


テーブルにAutoIncrement列を作ったのはいんだけど、どうやったらその値取れるの?って思って調べた。

やりかた


まずはテーブル作成

なんだか主キー列は_idっていうフィールド名にするのが決まりみたいだからそうする。
create table table1 (
  _id  integer primary key autoincrement not null,
  name text not null )
主キー以外の場合はやったことない。

Insert実行

private long insert(SQLiteDatabase db){
  SQLiteStatement stmt = db.compileStatement("insert into table1(name) values (?)");
  stmt.bindString(1, "なまえ");
  long id = stmt.executeInsert();
  return id;
}
これでインサートされた_idの値が返ってくる。
いい感じにできた。

2013年6月1日土曜日

ボールを浮かしたい。

Unityで遊んでます。

黄本のサンプルにある迷路を作って思ったんです。
転がすだけじゃ物足りないなぁって。

飛んだり跳ねたりさせたい。
スマホを水平に持って急上昇→急停止させたときにボールが浮くような感じ。


どうやるんだろうなぁ。

ここで書いたようにInput.accelerationを使えば傾きが取れるのは分かった。
でもaccelerationって言うからには加速度を取ってるんだよね?

調べてみた。

Input.acceleration

→公式リファレンス
3次元空間でのデバイスの加速度を取得します。

端末を机に置いた状態でX,Yは0近くでZが-1だから…
もしかして単位は重力加速度かな?

ぐぐったら出てきた。
http://sumaho0.blog.fc2.com/blog-entry-6.html
この中に「1は1Gを意味します。」って
まじかーー。

accelerationで傾き取るってどういうことよって思ってたけど疑問が氷解した。
動いてないから加速度0でしょ?って思ってたけど
重力方向の単位ベクトルが取得されてるってことね。

重力も加速度!たしかに!!

じゃあどうしよう

現在の仕様は(本のまま)

  • 画面いっぱいにはコースを表示する→OK
  • 端末を傾けてもコースの表示は変わらない→OK
  • 端末を傾けたとき重力を傾ける→OK
追加したい内容
  • 端末上昇→停止でボールを浮かせる
加速度の変化から速度を計算してボールに初速を与えればいいよね。
って言うのは簡単だけど全然作れる気がしない。

んー。
  1. accelerationで単位ベクトルが取れてる状態=端末が動いてない状態
  2. accelerationの変化 - (重力方向の)単位ベクトル = 本体移動による加速度
  3. それをさらに微分して一定の変化があるときに適当な初速をボールに与える
って感じ??
傾き変化による加速度変化と本体の移動による加速度変化をどうやって分離するかが問題だと思うけど…

頭爆発しそう。とりあえずやってみよう。

続きはまた。


Unity系記事まとめ

Related Posts Plugin for WordPress, Blogger...