2015年2月6日金曜日

Androidアプリ開発

開発時の注意点

activity_main.xml:画面のレイアウト

fragment_main.xml:端末の断片化に対応した画面レイアウト
→面倒なのでとりあえず対応しない

※Activityクラスのサブクラスは以下の記述だけでよい

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




レイアウト

activity_main.xml→アウトラインのcontainerを右クリック→レイアウトの変更
→レイアウトの方法を変えられる

RelativeLayout:相対的なポジションで場所を決められる
LinearLayout:縦または横一列に配置する




画面

Activityのサブクラスで画面を制御する



ライフサイクル

onCreate:最初に呼ばれる
onStart:onCreateの後、またはonStopの後に画面がアクティブになった場合
onPause:他の画面がアクティブになった場合
onResume:onPauseの後に画面がアクティブになった場合
onStop:しばらく画面がアクティブにならない場合



画面上のオブジェクトへのアクセス

genフォルダに自動生成される「Rクラス」を利用する
→R.javaの各オブジェクト毎のidを使う

例)button1のidを使う

R.id.button1




レイアウト上のオブジェクトを取得

findViewById(R.id.取得するオブジェクトのID);



ボタンクリック

ButtonオブジェクトにsetOnClickListenerでリスナーを設定する
→引数はOnClickListenerインターフェイスの実装クラスのインスタンス

引数のオブジェクトの「public void onClick(View v)」メソッドにクリック後の処理を記載する
※onClickの引数にはクリックされたオブジェクトが格納されている


例)button1がクリックされた場合

Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
  public void onClick(View v) {
    Log.d("TAG", v.getId() + " Click!");
  }
});



ボタンクリック2

View→On Clickにクリック時に呼ばれるメソッド名を記載

そのメソッドにクリック時の処理を記載
→引数はViewクラスのインスタンスとする

例)
public void OnBtnClick(View v) {
  Log.d("TAG", "Btn Click!");
}




ボタンクリック3

ActivityでOnClickListenerをimplementsする

ButtonクラスのsetOnClickListenerの引数を自分自身(this)とする





サイズの単位

dp:密度
sp:文字のサイズ




文字入力の更新を監視

EditTextのインスタンス.addTextChangedListener(TextWatcherを実装したインスタンス)




画面の回転

onDestroyが呼ばれる
→設定した値が無くなる

値を保存しておく必要がある


onSaveInstanceState(Bundle outState)で保存
onRestoreInstanceState(Bundle savedInstanceState)で再設定



@Override
protected void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  outState.putString("txtResult", tv.getText().toString());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  tv.setText(savedInstanceState.getString("txtResult"));
}




ソフトウェアキーボードを消す

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

 ※vはandroid.view.Viewクラスのインスタンス



Context

アプリケーションのグローバルな環境情報を受け渡すために使用されるもの

以下の方法で取得することができる

・アクティビティ.this
・getApplication()
・getApplicationContext()

※アクティビティ.thisはメモリリークの原因になるので使わない




ユーザーへの通知

Toast.makeText(コンテキスト, メッセージ, 時間※).show();


※時間
Toast.LENGTH_SHORT:短時間
Toast.LENGTH_LONG:長時間

例)MainActivityにMsg!と通知する
Toast.makeText(MainActivity.this, "Msg!", Toast.LENGTH_SHORT).show();



ビューのカスタマイズ

Viewを設定(setView)することでカスタマイズできる

例)
TextView textView = new TextView(this);
textView.setText("カスタマイズ");
Toast toast = Toast.makeText(this, "左", Toast.LENGTH_LONG);
toast.setView(textView);



ラジオボタン

RadioGroupを使用する


ラジオボタンクリック時の処理

setOnCheckedChangeListenerを設定する
→引数はOnCheckedChangeListenerを実装したインスタンス


onCheckedChanged(RadioGroup group, int checkedId)に処理を記載
→checkedIdにチェックしたラジオボタンのidが格納されている



選択されているラジオボタンの取得

ラジオグループ.getCheckedRadioButtonId()
→選択されているラジオボタンのIDを返す




シークバー

setOnSeekBarChangeListenerを設定する
→引数はOnSeekBarChangeListenerの実装したインスタンス

onStopTrackingTouch(SeekBar seekBar)
→つまみを離した時

public void onStartTrackingTouch(SeekBar seekBar)
→つまみをタッチした時

onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
→値を更新したとき(progressに値が格納)





リストビュー

Adapterパターンを使用している
→ArrayAdapterなどにデータを入れる

データを設定してリストビューにセット(setAdapter)する


ArrayAdapter

new ArrayAdapter<型>(コンテキスト, レイアウト, データ);


例)
ArrayList<String> data = new ArrayList<String>();
data.add("abc");
lv = (ListView)findViewById(R.id.listView1);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);
lv.setAdapter(adapter);



リストビューのアイテムをクリック

リストビューにsetOnItemClickListenerでリスナーを設定する

→onItemClick(AdapterView<?> av, View view, int position, long id)をオーバーライドしてクリック後の処理を記載

view:クリックされたItem
position:ItemのIndex




リストビューのアイテムを長押し

リストビューにsetOnItemLongClickListenerでリスナーを設定

→onItemLongClickをオーバーライドして、長押し時の処理を書く

※戻り値のbooleanはクリックイベントを消費するかどうか
 (trueにするとクリックイベントは発生しない)






リストビューのレイアウトを作成


1.layoutフォルダに一行分のレイアウト(XML)を作成

2.アダプターを作成
→レイアウトと表示するデータを受け取る

3.レイアウトとデータを設定
→アダプターの「getView」をオーバーライドしそこで行う

※getViewはリストビューの列を表示しようとする度に呼ばれる
  (positionは列のインデックス、convertViewは再利用可能なview)


4.アダプターをリストビューにセット


例)アダプタの作成例
public class MyAdapter extends ArrayAdapter<String> {

  LayoutInflater inflater;
  int resource;
  List<String> objects;

  public MyAdapter(Context context, int resource, List<String> objects) {
    //レイアウトとデータを受け取りフィールドにセット
    this.resource = resource;
    this.objects = objects;

    inflater = ((Activity)context).getLayoutInflater();
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {

    //対象となる行数のデータを取得
    String str = objects.get(position);
    View v;

    if (convertView != null) {
      //再利用する
      v = convertView;
    } else {
      //レイアウトをinflate
      v = inflater.inflate(resource, null);
    }
    //データをビューにセット
    ((TextView)v.findViewById(R.id.textView1)).setText(str);

    return v;
  }
}


ViewHolderパターン

上記の例ではfindViewByIdがリストビューの列数回呼ばれる
→処理が重くなる

findViewByIdした結果を保持するクラスを作成し、そのインスタンスをタグに持たせる
→Viewの再利用時はタグから保持クラスを取得する

例)保持クラスの例
class ViewHolder {
  TextView tv1;
  public ViewHolder(View v) {
    tv1 = (TextView)v.findViewById(R.id.textView1);
  }
}


例)保持クラスを利用した例
public View getView(int position, View convertView, ViewGroup parent) {

  String str = data.get(position);
  ViewHolder holder;
  View v;

  if (convertView != null) {
    v = convertView;
 
    //タグから保持クラスを取得
    holder = (ViewHolder)v.getTag();
  } else {
    v = inflater.inflate(resource, null);
 
    //保持クラスを生成しタグにセット
    holder = new ViewHolder(v);
    v.setTag(holder);
  }

  //保持クラスを利用して値をセット
  holder.tv1.setText(str);

  return v;
}




画像の取り扱い

res→drawable-○○○フォルダ
→解像度毎に画像を分けて入れる

※1つの画像のみを使用する場合は「drawable-hdpi」に置く



画像を表示

ImageViewを使用する

setImageResourceで画像をセットすると表示を切り替えられる
→画像の指定は「R.drawable.画像名」とする


※Android標準の画像を使うこともできる
android.R.drawable.イメージ名




ビューの表示/非表示

ビュー.setVisibility(visibility)

※visibility
View.VISIBLE:表示
View.INVISIBLE:非表示(スペースは空いたまま)
View.GONE:非表示(スペースを詰める)




ビューの動的生成

ビューのインスタンスを生成して設定する

例)
TextView textView = new TextView(this);
textView.setTextColor(Color.GREEN);
textView.setTextSize(100);
textView.setText("カスタマイズ");



レイアウトファイルから生成する

インフレーターを取得し、レイアウトをinflateする
→項目を修正する場合はレイアウトからfindViewByIdで取得する


例)

//インフレーターを取得
LayoutInflater inflater = getLayoutInflater();

//レイアウトをinflateする
View layout = inflater.inflate(R.layout.toastlayout, null);

//TextViewを取得し、変更
TextView text = (TextView)layout.findViewById(R.id.textView1);
text.setText("変更");




データの保存


SharedPreferences

Key/Valueの方式でデータを保存できる
→端末内部にXMLファイルを生成しそこに保存している


生成

