Lab 7 in Singapore

Unityでのゲーム開発、プログラミング教育、AIに関して。たまにシンガポールのネタも。

Unity Basic

【Unity】Texture への描画を試してみた Part 2

前回軽くTextureへ直接描画をする方法を紹介しました。
http://lab7.blog.jp/archives/2924409.html

今作っているゲームはこの方法を基盤にするものです。
せっかくなので、初心者でも使いやすく、もう少しこの描画ロジックを説明しようかと思います。


まず、Texture への描画ロジックは以下です。
より分かりやすいように、日本語でのコメントいっぱい入れてみました。
移動する GameObjectが、Fieldの Texture上での自分のUV座標を引数に Paint_Lineメソッドを呼び出す形です。

public class Test_Draw : MonoBehaviour {
 // テクスチャは正方形、移動オブジェクトは立方体の前提
 private const int C_TEXTURE_SIZE = 500;//テクスチャの一辺のPixel数
 private const int C_OBJECT_SIZE = 25; //立方体一辺のPixel数
 private Color[] buffer; //色情報操作用のバッファ配列
 private Color OBJECT_COLOR = Color.yellow; //塗る色の指定
 // 塗るテクスチャ座標はオブジェクトの中心座標なので一辺の半分を事前計算
 private int object_Halfsize = (int)( C_OBJECT_SIZE / 2);

 //説明①
 public void Paint_Line (Vector2 point) {
  // UV座標をテクスチャのPixelでの座標に変換
  // この変数をループでの変数に使うので int に型変換
  int point_X = (int) (point.x * C_TEXTURE_SIZE);
  int point_Y = (int) (point.y * C_TEXTURE_SIZE);

  // 現在のTextureの色情報をバッファ配列にコピー
  Texture2D mainTexture
= (Texture2D) GetComponent<Renderer> ().material.mainTexture;
  Color[] pixels = mainTexture.GetPixels(); //説明②
  buffer = new Color[pixels.Length];
  pixels.CopyTo (buffer, 0); //説明③

  //オブジェクトのある X,Y座標(UnityのX,Z座標)部分のPixel座標をループ。
  for(int x = point_X - object_Halfsize;
x < point_X + object_Halfsize; x++){
   for(int y = point_Y - object_Halfsize;
y < point_Y + object_Halfsize; y++){
    // バッファ上でオブジェクトのある Pexel座標の色情報を変換
    buffer.SetValue (OBJECT_COLOR, x + C_TEXTURE_SIZE * y);
   }
  }

  // 色変換をした色情報バッファをテクスチャに反映
  Texture2D drawTexture = new Texture2D (mainTexture.width,
mainTexture.height, TextureFormat.RGBA32, false);
  drawTexture.filterMode = FilterMode.Point;
  drawTexture.SetPixels (buffer); //説明④
  drawTexture.Apply(); //説明⑤
  GetComponent<Renderer> ().material.mainTexture = drawTexture;
 }
}

説明①:
Paint_Lineメソッドの引数 Vector2 pointはテクスチャのUV座標を渡す。
UV座標とは原点 (0,0)がテクスチャの左下で、右上が (1,1)となります。
よって、0~1の範囲と言うことになります。

説明②:
Color[] Texture2D.GetPixels:テクスチャからピクセルの色情報を取得します。

説明③:
CopyTo:配列のコピー。配列のコピーでは=を使うと参照コピーになってしまう。
http://lab7.blog.jp/archives/2651297.html

説明④:
Texture2D.SetPixels(Color[] colors):色情報バッファをテクスチャに反映。
テクスチャにピクセルカラー配列 colors(上記プログラム内ではbuffer)を指定します。

説明⑤:
Texture2D.Apply:SetPixels関数による変更を実際に適用する。

【Unity】Texture への描画を試してみた

オブジェクト上に貼り付けた Textureへ直接描画することを試してみました。
今回は北村愛実さんの以下のブログを参考にさせて頂きました。
http://nn-hokuson.hatenablog.com/entry/2016/12/08/200133

オブジェクトをキー操作して、オブジェクトが通った座標に指定した色を描画しています。



2つのクラスを作っていますが、Test_Drawが描画に関わ
る部分で、描画するオブジェクトにアタッチしてます。Test_Moveの方は、移動するオブジェクトにアタッチして、移動処理と描画する座標をTest_Drawに送っています。
Unity_Texture_Drawing_Test_02

ここでは、描画のメインパートであるTest_Drawのみソースを張り付けておきます。
(Test_Moveは移動処理や座標変換処理だけで単純です。)


