20200421のUnityに関する記事は6件です。

[Unity] 画面をキャプチャしてバイナリで保存する

0. 概要

Unityで大量のシミュレーション画像を生成してBMPで保存していたが、非常に取り回しが悪いので複数画像をバイナリ化して1つのファイルにしたい。そこで、PostRenderを使って描画される画面の左上ピクセルから順にRGBで並んだ配列をバイナリ化して1つのファイルに保存したので、その備忘録を以下に記す。

1. バイナリ画像化

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Capture : MonoBehaviour {
    Texture2D capture_display;
    string fileName = "screenshot\\image.bin";
    System.IO.BinaryWriter writer;
    byte[] yxrgb;
    int ary_size;

    // Use this for initialization
    void Start () {
        capture_display = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
        writer = new System.IO.BinaryWriter(new System.IO.FileStream(fileName, System.IO.FileMode.Append));
        ary_size = Screen.width * Screen.height * 3;
        yxrgb = new byte[ary_size];
    }

    private void OnDestroy()
    {
        writer.Close();
    }

    private IEnumerator OnPostRender() {
            yield return new WaitForEndOfFrame();
            // capture the frame
            RenderTexture.active = Camera.main.targetTexture;
            capture_display.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
            capture_display.Apply();
            for (int i = 0; i < Screen.width; i++)
            {
                for (int j = 0; j < Screen.height; j++)
                {
                    int offset = ( (i * Screen.width) + (j) ) * 3;
                    yxrgb[offset + 0] = (byte)((int)(capture_display.GetPixel(i, j).r * 255));
                    yxrgb[offset + 1] = (byte)((int)(capture_display.GetPixel(i, j).g * 255));
                    yxrgb[offset + 2] = (byte)((int)(capture_display.GetPixel(i, j).b * 255));
                }
            }          
            writer.Write(yxrgb);
    }
}

yield return new WaitForEndOfFrame();を入れておかないと1フレーム遅れた画像が書き出されてしまうので気を付けること。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity:2DShootingの作り方 #3

解説動画

https://youtu.be/v8nQ2RGTlBI

・前回:https://qiita.com/simanezumi1989/items/d6c6d9358dd5d096f03f
・コードの差分可視化サイト:https://www.diffchecker.com

コード

GameController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

// スコアの実装
// ・UIの作成
// ・UIの更新
// ・敵と弾がぶつかったときにスコア加算+更新
// ・Playerと弾の差別化:Tag

// ゲームオーバーの実装
// ・UIを作成
// ・敵とPlayerがぶつかったときにUIを表示
// ・リトライの実装
//  ・Spaceを押したらシーンを再読み込み

public class GameController : MonoBehaviour
{
    public GameObject gameOverText;

    public Text scoreText;
    int score = 0;
    void Start()
    {
        gameOverText.SetActive(false);
        scoreText.text = "SCORE:" + score;
    }

    private void Update()
    {
        if (gameOverText.activeSelf == true)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                SceneManager.LoadScene("Main");
            }
        }
    }

    // スコア加算
    public void AddScore()
    {
        score += 100;
        scoreText.text = "SCORE:" + score;
    }

    public void GameOver()
    {
        gameOverText.SetActive(true);
    }
}
EnemyShip.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 敵の移動:ましたに移動する
// 敵を生成:生成工場を作ってやる
// 敵に弾が当たったら爆発する
// 敵とPlayerがぶつかったら爆発する
// ------
// 敵を左右に揺らせる
// スコアの表示
// 敵を倒したときにスコアを上昇させる
// リスタートの実装

public class EnemyShip : MonoBehaviour
{
    public GameObject explosion; // 破壊のプレファブ

    // GameControllerの入れ物を作る:AddScoreを使いたいから
    GameController gameController; 
    void Start()
    {
        // GameObject.Find("GameController")
        //・ヒエラルキー上のGameControllerという名前のオブジェクトを取得
        gameController = GameObject.Find("GameController").GetComponent<GameController>();
    }

    void Update()
    {
        // 敵の移動:ましたに移動する
        transform.position -= new Vector3(0, Time.deltaTime, 0);
    }

    // 敵に弾が当たったら爆発する
    // 当たり判定の基礎知識:
    // 当たり判定を行うには、
    // ・両者にColliderがついている
    // ・少なくともどちらかにRigidbodyがついている

    // isTriggerにチェックをつけた場合はこちらが実行される
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // collisionにぶつかった相手の情報が入っている:bullet, Player
        if (collision.CompareTag("Player") == true)
        {
            Instantiate(explosion, collision.transform.position, transform.rotation);
            gameController.GameOver();
        }
        else if (collision.CompareTag("Bullet") == true)
        {
            gameController.AddScore();
        }
        Instantiate(explosion, transform.position, transform.rotation);
        Destroy(gameObject);
        Destroy(collision.gameObject);
    }

    /*
    private void OnCollisionEnter2D(Collision2D collision)
    {  
    }
    */
}

スタジオしまづからのお知らせ