getSharedPreferences(名前, モード);
→SharedPreferencesのインスタンスを返す



モード(Activityの定数)

MODE_PRIVATE:そのアプリのみアクセス可
MODE_WORLD_READABLE:他のアプリから読み取り可
MODE_WORLD_WRITEABLE:他のアプリから書き込み可
MODE_MULTI_PROCESS:複数のプロセスからアクセス可


データの取得

get○○○(キー名, デフォルト値);
→○○○は取得したいデータの型(String,Int,…)

※getAll()で全てのデータをMapで返す


データの保存

1.edit()でEditorインスタンスを取得する

2.エディターのput○○○(キー, 保存する値)で保存
→○○○は保存するデータの型(String,Int,…)

3.エディターのcommit()で保存の確定



例)

//生成
SharedPreferences sp = getSharedPreferences("SP", MODE_PRIVATE);

//取得
String str = sp.getString("KEY1", "");

//保存
Editor editor = sp.edit();
editor.putString("KEY1", "abc");
editor.commit();




ファイルの読み書き

基本的にはJavaのファイル読み書きと同じで以下が異なるだけ

InputStreamの取得
openFileInput(ファイル名);


OutputStreamの取得
openFileOutput(ファイル名, モード);

モード
MODE_APPEND:追記書き込み
MODE_PRIVATE:そのアプリのみアクセス可
MODE_WORLD_READABLE:他のアプリから読み取り可
MODE_WORLD_WRITEABLE:他のアプリから書き込み可



例)読み込み

InputStream in = openFileInput("myfile.txt");
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String lineStr;
StringBuilder sb = new StringBuilder();
while ((lineStr = br.readLine()) != null) {
sb.append(lineStr);
}
br.close();



例)書き込み

OutputStream out = openFileOutput("myfile.txt", MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
PrintWriter pw = new PrintWriter(osw);
pw.append("ABC");
pw.close();



assetsフォルダ内のファイルを読み込み

AssetManagerを取得し、ファイルをopenしてInputStreamを取得する

例)
AssetManager am = getResources().getAssets();
InputStream is = am.open("myfile.txt");



画面遷移


新規レイアウトの追加

layoutフォルダにxmlファイルを追加する



新規Activityの追加

新規→その他→Android→Androidアクティビティー

※上記方法を使わない場合はAndroidManifest.xmlの修正が必要



マニフェストファイル

activityタグ内に以下の記載があるものが最初に起動する画面

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>


アプリケーションタブ→Application Nodes→追加で新規Activityを追加する


※Activityの起動モード

デフォルトでは遷移の度に新しいActivityを生成する

Application NodesでActivityを選択しLaunch modeで変更できる
→singleInstanceで生成するActivityを1つだけにできる



インテント(Intent)を生成する

new Intent(遷移元のActivity, 遷移先のクラスファイル名)



インテントを使用する

startActivity(intent);



Activityを消す

finish()でActivityを消せる
→Launch modeをsingleInstanceにするのと同様の処理が可能



例)MainActivityからNextActivityへ遷移
Intent intent = new Intent(MainActivity.this, NextActivity.class);
startActivity(intent);
finish();





画面遷移時のデータの受け渡し


データを渡す

IntentのputExtraメソッドでデータを渡す

インテント.putExtra(キー, 値);

例)
Intent intent = new Intent(this, NextActivity.class);
intent.putExtra("name", "Ken");



データを受け取る

getIntent()でインテントを取得し、get○○Extra(キー)で取得
→○○は受け取るデータの型名

例)
Intent intent = getIntent();
String name = intent.getStringExtra("name");



オブジェクトを受け渡しする場合

受け渡しするオブジェクトはSerializableをimplementsする

受け取るときはgetSerializableExtra(キー)で取得
→戻り値がObject型なのでキャストが必要




画面遷移した結果を受け取る

画面遷移時に次画面へrequestCodeを送り、それに対して送信元へ結果を返すことができる



Requestの送信と画面遷移

startActivityForResult(インテント, リクエストコード);
→リクエストコードはint型



次画面で結果のセット

setResult(結果コード, Intent型のデータ);
→Intent型のデータは省略可

※データを作るときは引数無しのコンストラクタで生成
→new Intent();


結果の受け取り

Request送信元でonActivityResultメソッドをオーバーライドすると結果を受け取れる
→次画面で結果をセットするとRequest元のonActivityResultが呼ばれる

第一引数:リクエストコード
第二引数:結果コード
第三引数:Intent型のデータ




暗黙的インテント


暗黙的インテントを利用することで他のアプリケーションを起動できる
→startActivityForResultで起動する

Intent intent = new Intent(起動したい内容, 必要な情報);


例)ダイアラー起動
Uri uri = Uri.parse("tel:0120-123-123");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivityForResult(intent, REQUEST_CODE);


例)ブラウザ起動
Uri uri = Uri.parse("http://google.co.jp/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivityForResult(intent, REQUEST_CODE);




パーミッションの設定

電話をかける、通信などの機能は許可権限を記述する必要がある
→パーミッション無しでやろうとすると落ちる


パーミッションの付与

AndroidManifest.xml→下の「許可」タブ→追加→Uses Permission
→Nameに許可したい機能を選択する

例)通信の許可は「android.permission.INTERNET」





自作のアプリケーションで開く

アプリケーションから他のアプリケーションを起動する
→起動する「アプリケーションの選択」に自作アプリが表示される



呼び出し側

//データを他のActivityに送信する
Intent i = new Intent(Intent.ACTION_SEND);

//データの種類を指定
i.setType("text/plain");

//データを設定(EXTRA_TEXT:テキストデータ)
i.putExtra(Intent.EXTRA_TEXT, "ABC");

//起動
startActivity(i);




受け取り側

AndroidManifest.xmlの「intent-filter」を以下に変更

<intent-filter>
    <action android:name="android.intent.action.SEND" />
    <data android:mimeType="text/plain" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>


※受け取り側は先にインストールしておく必要がある




ダイアログ


ダイアログの表示

AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("確認");
alert.setMessage("よろしいですか?");

alert.show();



OKボタンの追加とクリック時の処理

alert.setPositiveButton("はい", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface arg0, int arg1) {
  Toast.makeText(MainActivity.this, "実行しました", Toast.LENGTH_SHORT).show();
  }
});



NGボタン

setNegativeButton


キャンセルボタン

setNeutralButton


※メッセージをリスト表示にすることもできる



その他のダイアログ

・日付:DatePickerDialog
・時間:TimePickerDialog
・進捗:ProgressDialog



ProgressDialog


※ProgressDialogは別スレッドからアクセスできる


例)スレッドで水平バーの進捗を管理

ProgressDialog p  = new ProgressDialog(this);

p.setTitle("処理中…");
p.setMessage("処理終了までお待ちください");

//水平バーを表示
p.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

//閉じられないようにする
p.setCancelable(false);

p.show();

//スレッドで進捗を管理
Thread t = new Thread(new Runnable() {

  @Override
  public void run() {
    int count = 1;
    while (true) {
      //進捗を増やす
      p.setProgress(count);
      count++;
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        Log.e("TAG", e.toString());
      }
      //進捗が最大値を超えたら終了
      if (count >= p.getMax()) {
        break;
      }
    }
    //ダイアログを閉じる
    mProgressDialog.dismiss();
  }
});
mThread.start();



スレッド

AndroidのUIは別のスレッドから操作することができない
→Handlerを利用する

Handler handler = new Handler();
handler.post(Rannableを実装したインスタンス);




定期処理

ScheduledExecutorServiceを利用する

scheduleAtFixedRate((Rannableを実装したインスタンス, delay時間, 繰り返しの時間, 時間の単位);
→処理を止める場合は「shutdown()」


例)2秒待ってから1秒毎に処理を行う
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(this, 2, 1, TimeUnit.SECONDS);



定期処理2

TimerTaskを利用しても実現できる

schedule(TimerTaskオブジェクト, delay時間, 更新時間(ms));
→処理を止める場合は「cancel()」


例)2秒待ってから1秒毎に処理を行う
mTimerTask = new MyTimerTask();
Timer timer = new Timer();
timer.schedule(mTimerTask, 2, 1000);




非同期処理

AsyncTaskを利用する
→AsyncTaskのサブクラスを作成する

AsyncTask<非同期で扱いたいオブジェクトの型, 進捗を管理するための型, 実行結果を受け取るための型>


実行前の処理

onPreExecute()


実行

AsyncTaskのサブクラスのインスタンス.execute(非同期で扱いたいオブジェクトの型)
→doInBackgroundが呼ばれる

※スレッドの部分なのでUIの変更はできない


進捗管理

doInBackground内でpublishProgress(進捗を管理するための型)を実行する
→onProgressUpdateが呼ばれる

※UIの変更はここで行う


終了

onPostExecute(実行結果を受け取るための型)が呼ばれる

※ここでもUIの変更可能



例)ログを100回表示(進捗を10回毎に表示)