public class Test_Draw_01 : MonoBehaviour {
    private Texture2D drawTexture ;     private Color[] buffer;

// Texture size (pixel) and Object size (pixel)     private const int C_TEXTURE_Z = 500;
    private const int C_OBJECT_X = 50;
    private const int C_OBJECT_Z = 50;
    public void Paint_Line (int point_X, int point_Z) {
        // Copy current pixels of texture to buffer         Texture2D mainTexture = 
(Texture2D) GetComponent<Renderer> ().material.mainTexture;         Color[] pixels = mainTexture.GetPixels();         buffer = new Color[pixels.Length];         pixels.CopyTo (buffer, 0);
        // Change pixel color of drawing area         for(int x = point_X - (C_OBJECT_X/2); 
x < point_X + (C_OBJECT_X/2); x++){             for(int y = point_Z - (C_OBJECT_Z/2); 
y < point_Z + (C_OBJECT_Z/2); y++){                 buffer.SetValue (Color.yellow, x + C_TEXTURE_Z * y);             }         }
        // Update pixels of texture with changed pixels         drawTexture = new Texture2D (mainTexture.width, 
mainTexture.height, TextureFormat.RGBA32, false);         drawTexture.filterMode = FilterMode.Point;         drawTexture.SetPixels (buffer);         drawTexture.Apply();         GetComponent<Renderer> ().material.mainTexture = drawTexture;     } }

Test_Draw内の Textureへ書き込む部分は、以下のような流れになっています。
まず元のTextureの各ドットの色情報を取得して、bufferにコピー。
受け取った移動オブジェクトの位置を中心にオブジェクトのサイズ分の領域にあるピクセルの色情報をbuffer上で直接変更。
(この部分を変更すればどうにでも描画できる。)
そして、最後に色変更をした bufferを実際のTextureに上書き。

上記の buffer上で色情報を直接変更する部分を書き換えて、このメソッドを座標を引数としてコールすれば Texture上で好きなように描画ができるわけです。
お試しあれ。

【Unity】C#での配列のコピー

C# ネタで誰かの助けとなるとよいのでシェアします。
C# での配列のコピーに関して。
またやらかしたので、自分への備忘としても書いておきます。

C# の配列のコピー。たとえば配列 Array_A の中身を配列 Array_B にコピーして、別々にそれらを使用する場合。
Array_B=Array_A;
当然こうやってはいけません。

初級者でも常識でしょうが、これは参照を指定しているだけです。よって、Array_B を変更すると Array_A も変更されてしまいます。(と言うより、Array_A を変更しています。)

実際は、CopyToを使用する必要があります。
Array_A.CopyTo (Array_B, 0);

(コピー先の配列名、開始インデックス)

また、CopyToは1次元の配列だとよいですが、多次元だと以下のようなエラーが出ます。
Error_ArrayCopy_01

多次元の場合は Array.Copy で大丈夫です。
using.System;
Array.Copy (Array_A, 0, Array_B, 0, 40);

(コピー元の配列名、開始インデックス、コピー先の配列名、コピー先開始インデックス、コピーする要素数)

注意点はこちらは Using.System が必要となります。

参照を指定しまい最初は偶然うまくいき、後から結果がおかしくなりデバックで苦労することはもう避けたいです。


【Unity】カメラからの Raycast を試してみた