スタジオしまづ は「プログラミング未経験でもゲームをリリース」をコンセプトに集まるオンラインサロンを運営しています。
https://camp-fire.jp/projects/view/149191
対象は以下の方としています。興味のある方はぜひ!
・独学でゲームを作れるか心配な方
・コミケで出展側として参加したい方
・一度でいいから自分のゲームを世に出したい方
・ゲームを作って憧れのゲーム会社に就職したい方

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

uGUIのCanvas Group

概要

Unityのバージョンは2018.4

uGUIのCanvas Groupについてのメモです。
Canvas Groupのコンポーネントの内容は以下の通りです。

  • Canvas Group
    • Alpha
    • Interactable
    • Blocks Raycasts
    • Ignore Parent Groups

内容はマニュアルを見ると詳しく載っています。
Canvas Group https://docs.unity3d.com/ja/2018.4/Manual/class-CanvasGroup.html

Canvas Groupの機能

  • Add Component > Layout > Canvas Group で追加
  • Canvas Groupが追加されたオブジェクトと子オブジェクトすべてに設定が影響する(設定は以下)
    • Alphaでオブジェクトの透明度を設定する
    • Interactableで入力を受け付けるか設定する
    • Block RaycastsでコンポーネントをRaycast用のコライダーとするかどうか設定する
    • 後ろに表示しているボタンを押せるようにすることができる
    • Ignore Parent Groupsでこのオブジェクトよりヒエラルキーが上のCanvas Groupの設定の影響を受けるか設定する
    • 特定のオブジェクトだけCanvas Groupの影響を受けないようにすることができる

参考ページ
https://tech.pjin.jp/blog/2017/03/20/unity_ugui_canvas-group/
https://kan-kikuchi.hatenablog.com/entry/CanvasFader

Canvas Groupの使い道

  • UIオブジェクトをまとめて表示/非表示を切り替える
    • メッセージウィンドのフェードイン/フェードアウト(Alphaをアニメーションで制御)
    • タブ型ナビゲーション画面などで表示を一気に切り替える
  • UIオブジェクトの入力をまとめて有効/無効を切り替える
    • Loading中にボタンをすべて押せなくする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】引数を使ったボタンで好きな数字をテキストに表示する

環境

Unity 2019.3.7f1

はじめに

同じような処理のボタンが複数ある場合、
引数を使ったボタンでコードを簡略化できます。

こちらは一つの関数で処理しています。

方法

1.ボタンに割り当てる関数で引数を宣言する。
2.ボタン側で引数の入力値を設定

具体例

1~9の引数をそれぞれ設定したボタンを作成し、
ボタンを押すとテキストに
設定した数値が表示されるようにしてみましょう。

1.前準備
・ボタンを9つ作成
【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group
https://qiita.com/Maru60014236/items/56d2d53e0a80f1e65e94
で作ったボタン群を使います。
(内容:ボタン並べただけ)
image.png

・空のオブジェクトを作成
・新規スクリプト作成
・空のオブジェクトに作成したスクリプトを割り当てる

・テキストを作成
テキストは、見やすくするためこのように設定
・フォントサイズ50
・水平オーバーフロー Overflor
・垂直オーバーフロー Overflor
image.png

2.ボタンのテキスト変更
ボタンのテキストを1~9に変更。
テキストフォントサイズを50にする。
image.png

3.ボタンに割り当てる関数を作成
このようにコードを書きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//UIを使うため追加

public class test : MonoBehaviour
{
    [SerializeField] private Text suuji_text;//Text型の変数suuji_textを宣言

    void Start()
    {        
    }

    //ボタンを押したら実行する関数 実行するためにはボタンへ関数登録が必要
    //int型の引数numberを宣言
    public void Push_Button(int number)
    {
        suuji_text.text =""+ number;//suuji_textに引数の数値を代入
    }
}

4.ボタンに関数割り当て
ボタンのクリック時のところに空のオブジェクトを割り当て
image.png

先程作成した関数を選択
image.png

 
数値入力欄が出現するので、
ここにボタンテキストに対応した数値を入力
image.png

それぞれのボタンで関数割り当て&数値入力を行ってください。

5.空のオブジェクトのスクリプトに前準備で作成したテキストをアタッチ
image.png

実行

おわりに

引数を使った関数でコードスッキリ!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group

環境

Unity 2019.3.7f1

はじめに

ボタンなどを等間隔で配置する方法です。
image.png

方法

1.整列させたいオブジェクト群をPanelオブジェクトに入れる
2.そのPanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
3.各種設定行う

具体例

実際にやってみましょう。

前準備
まずボタンを9つ作成します。
image.png

1.整列させたいオブジェクト群をPanelオブジェクトに入れる
パネルオブジェクト作成
image.png

今回Panelに色は不要なので透過を0にして透明にしておきます。
image.png
パネルの配下にボタンを入れる
image.png

2.PanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
Panelを選択
 
コンポーネントを追加
image.png

グリッドレイアウトグループを選択
image.png

3.各種設定行う
ボタンのサイズやセルの間隔などが調整できます。
今回はこのように設定しました。
image.png

できあがり!
image.png

おわりに

これで手作業での等間隔調整とはおさらばです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]Spriteの明度を真っ白まで上げられるシェーダーを用意する