//匿名クラスで非同期処理を行う
new AsyncTask<Integer, Integer, Boolean>() {

  @Override
  protected Boolean doInBackground(Integer... params) {
    for (int i = params[0]; i < 100; i++) {
      if (i % 10 == 0) {
        publishProgress(i);
      }
      Log.d("TAG", "i=" + i);
    }
    return true;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    Log.d("TAG", "onProgressUpdate:" + values[0]);
  }

  @Override
  protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);
    Log.d("TAG", "onPostExecute:" + result);
  }
}.execute(1);




AsyncTaskLoaderでの非同期処理

スレッド本体の処理のみを記述し、前処理や終了後の処理はコールバック関数を呼び出す
→UIから独立した処理をAsyncTaskLoaderに、UIの操作はActivity(コールバック関数を実装)にそれぞれ記述することができる


※サンプルコードの注意点

p123 上のコード:FragmentActivity
→4系の場合はActivityでよい


p123 下のコード:getSupportLoaderManager()
→4系の場合はgetLoaderManager()でよい


AsyncTaskLoader


クラス定義

AsyncTaskLoader<処理を行うメソッドの戻り値>のサブクラスを定義


処理

戻り値 loadInBackground()



コールバック関数の定義

LoaderCallBacks<ローダーの戻り値>インターフェイスを実装


前処理の定義

onCreateLoader(ID値, バンドルに格納したパラメータ)


終了後処理の定義

onLoadFinished(ローダー, 処理の戻り値)


処理がリセットされた場合の処理

onLoaderReset(ローダー);


Bundle

パラメーターの入れ物

値の設定:set○○○(キー, 値)
値の取得:get○○○(キー)
※○○○は値の型


AsyncTaskLoaderの呼び出し

getLoaderManager().initLoader(ID値, Bundle, コールバック関数を実装したオブジェクト)
→onCreateLoaderメソッドが呼ばれるのでその中でローダーを生成する



AsyncTaskLoaderの生成

インスタンスを生成し(引数はコールバック関数を実装したオブジェクト)、「forceLoad()」メソッドを実行する
→AsyncTaskLoaderに記述した処理「loadInBackground()」が実行される




独自のViewを作成


Viewを継承したクラスを作成
→コンストラクタを定義する必要がある


Viewのコンストラクタ

・画面レイアウトのXMLを使用する場合は引数2つを利用
・独自のスタイルを利用する場合は引数3つ



独自の描画処理

OnDraw()をオーバーライドする
→Canvasを利用することで描画処理を行うことができる


Paint

Cancasに描画する筆のようなもの
→描画時の色やテキストサイズを設定できる

例)色を青に設定
Paint paint = new Paint();
paint.setColor(Color.BLUE);


テキストの描画

キャンバス.drawText(文字, X座標, Y座標, ペイント);


画面レイアウトに独自のViewを設定

レイアウトの一番下の「カスタム&ライブラリー・ビュー」に自分の作ったビューが表示される
→ドラッグ&ドロップでレイアウトに設置できる

※表示されない場合は「リフレッシュ」ボタンを押す



独自Viewに画像を表示

Bitmapオブジェクトを生成し、drawBitmapでキャンバスに描く


Bitmapオブジェクトの生成

BitmapFactory.decodeResource(getResources(), drawable内の画像のID)


Bitmapの描画

キャンバス.drawBitmap(Bitmapオブジェクト,  X座標, Y座標, ペイント);

例)
//drawableの画像を取得
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 100, 100, null);



SurfaceViewの利用

ダブルバッファリング処理を行うことができる
→アニメーション時のチラツキを防ぐ


SurfaceViewの実装

1.SurfaceViewのサブクラスを作る


2.SurfaceHolder.Callbackインターフェイスを実装する
→メソッドを実装する

3.surfaceCreated以降に描画処理を記述



SurfaceViewへの描画


1.キャンバスの取得(ロック)

getHolder().lockCanvas();
→nullになる可能性があるのでチェックが必要


2.キャンバスに描画


3.キャンバスのロック解除と送信

getHolder().unlockCanvasAndPost(キャンバス);



SurfaceViewからの通知

SurfaceViewが破棄された場合などを通知してほしい
→SurfaceHolder.Callbackインターフェイスを実装する



コールバックの登録

通知を受け取るためには登録が必要
→コンストラクタに以下を記述

getHolder().addCallback(this);



コールバック

以下のメソッドがそれぞれのタイミングで呼ばれる

surfaceChanged:変更された時
surfaceCreated:作成されたとき
surfaceDestroyed:破棄されたとき




Viewのタッチ処理

Viewをタッチしたときに処理をしたい
→ViewクラスのonTouchEventをオーバーライドする

public boolean onTouchEvent(MotionEvent event) {

  //タッチした場所(X,Y)を取得
  float x = event.getX();
  float y = event.getY();

  //戻り値はイベント消費するかどうか
  return false;
}

イベントの取得

event.getAction()


イベントの種類

タッチ開始:MotionEvent.ACTION_DOWN
ドラッグ:MotionEvent.ACTION_MOVE
タッチ終了:MotionEvent.ACTION_UP

例)
switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
    //タッチ開始
    break;
 
  case MotionEvent.ACTION_MOVE:
    //ドラッグ
    break;
 
  case MotionEvent.ACTION_DOWN:
    //タッチ終了
    break;
 
}


排他制御

synchronizedブロックを利用することで排他制御ができる
→メインスレッドと他のスレッドで同じオブジェクトにアクセスする場合に使用する

synchronized (排他制御するオブジェクト) {
  排他制御するオブジェクトを操作する処理
}




線を描画する


Paintの設定

スタイル:setStyle
太さ:setStrokeWidth
先端の形:setStrokeCap
繋ぎ目の形:setStrokeJoin



Pathの設定

始点:moveTo(X座標, Y座標)
点:lineTo(X座標, Y座標)



Pathを描画

キャンバス.drawPath(パス, ペイント)




文字リソース

1ファイルに一元管理する
→「res→values→strings.xml」に記述する


例)「@string/action_settings」の場合
<string name="action_settings">Settings</string>




メニュー

画面上部のアクションバーにメニューが表示される


レイアウトファイルを使った場合

public boolean onCreateOptionsMenu(Menu menu) {
 
    //menu→main.xmlを見に行く
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


public boolean onOptionsItemSelected(MenuItem item) {
    //押されたメニューの取得
    int id = item.getItemId();
 
    //メニューが押された場合の処理
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

main.xml

<item
    android:id="@+id/action_settings"
    android:orderInCategory="100"
    android:showAsAction="always"
    android:title="@string/action_settings"/>

※showAsActionで表示のやり方を変えられる



動的メニュー追加

onCreateOptionsMenuの中で、メニューを追加する

メニュー.add(メニュータイトル);
→MenuItemが戻り値



MenuItemのクリックイベント

メニューアイテム.setOnMenuItemClickListener
→引数は「OnMenuItemClickListener」型




通信



基本は以下のやり方

※パーミッションに「android.permission.INTERNET」を追加する

※通信は別スレッドで処理を行う


//HTTP通信する仕組み
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse res;
HttpEntity entity;

try {
  //HTTP通信する(リクエストを送信する)
  res = client.execute(get);

  //ステータスコードのチェック(200:OK)
  if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
 
    //ボディ部を抽出する
    entity = res.getEntity();
 
    //受信データを文字列に変換する
    str = EntityUtils.toString(entity, "UTF-8");
  }
} catch (ClientProtocolException e) {

} catch (IOException e) {

} finally {
  client.getConnectionManager().shutdown();
}



エミュレーターからローカルPCの通信

ホスト名を「10.0.2.2」



実機からローカルPCへの通信

1.Androidの実機とPCは同じWiFiに接続する
2.AndroidからPCに振られているIPアドレスでアクセスする




XMLの解析


XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(XMLデータ));
int eventType = parser.getEventType();

while (eventType != XmlPullParser.END_DOCUMENT) {
  if (eventType == XmlPullParser.START_TAG) {
    if ("取得したいタグの名前".equals(parser.getName())) {
      eventType = parser.next();
      if (eventType == XmlPullParser.TEXT) {
        parser.getText()でタグの値を取得
      }
    }
  }
  eventType = parser.next();
}

※パーサー.nextText()で次の要素の値を取得できる


JSONの解析


JSONObject jsonObj = new JSONObject(JSONデータ);
JSONArray jsonArr = jsonObj.getJSONArray(root要素名);

for (int i = 0; i < jsonArr.length(); i++) {
  JSONObject jo = jsonArr.getJSONObject(i);
  if (jo.has(取得したい要素名)) { //要素の存在確認
    jo.getString(取得したい要素名)で値を取得
  }
}




サーバーへPOST

HttpPost request = new HttpPost(サーバーのURL);
client = new DefaultHttpClient();

//送信するデータのリスト
ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();

//Key&Valueの方式で送りたいデータを作成
nameValuePair.add(new BasicNameValuePair("data1", "value1"));
request.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));

//サーバーへPOST
HttpResponse response = client.execute(request);





XMLの生成

//準備
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
db = dbf.newDocumentBuilder();
Document document = db.newDocument();

//データ登録
Element root = document.createElement(ルート名);
document.appendChild(root);

Element element = document.createElement(キー);
root.appendChild(element);
Text text = document.createTextNode(値);
element.appendChild(text);

//データ変換
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
DOMSource source = new DOMSource(document);
transformer.transform(source, result);

writer.toString(); //XMLをStringに変換




PHPでのXMLのパース

simplexml_load_string(XMLデータ)
→SimpleXMLElementのデータを返す



Jsonの生成

JSONObject addressObj = new JSONObject();
JSONArray personAry = new JSONArray();
for (Person p : list) {
JSONObject personObj = new JSONObject();
personObj.put("name", p.name);
personObj.put("age", p.age);
personObj.put("blood", p.blood);

personAry.put(personObj);
}
addressObj.put("address", personAry);
jsonString = addressObj.toString();




PHPでのJson出力

<?php
$ary = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
header('Content-type: application/json; charset="utf-8"');
echo json_encode($ary);



PHPでJsonから配列の変換

$str = file_get_contents(取得するJsonデータのURL);
$ary = json_decode($str, true);



画像を通信で取得


DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse res = client.execute(get);

if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){

  //ボディ部を抽出する。
  HttpEntity entity = res.getEntity();

  //入力データを取得する
  InputStream is = entity.getContent();

  //画像データに変換する
  Bitmap bmp = BitmapFactory.decodeStream(is);
}



画像のリサイズ

float resizeScaleWidth = 0.0f;
float resizeScaleHeight = 0.0f;

Matrix matrix = new Matrix();
resizeScaleWidth = resizeWidth / bitmap.getWidth();
resizeScaleHeight = resizeHeight / bitmap.getHeight();
matrix.postScale(resizeScaleWidth, resizeScaleHeight);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), this.bitmap.getHeight(), matrix, true);

※bitmapはリサイズしたいBitmap型のインスタンス




Web View


ブラウザでWebページを表示する

WebView wv = (WebView)findViewById(R.id.webView1);
wv.loadUrl("http://yahoo.co.jp/");



Web ViewでWebページを表示する

WebView wv = (WebView)findViewById(R.id.webView1);

wv.setWebViewClient(new WebViewClient() {

  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
    return false;
  }
});

wv.loadUrl("http://yahoo.co.jp/");




JavaScriptを使用できるようにする

WebSettings webSettings = wv.getSettings();
webSettings.setJavaScriptEnabled(true);




サウンド再生

//SoundPoolインスタンス作成引数は
//ロードするファイルの数,ストリームのタイプ,
//サンプリングレートのクオリティ(デフォルトは0)
sp= new SoundPool( 1, AudioManager.STREAM_MUSIC, 0 );

//ロード完了が知りたい場合。省略可
sp.setOnLoadCompleteListener(new OnLoadCompleteListener() {
  @Override
  public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
    //ロードが完了するとここを通る。boolean 変数を設定して、
    //後の処理に繋げることも可
    Toast.makeText(MainActivity.this, "soundOK", Toast.LENGTH_SHORT).show();
  }
});

//id取得
//引数はcontext,リソースid,1(規定)
//音声ファイルはwav,ogg形式。
//ファイル名の先頭はアルファベット小文字がよい
sounds_id = sp.load(this, R.raw.se1, 1 );



//再生。id,音量左0.0~1.0,音量右,優先度(0がMax),
//再生回数(-1で無限ループ、0でループしない)
//再生速度(0.5~2.0:0.5倍から2倍)
sp.play(sound_id, vol, vol, 0, 0, 1.0F);






SQLite


DBの生成、接続

SQLiteOpenHelperのサブクラスを利用する

public class MyOpenHelper extends SQLiteOpenHelper {

  public MyOpenHelper(Context context, String name, CursorFactory factory, int version) {
    super(context, name, factory, version);
  }

  //DBが生成されていない場合に呼ばれる
  public void onCreate(SQLiteDatabase db) {
    //テーブルの生成などの初期処理を行う
  }

  //DBがバージョンアップされた場合に呼ばれる
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  }

}


//ヘルパーの生成
SQLiteOpenHelper helper = new MyOpenHelper(getApplicationContext(), "my.db", null, 1);

//DB接続(書き込み可能)
SQLiteDatabase  db = helper.getWritableDatabase();
//読み込み専用の場合は「getReadableDatabase」



INSERT

//登録する値
ContentValues values = new ContentValues();
values.put(列名, 値);

//登録されているデータ数を返す(失敗は-1)
long rows = db.insert(テーブル名, NotNull列のデフォルト値, values);
if (rows != -1) {
  //登録成功
} else {
  //登録失敗
}


SELECT

//SELECT句
String[] columns = {"ID", "NAME"};

//WHERE句とBindする値
String where = "NAME LIKE ?";
String[] params = {"%" + text + "%"};

//クエリー実行※
Cursor cursor = db.query("TABLE1", columns, where, params, null, null, null, null);

//カーソルを次へ移動
if (cursor.moveToNext()) {
  //値を取得
  id = cursor.getInt(cursor.getColumnIndex("ID"));
  str = cursor.getString(cursor.getColumnIndex("NAME"));
}
//カーソルを閉じる
cursor.close();

※queryの引数
1.テーブル名
2.カラム名(SELECT句)
3.検索条件(WHERE句)
4.検索条件パラメータ(WHERE句のBindする値)
5.グループ化(GROUP BY句)
6.グループの絞込み(HAVING句)
7.ソート順(ORDER BY句)
8.取得件数(LIMIT句)



UPDATE

//更新する値
ContentValues values = new ContentValues();
values.put(列名, 値);

//WHERE句とBindする値
String where = "ID=?";
String[] whereArgs = {"1"};

//更新した列数を返す
int rows = db.update(テーブル名, values, where, whereArgs);
if (rows != 0) {
  //更新成功
} else {
  //更新失敗
}


DELETE

//WHERE句とBindする値
String where = "ID=?";
String[] whereArgs = {"1"};

//削除した件数を返す
int rows = db.delete(テーブル名, where, whereArgs);
if (rows != 0) {
  //1件以上削除
}


トランザクションを利用


//トランザクションスタート
db.beginTransaction();

//成功をセット
db.setTransactionSuccessful();
※セットされなければロールバック

//トランザクション終了
db.endTransaction();



SQL文を使用

SELECT以外
db.execSQL("SQL文" [,置き換え文字の配列]);


SELECT
db.rawQuery("SQL文" ,置き換え文字の配列);
→Cursorを返す




SQLiteStatementを利用

※SELECTはできない

//Statementを取得
SQLiteStatement stt = db.compileStatement(SQL文);

//文字をBind(Indexは1から始まる)
stt.bindString(インデックス, 値);

//INSERTを実行
stt.executeInsert();

//UPDATE,DELETEを実行
stt.executeUpdateDelete()




フラグメン

画面をいくつかの要素に分けて(断片化)、Activityでそれを組み合わせる


2種類の実装方法がある

1.Layoutファイルを使う
2.コード内で動的に生成


Layoutファイルを使う方法

1. Fragmentのサブクラスを作成

2. ActivityのLayoutにFragmentを追加

3. FragmentのサブクラスでonCreateViewをオーバーライド
  →戻り値でレイアウトをinflateする

  例)
  return inflater.inflate(R.layout.fragment1, container, false);

4.FragmentのサブクラスでonStartをオーバーライド
  →処理を記述する

  ※findする場合は「getActivity().findViewById(…」
    (同じActivity上の他のFragmentの要素にもアクセス可能)




フラグメントの動的生成

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(追加先のビュー, フラグメントのインスタンス);
ft.commit();



フラグメントの置き換え

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(追加先のビュー, フラグメントのインスタンス);

//バックスタックに追加
ft.addToBackStack(null);

ft.commit();

2015年1月11日日曜日

Unity

※※Unityでの重要要素※※

40点分…Instantiate

30点分…OnCollisionEnter
20点分…OnTriggerEnter
15点分…OnControllerColliderHit

15点分…AddComponent
30点分…GetComponent

25点分…SendMessage

20点分…Find

※※


画面構成


Sceneビュー

開発で使う、Scene内のGame Objectを操作する


Gameビュー

実際のゲームでの見え方を確認する

ゲームを実行するとSceneビューから切り替わる



Hierarchy(ヒエラルキー)ビュー

Game Objectが階層構造で表示される


Projectビュー

Project内のデータやスクリプトなどが格納されている


Inspector(インスペクター)ビュー

選択したGame Objectの詳細設定が表示される


Consoleビュー

スクリプトのデバッグ表示やエラーメッセージが表示される


Game Object

物やキャラクターなどの総称


UI切り替え

Window→Layoutsで選択




ゲーム実行中の注意点

ゲーム実行中にGame Objectの設定を変えても保存されない
→ゲームプレイ中のビューの色を変えた方が良い



ゲームプレイ中のビューの色の変更

Edit→Preferences→Colors→Playmode tint→変える色を選択



Game Objectの生成

Hierarchy→Create→作りたいモノを選択



プリミティブ素材

以下のような基本的な図形が用意されている

Cube…立方体
Sphere…球
Capsule…カプセル型
Cylinder…円柱
Plane…板


操作ツール

手のひら、矢印などのボタン群、どのような操作をするのかを切り替える
→左からQWERボタンがショートカットに割り当てられている



表示位置の変更


手のひらツールでSceneビューの表示位置を動かすことができる

[Alt]を押しながら(Macではoption)で、アイコンが目の表示に変わり、アングル(角度)を変えることができる


右上のScene Gizmoでも同じように視点の変更ができる


Hierarchyのオブジェクトをダブルクリックで、それが視点の中心にくる



Scene Gizmo(シーンギズモ)

真ん中の□クリックで遠近感が無くなる

Shift+真ん中クリックで角度をつける




オブジェクトの移動


十字キーツールで選択したGame Objectを移動することができる

InspectorビューのTransformのPositionを入力しても同じ



オブジェクトの回転


回転ツールで選択したGame Objectを回転させることができる

InspectorビューのTransformのRotationを入力しても同じ



オブジェクトの大きさを変える


拡大縮小ツールで選択したオブジェクトの大きさを変えることができる
→真ん中をドラッグで全体的に拡大縮小できる

InspectorビューのTransformのScaleを入力しても同じ



ライト

ライトで光を当てることでオブジェクトが明るくなる

Directional Light…太陽の光で方向のみを設定する



現在の見た目でカメラを固定

Hierarchyでカメラを選択→Game Object→Align With View



ProjectとScene

Projectはそのゲーム全体のことで複数のSceneが格納される

Sceneはタイトル画面や各ステージなど、別々のシーン毎に1つずつ作る


Prefab(プレハブ)

個別のシーンのオブジェクトをプロジェクト内で共通に使えるようにすること
→HierarchyビューにあるオブジェクトをProjectビューにドラッグ&ドロップする

ProjectビューにあるプレハブはHierarchyビューにドラッグ&ドロップで同じものをいくつも生成できる



シーンの作成

File→Save Scene→シーン名を入力して保存
※保存後、Projectビューにシーンが表示される


オブジェクトの生成

Hierarchy→Create→作りたいモノを選択



オブジェクトの複製

Hierarchyの複製元を右クリック→Duplicate



重力の付与

オブジェクトにRigidbody(リジッドボディ)を設定する

InspectorのAdd Component→Physics→Rigidbody


Rigidbodyの設定項目

Mass…質量
Drag…空気抵抗
Angular Drag…回転にかかる空気抵抗
Use Gravity…重力を付けるかどうか
Is Kinematic…スクリプトから操作しなければ動かない
Constraints→Freeze Position…ポジション固定
Constraints→Freeze Rotation…回転固定


衝突判定を無くす

~ Colliderのチェックを外す
※Box Colider、Sphere Coliderなど



摩擦や反発の設定

プロジェクトにPhysic Materialを作成し、それをオブジェクトに付与する



Physic Materialの作成

Projectビュー→Create→Physic Material→名前を付ける



Physic Materialの付与

付与したいオブジェクトを選択→Inspectorの~ ColiderのMaterialに作成したPhysic Materialをドラッグ&ドロップ



Physic Materialの設定項目

Dynamic Friction…動的な状態の摩擦(0~1) ※0が摩擦なし
Static Friction…静的な状態の摩擦(0~1) ※0が摩擦なし
Bounciness…反発係数(0~1) ※0で反発無し
Friction Combine…オブジェクトが衝突した際の摩擦の計算方法
Bounce Combile…オブジェクトが衝突した際の反発の計算方法



オブジェクトに色をつける

プロジェクトにMaterialを作成し、設定後それをオブジェクトに付与する



Materialの作成

Projectビュー→Create→Material→名前を付ける



Materialの設定

Projectビュー→Materialを選択→InspectorのMain Colorで色を設定


Materialの付与

Projectビュー→Materialを選択→Hierarchyの付与したいオブジェクトの上に、Materialをドラッグ&ドロップ




Empty

フォルダ的にいくつかのオブジェクトをまとめられる

GameObject→Create Empty


※Emptyでまとめたオブジェクトに重力を付けたい場合、EmptyにRigidbodyを付与する




物体の形の変更

Inspectorの○○○(Mesh Filter)->Meshを変更で可能




Asset(アセット)

アセットと呼ばれる部品を使うと簡単に地面や空などを作れる


unityPackageとして標準で使えるアセット

Character Controller…操作できるキャラクター
Particles…火や煙などのエフェクト
Skyboxes…空
Terrain Asset…地面
Tree Creator…木
Water(Basic)…水


Terrain

ブラシでなぞって山を作ったり、筆で土や湖などを塗ったりできる

テクスチャーを貼り、地面の表面を芝や雪などの質感を与えられる

木を生やしたり、草を生やしたりすることもできる



Skybox

Main Camera(メインカメラ)に設定することで、カメラが移動しても常に空が表示される



Character Controller


自分で動かすことのできるキャラクター

First Person Controller…一人称視点
3rd Person Controller…三人称視点



3rd Person Controller

各アニメーションを設定するだけで、自在に動かせるキャラクターを作れる

Idel Animation…待機中
Walk Animation…歩く
Run Animation…走る
Jump Pose Animation…ジャンプ



Particle

エフェクトで様々な表現を作れる

Dust Storm…砂嵐
Water fall…滝
Fire1…炎



Asset Store(アセットストア)

様々なアセットが入手できるストア



Web Player書き出し

Web Playerに書き出せばブラウザ上でプレイできる

File→Build Settings…→WebPlayerを選択しSwitch Platform→Buildで名前をつけて保存




スクリプトの追加

Inspector→Add Component →New Script



エディタを変える

edit-→Preferences…→External Tools →External Script Editor



スクリプトについて

jsはクラス宣言が省略されている
(ファイル名と同じクラスでMonoBehaviourを継承)


Startメソッド…最初に一回だけ呼ばれる

Updateメソッド…フレーム毎に何度も呼ばれる



デバッグ出力

Debug.Log


変数宣言

var


関数宣言

function


オブジェクトの移動


transform

全てのGame Objectが持っているプロパティで位置・回転の情報を持っている


移動(相対)

transform.Translate(X軸, Y軸, Z軸);
※X,Y,Zの値が加算された位置に移動する


回転

transform.Rotate(X軸方向,Y軸方向,Z軸方向);


前進(Z軸方向)

transform.Translate(transform.forward);
※負の値を掛けると反対方向


上昇(Y軸方向)

transform.up


右(X軸方向)

transform.right



フィールド値

フィールド(privateではない)値がInspectorに表示され、そちらで編集できる


フィールド値の優先順位

初期値→Inspector→Start()内の順で設定した値が優先される




位置情報

Vector3クラスを使う

new Vector3(X座標, Y座標, Z座標)



現在座標

transform.position



絶対座標への移動

transform.position = Vector3.MoveTowards(transform.position, new Vector3(X座標, Y座標, Z座標), 移動量);

例)
transform.position = Vector3.MoveTowards(transform.position, new Vector3(10,10,10), 0.1);



キーボード入力の取得

Input.GetKey(キーコード)
※true or falseを返す



キーコード

上…KeyCode.UpArrow
下…KeyCode.DownArrow
右…KeyCode.RightArrow
左…KeyCode.LeftArrow





画像をテクスチャにする

画像をAssetsにドラッグ&ドロップ



力を加える

transform.rigidbody.AddForce(X, Y, Z);
※オブジェクトにリジッドボディが付与されている必要がある




パーティクルの追加

Add Component→Effects→Particle System



移動(直接入力)

transform.position.x = Xの値;
transform.position.y = Yの値;
transform.position.z = Zの値;



拡大・出力(直接入力)

transform.localScale.x = Xの値;
transform.localScale.y = Yの値;
transform.localScale.z = Zの値;



見えなくする

Mesh Rendererのチェックを外す



無効にする

オブジェクト名の左側のチェックを外す



コンポーネントの削除

設定(歯車ボタン)→Remove Component



型の付け方

var 変数名 :型名;



Keyの割り当て参照

edit→Project Settings→Input



キー入力の取得

Input.GetButtonUp(Input名)
→ボタンを押した後、離したかどうかをtrue or falseで返す



キー入力の取得

Input.GetAxis(Input名)
→正方向がプラス、負方向はマイナスを返す




インスタンスの生成

Instantiate(生成したいオブジェクト, position, rotate);
※生成したいオブジェクトはプレハブ化していること




衝突判定

OnCollisionEnter(obj:Collision)
→他のオブジェクトと衝突した場合に呼ばれる

※引数はぶつかった相手



衝突したオブジェクトの名前を取得

Collsionの変数名.gameObject.name



乱数

Random.Range(From値, To値)



時間関係の処理

Timeクラスを使う


フレームのカウント取得

Time.frameCount



数学関数

Mathfクラス

Mathf.Floor()…切り捨て
Mathf.Ceil()…切り上げ
Mathf.Round()…四捨五入



スクリプトを実行しているオブジェクト

gameObjectプロパティで取得




Game Objectを消す

Destroy(消したいオブジェクト);

例)自分を消す
Destroy(gameObject);




BGMの付与

EmptyでBGMを与えるオブジェクトを作る

Add Component→Audio→Audio Source

起動したら再生
Play On Awakeにチェック

ループ
Loopにチェック




効果音(SE)の再生


AudioSource.PlayClipAtPoint(効果音, transform.position);

※音が鳴らない場合は3D Soundを外すと良い場合がある



エフェクト

Particleを生成する

例)
var explosion :GameObject;
function OnCollisionEnter(obj :Collision) {
//爆発のエフェクト
Instantiate(explosion, transform.position, transform.rotation);
}



トレイルレンダラ

オブジェクトの後ろにエフェクトを出す

Add Component→Effects→Trail Renderer

Materials→Element0にパーティクルを設定





テキストを表示

GUIText
※ver4.6以降はuGuiを使用

Position x(0~1), y(0~1)で調整
※(0,0)で左下



テキストを設定


GUI Textの場合

guiText.text = 設定したい文字列;




uGuiの場合

var score :Ui.Text;
score.text = 設定したい文字列;



GUIの表示

OnGUI()で実行時に表示される



矩形型

Rect(x, y, width, height)



ラベルの表示

var style : GUIStyle;

function OnGUI() {
GUI.Label(Rect(10,10,200, 50), "abc", style);
}
→InspectorでStyleを設定する



画面遷移


File→Build Settings→シーンを登録

Application.LoadLevel(シーン名);




Tiling(タイリング)

テクスチャ画像を張る枚数



当たり判定の設定

Add Component→Phusics→Colliderを設定



タグ

オブジェクトのスクリプトでの識別に使う

InspectorのTab→Add Tag…→Element0にタグ名を入力し作成
→作成したタグを設定


タグの参照

gameObject.tag

例)タグの名前がBulletかどうか
if (gameObject.tag == "Bullet") {




マウスクリック

押したとき
Input.GetMouseButtonDown(ボタン番号);

離したとき
Input.GetMouseButtonUp(ボタン番号);

0…左クリック
1…右クリック
2…真ん中クリック


関数の戻り値の型

function 関数名(引数) : 戻り値の型 {
・・・
}



キャスト

キャストしたい変数 as キャストしたい型




親オブジェクトの設定

設定したいオブジェクト.transform.parent = 親にしたいオブジェクトのtransform;



ローカルな位置情報

親オブジェクトからの相対位置になる

例)親からX方向に10ずれたポジションに設定
obj.transform.localPosition = Vector3(10, 0, 0);

ローカルな位置…transform.localPosition
ローカルな大きさ…transform.localScale




(0,0,0)のVecter3を生成

Vector3.zero



クリックした座標の取得

Input.mousePosition




Rayを飛ばす

Rayとは指定の向きへレーザーを放つ感じ

ScreenPointToRay(飛ばすポジション);

例)メインカメラからマウスポインタへRayを飛ばす
Camera.main.ScreenPointToRay(Input.mousePosition);


角度を取得

オブジェクト.direction.normalized;



加速度を与える

rigidbody.AddForceと違い、摩擦などを考慮せずいきなりトップスピードになる

オブジェクト.rigidbody.velocity = 加速度の値
※オブジェクトにrigidbodyが設定されていること




当たり判定(スクリプト上だけ)


Is Triggerにチェック

OnTriggerEnter(col : Collider) で検出




オブジェクト同士のくっつき

CharacterJointを設定

Break Force…耐えられる力の限界
Break Torque…耐えられる回転の限界






スクリプトでコンポーネントを追加

gameObject.AddComponent(コンポーネント名)
→追加したコンポーネントを戻り値として返す



スクリプトでのCharacterJoinの設定

オブジェクト.connectedBody = くっつけたい相手のrigidbody
オブジェクト.breakForce = Break Forceの値
オブジェクト.breakTorque = Break Torqueの値




フィールドのアクセス修飾子

public,なし…Inspectorに表示される
private…Inspectorに表示されない




ボタンを生成

GUI.Button(Rect型の変数, テキスト);
→クリックされたらtrue、そうでなければfalseを返す

例)
if (GUI.Button(Rect(400, 250, 100, 50), "BUTTON")) {
Debug.Log("Click!");
}




ラベルを生成

GUI.Label(Rect型の変数, テキスト, GUIStyle型の変数);




GUIStyle

GUIのStyleを設定

例)フォントサイズを40,色を赤に設定
var style : GUIStyle;
style.fontSize = 40;
style.normal.textColor = Color.red;




プリミティブ素材の生成

GameObject.CreatePrimitive(プリミティブ素材のタイプ);


プリミティブ素材のタイプ

PrimitiveType.Sphere
PrimitiveType.Cube
PrimitiveType.Plane




オブジェクトを無効にする

オブジェクト.renderer.enabled



Rayの当たり判定

Physics.Raycast(Ray型の変数, RaycastHit型の変数, 距離)
→当たったかどうかをtrue or falseで返す

例)メインカメラからマウスポインタまでの当たり判定
var ray : Ray;
var hit : RaycastHit;
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, hit, 100)) {
Debug.Log("Hit!!");
}



プレハブのインスタンスの変更

インスタンスのみ変更され、プレハブ本体は変更されない
→Applyボタンを押すとプレハブ本体の方にも変更が適用される



経過時間

Time.time



ある地点から角度を指定した座標の指定

rad = 角度 * PI / 180;
x = sin(rad), y = cos(rad);

例)(0,0)の地点から30度の場所に移動
var rad = 30 * Mathf.PI / 180
transform.pisition(sin(rad), 1, cos(rad));



マウスポインターが重なったとき

OnMouseEnter()



フレームレートに依存しない処理

1秒間にUpdateが呼び出される回数は環境毎に変わる
→Time.deltaTimeを掛けると良い

例)1秒間に30度ずつ回転させる
transform.Rotate(0, 30 * Time.deltaTime, 0);



Mecanim

アニメーションの遷移を管理する



Characer Controller

キャラクターを動かす

物理演算の影響を受けなくなる



カメラの追従

Smooth Foolowスクリプトを設定する



影を作成

Projectorsアセットを使用



レイヤー


Edit→Project settings→Physics

Layer Collision Matrixでレイヤー同士の衝突の有無を設定




プロジェクト内の重力

Edit→Project settings→Physics

Gravityを変更することができる




データの保存

PlayerPrefsでKey,Value方式で保存できる


キーの存在確認

PlayerPrefs.HasKey(キー);


PlayerPrefs.Set○○(キー);
※○○はデータの型名(Intなど)


値の取得

PlayerPrefs.Get○○(キー);


データの削除

PlayerPrefs.DeleteKey(キー);



設定しているコンポーネントの取得

GetComponent(コンポーネント名)



アニメーターのパラメーターをセット

アニメーター.Set○○(キー, 値);
※○○はデータの型名(Intなど)


アニメーターのステート情報を取得

アニメーター.GetCurrentAnimatorStateInfo(0);
→AnimatorStateInfo型の戻り値にステート情報が格納されている



アニメーターステート情報の名前を確認

アニメーターステート情報.IsName(名前)
→現在のアニメーションがその名前かどうかを返す




関数の遅延実行

Invoke(関数名, 秒数);



キャラクターを操る方法

transform
rigidbody
charactor Controller




Charactor Controller

接触判定も含まれている
→元々あった接触判定は差し替えとなる

接触判定
Center,Radius,Height

接地しているかどうか
isGrounded

Slope Limit…上れる坂の角度
Step Offset…上れる段差





ベクトル大きさ

Vector3の変数.magnitude




そちらを向く

transform.LookAt(方向<Vector3>)



移動

キャラクターコントローラー.move(方向<Vector3>);


Vector3.zero = Vector3(0, 0, 0);
Vector3.one = Vector3(1, 1, 1);
Vector3.forward = Vector3(0, 0, 1);
Vector3.back = Vector3(0, 0, -1);
Vector3.up = Vector3(0, 1, 0);
Vector3.down = Vector3(0, -1, 0);



Rigを設定できるWebサービス

https://www.mixamo.com/



子要素のコンポーネントを取得

GetComponentInChildren(コンポーネント名)



OnTrigger○○○

OnTriggerEnter:接触した時
OnTriggerStay:接触している間
OnTriggerExit:離れた瞬間



影を付ける

ライトを選択→ShadowTypeをSort,Hard Shadows
※影の演算は重くなるので注意