前回【Physics.Raycast を試してみた】と題して、ゲームオブジェクトからのRayの照射を試しました。
(【Physics.Raycast を試してみた】:http://lab7.blog.jp/archives/2256403.html )

今回は、Raycastの使用例のもう1つとして、カメラからのRayの照射を試します。
参考: https://docs.unity3d.com/ja/540/Manual/CameraRays.html

【カメラからのRayの照射】
3D空間上に散らばったオブジェクトをマウスでクリックすると形と色(オブジェクト名とタグ)が現れます。



このCameraに適用したRaycastのC#ソースは以下です。

public class Raycast_Test_2 : MonoBehaviour {
    public Text textObjectName;     public Text textObjectTag;
    void Update () {
        // If mouse button is clicked         if (Input.GetMouseButtonDown(0)) {
            // Create Ray             Ray ray = 
Camera.main.ScreenPointToRay(Input.mousePosition);             RaycastHit hit = new RaycastHit();
            // If Ray hit something             if (Physics.Raycast(ray, out hit, 10)) {
                // Show Name and Tag of the object                 string objectName = hit.collider.gameObject.name;                 textObjectName.text = objectName;                 string objectTag = hit.collider.gameObject.tag;                 textObjectTag.text = objectTag;             }         }     } }


【Unity】Physics.Raycast を試してみた

ある位置からある方向に存在するゲームオブジェクトを判定させるのに Raycast を使います。
イメージとしてはある位置から仮想のレーザービームを照射して、それがヒットした際のオブジェクト情報を取得します。

それには、
1.Scene上のゲームオブジェクトからある方向に存在するオブジェクトを判定させる。
    (ゲームオブジェクトからのRayの照射)
2.Cameraから画面上のある位置の先に存在するオブジェクトを判定させる。
    (カメラからのRayの照射)
のような使い方があります。

具体的にはこれらを用いて、シューティングゲームで敵AIから見て自分との間に障害物がなければ敵AIが自分を撃ってくるとか、3D空間上にあるゲームオブジェクトを画面上からマウスで選択するとか、アイデア次第でいろいろなことができます。

では試してみましょう。
(参考: https://docs.unity3d.com/jp/540/ScriptReference/Physics.Raycast.html

【ゲームオブジェクトからのRayの照射】
適役のUnity標準のThirdPersonControllerが、Playerがコントロールしているユニティちゃんの方向を常に向いています。
もし二人の間に障害物がなくユニティちゃんを直視できる状態であるとRayのビームを赤く表示させます。

以下の実行画面は、左がGame画面、右がScene画面です。


このThirdPersonControllerに適用したRaycastのC#ソースは以下です。

public class Raycast_Test : MonoBehaviour {
    public Transform target;     RaycastHit hit;
    void FixedUpdate()     {                 // Face to target direction         transform.rotation = 
Quaternion.LookRotation (target.position - transform.position);
        // Create 'Ray' to forward direction         Ray ray = new Ray(transform.position, transform.forward);
        // If Ray hit someting         if (Physics.Raycast (ray, out hit, 15)) {
            // If the object is "Player"             if (hit.collider.tag == "Player")              {
                // Draw Red Line                 Debug.DrawLine(ray.origin, hit.point, Color.red);
            
}          }     } }

また、カメラからのRayの照射はまた次回試します。

【Unity】uGUI:Canvas の各種描画モードを試す

現在UnityでUIを設定するには、標準搭載されているuGUIを使用するのが通常です。
シーン内に配置されたuGUIのUIオブジェクトは、Canvasと言うオブジェクトによって描画されます。よって、UIオブジェクトを使用する際 Canvasは必須となります。

今回は、そのCanvasの3つの描画モードを試してみました。
(参考: https://docs.unity3d.com/jp/540/Manual/class-Canvas.html

Canvasには以下のような3つの描画モード(Render Mode)があります。
  ・ Screen Space - Overlay
  ・ Screen Space - Camera
  ・ World Space
Unity_Canvas_Test_11


3つの描画モードを試したScene上のオブジェクトは、基本的に共通で以下のような順番で並べました。
Main Camera-青の柱Canvas(Text-Image)緑の柱黄の柱―Sub Camera
Unity_Canvas_Test_03

【 Screen Space - Overlay 】
このモードはCanvasがどこにあっても、アクティブなCameraの正面に画面の大きさにあった形で描画されます。
よって、これはScene上のCanvasの位置はあまり関係ありません。

「上:Main Cameraの映像」「下:Sub Cameraの映像」
Unity_Canvas_Test_06Unity_Canvas_Test_07

「プロパティ」
Unity_Canvas_Test_12

【 Screen Space - Camera 】
このモードは指定したCameraから指定された距離だけ離れた位置にCanvasが表示されます。
Cameraかの距離を青の柱と緑の柱間くらいにしたので、その場所にCanvasが表示されています。しかし、指定されていないCameraにはCanvasが反映されません。

「上:Main Cameraの映像」「下:Sub Cameraの映像」
Unity_Canvas_Test_01Unity_Canvas_Test_02

「プロパティ」
Unity_Canvas_Test_04

【 World Space 】
このモードはCanvasがScene上の他のオブジェクトと同じような扱いで表示されます。
CanvasはRect Transformで指定した位置に表示されるので、Sceneの表示と同じように青と緑の柱の間に現れました。
前から見るのと後ろから見るのでは映像は逆になりますが、Canvas内の各UIオブジェクトの表示順序はHierarchyで指定した順番です。

「上:Main Cameraの映像」「下:Sub Cameraの映像」
Unity_Canvas_Test_09
Unity_Canvas_Test_10

「プロパティ」
Unity_Canvas_Test_16

【Unity】Transformを使用した移動を試す

前回、Rigidbodyを使用した移動方法を試しました。
http://lab7.blog.jp/archives/2041666.html
今回はTransformを使用した基本的な移動方法を試します。

【次の瞬間の移動先を指定する】
  • position: ワールド空間の位置指定
  • localPosition: 親からの相対的な位置指定 (親がない場合、position と同じ)
  • Translate: 指定した方向と距離に移動

(参照元はUnityマニュアル。
https://docs.unity3d.com/jp/540/ScriptReference/Transform.html

青:position緑:localPosition赤:Translate


このC#ソースは以下です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTest_2 : MonoBehaviour {
    Vector3 moveDirection;
    void Start () {
       moveDirection = transform.up;
    }
    void FixedUpdate() {
        if (this.name == "Position")
           // positionの設定
           transform.position 
= transform.position + moveDirection * Time.deltaTime;
        else if (this.name == "LocalPosition")
           // localPositionの設定
           transform.localPosition 
= transform.localPosition + moveDirection * Time.deltaTime;
        else if (this.name == "Translate")
           // Translateの設定
           transform.Translate(moveDirection * Time.deltaTime);
    }
}


Game App from Lab7
GooglePlay_Top_2 (Android, iOS) GooglePlay_Top_2 (Android, iOS) GooglePlay_Top_2 (Windows)
Contact [お問い合わせ]
Blog Visitors [訪問者数]
  • 累計: