スマートデバイスプログラミング 第9回
カメラ機能を使ってみよう

課題

(1)カメラの画像を画面内に表示させてみましょう。
(2)ボタンを押すと、画像の内容によりスコアが表示されるようにしてみましょう。
(3)ハイスコアが保存できるようにしてみましょう。
(4)その他、プログラムを改良したり、学んだ技術を駆使して、何か面白いことをやってみましょう。
作ったC#のプログラムを添付してください。
(プロジェクトを保存したフォルダのasset以下にあると思います。
コメント欄には、どこまでやったかとハイスコアを書いてください。

  1. 新規プロジェクトを作る(「2D」プロジェクトを選びましょう)
  2. スクリプトを貼りつける、空のゲームオブジェクトを作りましょう(GameObject→Create Empty)
  3. カメラ情報表示用のテキストを作りましょう(GameObject→UI→Text)
  4. 座標はx-200,y0,サイズはw150,h300にしましょう
  5. カメラ画像表示用のイメージを作りましょう(GameObject→UI→RawImage)
  6. 座標はx0,y0,サイズはw300,h300にしましょう
  7. 新規スクリプトを作成しましょう。名前はGameManagerで。
  8. スクリプトを編集しましょう。
    
    //3行目に追加
    using UnityEngine.UI;
    
    //class名が違っていたら上書き
    public class GameManager : MonoBehaviour {
    
    //クラス入ってすぐのところに
    public Text label;
    
    //Start内を下記に
    void Start () {
    
      WebCamDevice[] devices = WebCamTexture.devices;
    
      if (devices.Length > 0){
    
        label.text = "Camera:"+devices.Length+"\n";
        for(int i=0;i <devices.Length;i++) {
          label.text += "ID:"+i+
            " Name:"+devices[i].name+
            " isFront:"+devices[i].isFrontFacing+"\n";
        }
      }
      else {
        label.text = "Error: No Camera";
      }
    }
    
    //Update内を下記に
    void Update () {
    }
    
  9. GameManageをGameObjectにAddComponentして変数labelを作ったTextで埋めます。
  10. 起動すると、テキストエリアにカメラ情報が表示されます。
  11. カメラの数と、各カメラの名前、前面か後面かが表示されます。
  12. 次に、カメラの映像を画面に表示させてみましょう。
  13. スクリプトを編集しましょう。
    
    
    //クラス入ってすぐのところに
    public RawImage canvas;
    WebCamTexture video;
    
    //Start()内、for文の後に追加
      video = new WebCamTexture();
      canvas.texture = video;
      video.Play();
    
  14. 変数canvasにRawImageをドラッグ&ドロップしましょう。
  15. 実行するとカメラ画像が表示されます。
  16. カメラ名、解像度、fps(省略可)の指定が可能です。
  17. 
    
    //生成時の引数を追加してみましょう。(1行入れ替え)
    //video = new WebCamTexture();
    video = new WebCamTexture(devices[0].name,100,100,10);
    
  18. 実行すると、荒い解像度で表示されるようになります。
  19. 解像度が荒くなるので、もう少し細かくしましょう。
  20. 
    //生成時の引数を追加してみましょう。(1行入れ替え)
    //video = new WebCamTexture();
    //video = new WebCamTexture(devices[0].name,100,100,10);
    video = new WebCamTexture(devices[0].name,300,300,10);
    
  21. これで、画像が表示されるようになります。
  1. ボタンを配置して、スコアをカウントできるようにしましょう。
  2. Create→UI→Buttonでボタンを配置
  3. スクリプトを編集
  4. 
    //変数宣言のところに追加
    int score = 0;
    
    //メソッドを一つ追加
    //<は半角に戻してください
    public void calcScore(){
      score = 0;
      for (int x=0; x<300; x++) {
        for (int y=0; y<300; y++) {
          Color32 col=video.GetPixel (x,y);
          if((x>=100&&x<200)||(y>=100&&y<200)){
            score += col.r+col.g+col.b;
          }
          else{
           score -= col.r+col.g+col.b;
          }
        }
      }
      score /= 10000;
      label.text = "score:"+score;
    }
    
  5. 保存してUnityの画面に戻ります。
  6. ボタンが押された時にcalcScoreが呼ばれるようにしましょう
  7. (Inspector窓でボタンの設定を追加します)
  8. (OnClickの欄で「+」を押して、「None」を選んでGameObjectを選択、「NoFunction」を選んでGameManager以下のCalcScore選択)
  9. ボタンを押すとスコアが表示されるようになります。
  10. どうすれば高いスコアになるか、色々試してみてください。
    // ハイスコアを取得する。保存されてなければ0を取得する。 highScore = PlayerPrefs.GetInt (highScoreKey, 0);
  1. 次に、ハイスコアを保存してみましょう。
  2. PlayerPrefsという仕組みを使うと、int,float,stringが保存できるようになります。
  3. スクリプトを編集しましょう
  4. 
    //変数の宣言に追加
    int highScore = 0;
    string highScoreKey="highScore";
    
    //Start()内に追加
    // ハイスコアを取得する。保存されてなければ0を取得する。
    highScore = PlayerPrefs.GetInt (highScoreKey, 0);
    
    //calcScore内でスコアを計算した後に追加
    if(score>highScore){
      highScore=score;
      // ハイスコアを保存する
      PlayerPrefs.SetInt (highScoreKey, highScore);
      PlayerPrefs.Save ();
    }
    label.text= "score:"+score+"\n"+"highScore:"+highScore;
    
    
  5. 保存して実行するとハイスコアが保存去れるようになります。
  6. ハイスコアを更新したらいったん停止して、再度実行してみましょう。
  7. 保存されているのがわかるかと思います。
  8. (以下、400x300でimageとwebCamを用意して、「回転」ボタンを設置した際の 参考ソースです。ご参考まで。)
    
    //変数の宣言を追加。
    bool portrait=false;
    
    //回転ボタンを押した時に呼ぶメソッド
    public void RotateCanvas()
    {
      canvas.transform.Rotate(0, 0, 90);
    
      //※RawImage、webCamを正方形で用意した場合は不要です。
      //※さらに、RawImageをマスクして使う場合に必要な処理になります。
      //※単純に回転すると横幅が足りなくなるので、拡大してあげます。
      //※さらに、RawImageをマスクして使う場合に必要な処理になります。
      //※さらに、RawImageをマスクして使う場合に必要な処理になります。
      portrait = !portrait;
      if (portrait) canvas.transform.localScale = new Vector3(1.333f, 1.333f, 1f);
      else canvas.transform.localScale = Vector3.one;
    }
    

よくある質問

スクリプトを更新したのに、InspectorViewの変数が増えない

プログラムが間違っていてビルドエラーが出ている可能性が高いです。

エディタ上でbuildしてみましょう。

{}の対応が間違っていないか、全角スペースが入っているかなど、確認してみましょう

ビルドエラーが出ていないのに、スクリプトをobjectに追加できない

classの大文字と小文字が違っている可能性があります。

エディタのbuildエラーが出ませんが、Unityでは読み込めない、という状況が確認されています。

保存して再度開いたらブロックやボールが消えた

unityの仕様(不具合)かなと思います。

BG(背景画像)の描画優先度を下げることで解決します。

BGのInspectorViewでOrder in Layerを-1にしてください

(テキストの手順にも追記しておきました)