オブジェクトの関数を実行

オブジェクト.gameObject.SendMessage(関数名);
→戻り値を取得できない


関数が無い場合もエラーを表示させない

第二引数に「SendMessageOptions.DontRequireReceiver」を指定する


SendMessageを使わない方法

var s:スクリプト型 = gameObject.GetComponent(スクリプト名);
s.実行したい関数




傾きを設定

transform.eulerAnglesに値を設定する

※transform.rotation = Quaternion.Euler(Vector3の値);でも同じ



そちらの方向を向く

transform.rotation = Quaternion.LookRotation(Vector3の向きたい方向);



Mathfの関数

Mathf.Pow…べき乗
Mathf.Sqrt…平方根
Mathf.Clamp…値の上限,下限を設定できる
Mathf.PingPong…往復する値を返す
Mathf.Lerp…線形補完
Mathf.Abs…絶対値



指定時間後に削除

Destroy(オブジェクト, 秒数);



オブジェクトの有効・無効

設定
オブジェクト.SetActive(booleanで有無)

取得
オブジェクト.activeSelf



自分が削除されたとき

OnDestroy()




配列

2つのやり方がある

【1】
new Array(配列の要素,・・・);

【2】
var 変数名:配列の型[];
変数名 = new 変数名:配列の型[要素数];

※初期化子を使う場合
var 変数名 = [要素1, 要素2, ・・・];





キャラクターコントローラーの衝突判定

OnControllerColliderHit(ControllerColliderHit型)



単位ベクトル

magnitudeが1になるような値
→方向のみを使いたい場合に使用

Vector3型の変数.normalized




Arrayクラス

Shift…要素を前方向に詰める
Unshift…要素を先頭に追加して後ろにずらす
Push…最後の要素として追加
Pop…最後の要素を取り出す



2台目のカメラ

Audio Listenerを削除する

mainカメラと2台目と両方のViewport Rectを調整する
→X, Wを設定




当たり判定

1.CharacterControllerを持つオブジェクトが移動して衝突する場合

OnControllerColliderHit


2.colliderを持つオブジェクトがCharactorControllerを持つオブジェクトに衝突する場合

OnTrigger○○○


3.CharacterControllerを持つオブジェクト同士

OnControllerColliderHit




Hierarchyのオブジェクトを取得

GameObject.Find("オブジェクト名");



子要素の数を取得

transform.childCount



子要素を取得

transform.GetChild(インデックス)



オブジェクト、スクリプトの取得

GameObject.FindObjectOfType(オブジェクトの型);
→メソッドチェーンで取得したスクリプトのメソッドを呼べる



C#について

using→import
:→extens
アクセス修飾子無し→private
ジェネリクス<型>



画面の幅と高さを設定

Build Settings…→Player Settings…→Resolution and Presentation→幅と高さを指定

Gameビューの左上をWeb(○○○×○○○)にすると幅と高さが制限される



オブジェクトが画面外になった場合

OnBecameInvisible()




デバッグでポーズ

Debug.Break();



Skyboxの設定

Edit→Render Settings→Skybox Material
※SceneビューのEffectsでSkyboxにチェック




Euler角からQuaternionへの変換

Quaternion.Euler(X, Y, Z);



Updateが終わった後の処理

LateUpdate()に記載する
→Updateの後に呼ばれる(毎フレーム)




Legacy Animation


アニメーションを実行

アニメーション.clip = 実行したいアニメーションクリップ;
アニメーション.Play();



徐々にアニメを変化(クロスフェード)

アニメーション.CrossFade(アニメの名前<String>, クロスする時間);





内部クラスをInspectorに表示させる


[System.Serializable]
※C#の場合




影を付ける(軽めの処理)

Projectorで黒い光を当てる
→自分も真っ暗になってしまう

解決策
→Ignore Layersで例外を設定
→Near Clip Planeで当てる範囲を調整



影を付ける(軽い処理)

足元に影の画像を表示するオブジェクトを設置する




衝突判定の条件

1.衝突を起こす両方のゲームオブジェクトにColliderコンポーネントが追加されていなければならない
2.2つのゲームオブジェクトのうちで移動する方には必ずRigidbodyコンポーネントが含まれていなければならない




コルーチン


スレッド(マルチタスク)のようなモノ

開始

StartCoroutine(実行したいメソッド)


実行したいメソッドの型

IEnumeratorを戻り値として返す
→「yield return 戻り値;」で返す



コルーチンの一時中断

yield return new WaitForSeconds(中断時間);
→再開はこの後から



例)コルーチンの例

void Start () {
  // コルーチンを実行
  StartCoroutine ("Sample");
  StartCoroutine ("Sample2");
}

// コルーチン(途中で一定時間中断)
private IEnumerator Sample() {
  // ログ出力
  Debug.Log ("1");

  // 1秒待つ
  yield return new WaitForSeconds (1.0f);

  // ログ出力
  Debug.Log ("2");

  // 2秒待つ
  yield return new WaitForSeconds (2.0f);

  // ログ出力
  Debug.Log ("3");
}

//1フレームごとにログを出力
private IEnumerator Sample2() {
  for (int i = 0; i < 100; i++) {
    Debug.Log ("i:" + i);
    yield return null;
  }
}



回転の初期値

Quaernion.identity




ある範囲内にあるColliderを取得

Physics.OverlapSphere(中心点, 半径)

例)指定した原点を中心に10.0f半径内に入っているColliderオブジェクトを抽出
Collider[] colls = Physics.OverlapSphere(tr.position, 10.0f);



爆発のような力を与える

オブジェクト.rigidbody.AddExplosionForce(爆発力, 原点, 半径, 上に跳ね飛ばす力);




テクスチャの更新

MeshRenderer変数.material.mainTexture = Texture型;



コンポーネントの削除禁止

[RequireComponent(typeof(コンポーネント名))]
※クラス宣言の前に記述







アニメーション


Rig→Animation Type

Humanoid…人間型
Generic…四足歩行


Apply→Configure…→モデルの動きを調整





追跡ルーチン


床と障害物を「Navigation Static」


Window→Navigation→Bakeタブ→Bakeボタン→通っても良い部分が青くなる

Nav Mesh Agentコンポーネントを追加


NavMeshAgent変数.destination = 対象のポジション;




2点間の距離

Vector3.Distance(A地点, B地点);



列挙型

enum 型名 {値1, 値2,・・・};
→使う場合は「型名.値」



徐々に方向を変える

Quaternion.Slerp(from, Quaternion.LookRotation(to - from), speed(0~1));



どんな状況からもアニメーションする

「Any State」からMake Transition



アニメーションが○%まで再生したら

Exit Time を設定(0~1)



アニメーターの階層構造

複数のレイヤーを持つことができる
→GetCurrentAnimatorStateInfo(0)は1つ目のレイヤー



アニメーションをハッシュ値で比較

GetCurrentAnimatorStateInfo(0).nameHash == Animator.StringToHash(レイヤー名.アニメーション名")




同じタグのオブジェクトを取得

FindGameObjectsWithTag(タグ名)

例)
GameObject[] ary = GameObject.FindGameObjectsWithTag("a");
foreach (GameObject a in ary) {
・・・
}




イベント駆動


イベントを発生させる側

デリゲートの設定
public delegate void デリゲート名(引数);


イベントの設定
public static event デリゲート名 イベント名;


イベントの発生
イベント名(引数);




イベントを受け取る側

イベントを登録
void OnEnable() {
スクリプト名.イベント名 += 実行するメソッド名;
}


イベントを削除
void OnDisable() {
スクリプト名.イベント名 -= 実行するメソッド名;
}



子オブジェクトのコンポーネントを全て取

GetComponentsInChildren
※Index:0に自分自身が入る




ゲームオブジェクトを動的に生成

GameObject 変数名 = new GameObject(名前);




Trigger型パラメータ(アニメーション)

アニメーション型変数.SetTrigger("パラメーター名");
→トランジションが終らないとOffにならない為、使い方が難しい



アニメーションによって座標を変化させない

Inspector→Animator→Apply Root Motion
→チェックをはずす



アニメーションのリターゲティング

違うアバターにアニメーションコントローラーとスクリプトを付与
→元のアバターと同じアニメーションをする

※RigのAnimation Typeを合わせる必要がある




アニメーションイベント


アニメーションを選択→Inspector→Eventsにイベントを追加
→呼び出す関数名(Function)、関数の引数を設定
→→設定したイベントのタイミングで登録した関数が呼ばれる




Unity 2D



画像の重なりを管理

Sorting Layersを追加する




1つの画像を分割

Sprite Mode→Multiple

Sprite Editorで選択する




回転させない

Rigidbody2D→Fixed Angle



2Dアニメーション

Window→Animation→Create New Clip

Sample:1秒間のコマ数
画像をドラッグ&ドロップ




画像を反転

Scaleを負の値にする



LineCast

線を引いて、その線上に当たり判定があるかを判定