はじめに

Unityで表示させたSpriteの明度を変えたい場合、シェーダーを使えばいろいろいじれるのですが

  • デフォルトで設定されているマテリアル(Sprites-Default)ではシェーダーがいじれない
  • シェーダー(Sprites/Default)がいじれるようになっても暗くはできるが明るくはできない

ということがあり苦戦しました。
内容はかなりシンプル && ネット上に同じような内容がありますが、自分なりの備忘録として残します。

環境

  • Unity: 2019.3.0f6 64bit

書いた内容

  • やりたかったこと
  • やったこと(ビルトインシェーダーを編集して自前のシェーダーを作成・適用した手順)

やりたかったこと

Unityでちょっとした画像(Sprites)を表示させたのですが、これを状況に応じてブラックアウト・ホワイトアウトさせたいと思いました。
1.png

やったこと

◆シェーダーがいじれない問題
画像の明度を変えるにはシェーダーをいじればいい、というようなことを見かけたので早速いじってみようとしたのですが…そもそもシェーダーがいじれませんでした。
2.png
対策:
どうやらデフォルトのマテリアル(Sprites-Default)ではシェーダーがいじれないようです。
おとなしく別のマテリアルを作成・アタッチしたところ、Sprites-Defaultをいじれるようになりました。

◆暗くはできるが明るくできない問題
実際にSprites-Defaultでカラーピックをいじってみたところ、画像を暗くはできるのですが明るくはできませんでした。
(RGB値マックスで元画像と同じ状態)
3.png
4.png

Spriteを元画像以上に明るくするにはSprites-Defaultではだめなようです。

対策:
Unityのビルトインシェーダーを参考に、自前のシェーダーを用意すればよいとのことです。
以下手順です。

1.Unityダウンロードアーカイブで任意のバージョンのビルトインシェーダーのソースコードを入手する
5.png
自分の環境に近いバージョンのものをDLすればおそらく問題ないと思います。
(少なくとも今回の件については)

2.Sprites-Defaultのソースコードを見つけて編集する
ここで少しつまづきました。
ネット上の記事(例えばこちら)を見てみると
「"DLしたバージョン\DefaultResources\Sprites-Default.shader"のfixed4 frag(v2f IN) : COLORを編集する」
というような内容が見つかったのですが
・自分がDLしたバージョン(Unity2019.3.10f1)ではDefaultResources以下にSprites-Default.shader が無い
  →DefaultResourcesExtra にいました
   (DefaultResourcesとDefaultResourcesExtraの区別って何なんでしょうね…?)
・Sprites-Default.shader の中に編集すべき関数がない
  →#include "UnitySprites.cginc" に実体があるので必要な部分をフック(?)する必要がある
というような違いがありました。

実際に編集した内容は以下の通りです。

Sprites-Default.shader
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Sprites/Default"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
        [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
        [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
        [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
        [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        {
        CGPROGRAM
            #pragma vertex SpriteVert
            #pragma fragment SpriteFrag
            #pragma target 2.0
            #pragma multi_compile_instancing
            #pragma multi_compile_local _ PIXELSNAP_ON
            #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
            #include "UnitySprites.cginc"
        ENDCG
        }
    }
}

上記ソースコードに対し、Shaderの名前変更およびCGPROGRAM内の変更を行いました。

変更箇所1
Shader "Sprites/Default_Custom"
変更箇所2
        CGPROGRAM
            #pragma vertex SpriteVert
            #pragma fragment SpriteFrag_Custom  // 呼び出される関数を変える
            #pragma target 2.0
            #pragma multi_compile_instancing
            #pragma multi_compile_local _ PIXELSNAP_ON
            #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
            #include "UnitySprites.cginc"

            // 基本的にはUnitySprites.cgincからコピー
            sampler2D _MainTex_Custom;
            fixed4 SpriteFrag_Custom(v2f IN) : SV_Target
            {
                // とりあえず指定色をかける
                fixed4 c = SampleSpriteTexture(IN.texcoord) * _Color;
                // 指定色のRGB各値が0.5なら元の色、0.5を超えると白に近づくように調整
                c.rgb = c.rgb * 2.0 + max(fixed3(0,0,0), _Color.rgb - 0.5) * 2.0;
                c.rgb *= c.a;
                return c;
            }
        ENDCG

変更したファイルは"Sprites_Custom_fadeBW.shader"という名前で保存しました。
※BW=ブラックホワイト(ポケモンっぽい)

3.実際に適用
あとは単純に、上記シェーダーをプロジェクトに追加→デフォルト以外のマテリアルでシェーダー選択します。
シェーダーのカラーピックを変更してRGB値を上げると画像が白くなります。
これでやりたいことは達成できました。
6.png

最後に

シェーダーというものに初めて触れました。(正確には初めて中身をいじりました)
今回いじる範囲についてはできるだけ理解して対応できたとは思いますが、シェーダーというものは非常に奥の深い世界だということも感じました…。
いずれはもっと理解を深めて、自らの作品の表現力をアップさせられる実力をつけたいところです。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む