Physics2D.Linecast(開始点, 終了点, 判定するレイヤー);
→戻り値としてRaycastHit2Dを返す



アニメーションイベン

Animationウィンドウで左クリック→Add Animation Event
→呼び出すfunctionを設定




uGUI

Render Mode→Screen Space-Overlay
→最前面に表示

※using UnityEngine.UI;
→こうしておくとText.○○などとと使える


2014年12月26日金曜日

PHPでDBアクセス

PDO(PHP Data Objects)

データーベース抽象化レイヤ(DBの違いを気にせずに使える)


エラー通知

以下の記述をしておくと、SQLの構文エラーを通知してくれる

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

※$dbはPDOオブジェクト



DBを開く

new PDO(データベース接続文字列, ユーザー名, パスワード)



データベース接続文字列

mysql:host=ホスト名; dbname=データベース名; charset=文字コード



DBを閉じる

PDOオブジェクトを破棄する(NULLにする)
※こうしなくてもスクリプトが終了すれば自動でDB接続が切断される



例)ローカルDBのデータベース名php10を文字コードutf8で開く

//開く
$db = new PDO('mysql:host=localhost;dbname=php10;charset=utf8', 'phpusr', 'phppass');

//閉じる
$db = NULL;




例外処理

try {
  例外が発生する可能性のあるコード
} catch (例外の種類 変数名) {
  例外発生時の処理
}


例)
try {
  $db = new PDO('mysql:host=localhost;dbname=php10;charset=utf8', 'phpusr', 'phppass');
} catch (PDOException $e) {
  die('エラーメッセージ:' . $e->getMessage());
}



SQLの実行

以下の手順が必要

・SQLの準備
・SQLにパラメータをセット
・SQL実行



SQLの準備

PDOオブジェクト->prepare(SQL文);

※PDOStatementオブジェクトが返ってくる




SQLにパラメータをセット

SQL文の中にプレイスホルダ(:名前)を使った場合、そこに値をセットする

※プレイスホルダを使わないとセキュリティ上の問題(SQLインジェクション)がある

PDOStatementオブジェクト->bindValue(パラメータ名, 値);


※セットする値が数値(int)の場合は第三引数に「PDO::PARAM_INT」を付けた方がよい

例)
$stt->bindValue(':age',$arr['age'],PDO::PARAM_INT);




SQL実行

PDOStatementオブジェクト->execute();


例)INSERTを実行

//DB接続
$db = new PDO('mysql:host=localhost;dbname=php10;charset=utf8', 'phpusr', 'phppass');

//SQLの準備
$stt = $db->prepare('INSERT INTO schedule(title) VALUES(:title)');

//SQLにパラメータをセット
$stt->bindValue(':title', $_POST['title']);

//SQL実行
$stt->execute();

//DB切断
$db = NULL;




DBからレコードを取得


SELECT文をexecuteメソッドを実行するとその結果がPDOStatementに保存される




取得したレコードの表示

1行ずつフェッチ(読み込み)をする

PDOStatementオブジェクト->fetch();




フェッチの形式を変更

fetchメソッドは規定で配列または連想配列でアクセスできるように返してくれる

変更したい場合はfetchメソッドに以下の引数を渡す

PDO::FETCH_NUM…配列($row[1])
PDO::FETCH_ASSOC…連想配列($row['title'])
PDO::FETCH_BOTH…配列または連想配列[規定]($row[1] or $row['title'])
PDO::FETCH_OBJ…オブジェクト($row->title)



例)

$db = new PDO('mysql:host=localhost;dbname=php10;charset=utf8', 'phpusr', 'phppass');
$stt = $db->prepare('SELECT title FROM schedule');
$stt->execute();

//全てのレコードをフェッチ
while ($row = $stt->fetch()) {
  //タイトル列を表示
  print($row['title']);
}
$db = NULL;




文字列→日付変換

strtotime(日付時刻文字列);

日付の文字列がUnixタイムスタンプ(1970/1/1 00:00:00から経過した秒数)に変換される

例)
$ts = strtotime('2014/12/26');




日付をフォーマット

フォーマットした日付を文字列で取得

date(フォーマット文字列 [, Unixタイムスタンプ]);

※タイムスタンプは省略可能、その場合は現在日時・時刻となる

例)現在日時をYYYY/MM/DDの形で取得
$str = date('Y/m/d');




タイムスタンプ取得

現在日時・時刻のUnixタイムスタンプを取得

time()

例)
$ts = time;




任意のタイムスタンプ取得

任意の日付・時刻のUnixタイムスタンプを取得

mktime(時, 分, 秒, 月, 日, 年);


例) 2015/1/6 9:18:45秒のタイムスタンプを取得
$ts = mktime(9, 18, 45, 1, 6, 2015);





日付書式

Y4桁の年。例:2014
y2桁の年。例:14
L閏年。1:閏年 0:閏年ではない
mゼロ詰めの月。01~12
nゼロなしの月。1~12
Fフルスペルの月。例:January
M3文字形式の月。例:Jan
t月の日数。28~31
dゼロ詰めの日。01~31
jゼロなしの日。1~31
z年間の通算日。0~365
g12時間単位の時(ゼロなし)。1~12
G24時間単位の時(ゼロなし)。0~23
h12時間単位の時。01~12
H24時間単位の時。00~23
i分。00~59
s秒。00~59
a午前:am 午後:pm
A午前:AM 午後:PM
D3文字形式の曜日。例:Mon
lフルスペルの曜日。例:Monday
NISO-8601形式の曜日。1(月)~7(日)
w曜日。0(日)~6(土)



isset,empty,is_null
if($var)issetemptyis_null
$var=1TRUETRUEFALSEFALSE
$var="";FALSETRUETRUEFALSE
$var="0";FALSETRUETRUEFALSE
$var=0;FALSETRUETRUEFALSE
$var=NULL;FALSEFALSETRUETRUE
$varFALSEFALSETRUETRUE
$var=array()FALSETRUETRUEFALSE
$var=array(1)TRUETRUEFALSEFALSE

リダイレクト

以下のように書けば強制的に別のページに移動する

header('Location: リダイレクト先のURL');

※headerの前に出力(echoなど)をしてはいけない


例) yahooへリダイレクトさせる
header('Location: http://yahoo.co.jp/');




ファイルを開く

fopen(ファイルのパス, オープンモード)

※戻り値としてファイルハンドルを返す


オープンモード

rb…読み取り専用
wb…書き込み専用
w+b…読み書き
ab…追記書き込み
a+b…読み書き(追記)




ファイルを閉じる

fclose(ファイルハンドル);



ファイルに書き込む

fputs(ファイルハンドル, 書き込む文字列);

※fwriteでもOK



ファイルのロック

flock(ファイルハンドル, ロックの種類)

LOCK_SH…共有ロック(書き込み禁止)
LOCK_EX…排他ロック(読み書き禁止)
LOCK_UN…ロックの解除


例)
//ファイルをオープン
$file = fopen('guest.dat', 'ab');

//ファイルをロック
flock($file, LOCK_EX);

//ファイルに書き込み
fputs($file, 'abc');

//ロックを解除
flock($file, LOCK_UN);

//ファイルを閉じる
fclose($file);



@演算子

処理の実行に失敗した場合でも警告を発生させない

※その場合、エラーがあったかどうか分からないので「or die…」を付ける



CSVファイルの読み込み

fgetcsv(ファイルハンドル, 読み込む最大文字列, 区切り文字)

例)タブ区切りファイルの読み込み
$file = @fopen('guest.dat', 'rb') or die('ファイルが開けませんでした');
while ($row = fgetcsv($file, 1024, "\t")) {
  echo $row[0]));
}
fclose($file);


ファイルの読み込み

fgets(ファイルハンドル)



文字を分割

explode(区切り文字, 文字列)




トランザクション処理

DBへの複数回に渡る追加、更新をまとめて処理すること

※大量の件数の処理を行う場合はトランザクションを使ったほうが早い

※InnoDBではないと場合はトランザクションは使えない




トランザクション開始

beginTransaction



トランザクション完了

commit


トランザクションの巻き戻し

rollback


例)CSVファイルの中身を全件DBへ登録
try {
  $db = new PDO('mysql:host=localhost;dbname=php10;charset=utf8', 'phpusr', 'phppass');

  //トランザクション開始
  $db->beginTransaction();

  $file = @fopen('ejdic-hand-utf8.txt', 'rb') or die(' failure!');

  //CSVファイルの中身を全件登録
  while ($row = fgetcsv($file, 5000, ",")) {
    $stmt = $db->prepare('INSERT INTO ejdic (word, mean) VALUES(:word, :mean) ');
    $stmt->bindValue(':word', $row[0]);
    $stmt->bindValue(':mean', $row[1]);
    $stmt->execute();
  }

  //トランザクションを完了
  $db->commit();
} catch (PDOException $e) {

  //例外が発生した場合処理を巻き戻す
  $db->rollBack();
  echo $e->getMessage();
}