- 投稿日:2020-04-21T19:09:28+09:00
[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フレーム遅れた画像が書き出されてしまうので気を付けること。
- 投稿日:2020-04-21T17:53:54+09:00
Unity:2DShootingの作り方 #3
解説動画
・前回:https://qiita.com/simanezumi1989/items/d6c6d9358dd5d096f03f
・コードの差分可視化サイト:https://www.diffchecker.comコード
GameController.csusing 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.csusing 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
対象は以下の方としています。興味のある方はぜひ!
・独学でゲームを作れるか心配な方
・コミケで出展側として参加したい方
・一度でいいから自分のゲームを世に出したい方
・ゲームを作って憧れのゲーム会社に就職したい方
- 投稿日:2020-04-21T12:38:23+09:00
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.htmlCanvas 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/CanvasFaderCanvas Groupの使い道
- UIオブジェクトをまとめて表示/非表示を切り替える
- メッセージウィンドのフェードイン/フェードアウト(Alphaをアニメーションで制御)
- タブ型ナビゲーション画面などで表示を一気に切り替える
- UIオブジェクトの入力をまとめて有効/無効を切り替える
- Loading中にボタンをすべて押せなくする
- 投稿日:2020-04-21T07:19:53+09:00
【Unity】引数を使ったボタンで好きな数字をテキストに表示する
環境
Unity 2019.3.7f1
はじめに
同じような処理のボタンが複数ある場合、
引数を使ったボタンでコードを簡略化できます。こちらは一つの関数で処理しています。
— Maru@個人アプリ開発者 (@Maru60014236) April 20, 2020方法
1.ボタンに割り当てる関数で引数を宣言する。
2.ボタン側で引数の入力値を設定具体例
1~9の引数をそれぞれ設定したボタンを作成し、
ボタンを押すとテキストに
設定した数値が表示されるようにしてみましょう。1.前準備
・ボタンを9つ作成
【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group
https://qiita.com/Maru60014236/items/56d2d53e0a80f1e65e94
で作ったボタン群を使います。
(内容:ボタン並べただけ)
・空のオブジェクトを作成
・新規スクリプト作成
・空のオブジェクトに作成したスクリプトを割り当てる・テキストを作成
テキストは、見やすくするためこのように設定
・フォントサイズ50
・水平オーバーフロー Overflor
・垂直オーバーフロー Overflor
2.ボタンのテキスト変更
ボタンのテキストを1~9に変更。
テキストフォントサイズを50にする。
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.ボタンに関数割り当て
ボタンのクリック時のところに空のオブジェクトを割り当て
数値入力欄が出現するので、
ここにボタンテキストに対応した数値を入力
それぞれのボタンで関数割り当て&数値入力を行ってください。
5.空のオブジェクトのスクリプトに前準備で作成したテキストをアタッチ
実行
— Maru@個人アプリ開発者 (@Maru60014236) April 20, 2020おわりに
引数を使った関数でコードスッキリ!!
- 投稿日:2020-04-21T06:14:15+09:00
【Unity】オブジェクトを等間隔で配置する方法 Grid Layout Group
環境
Unity 2019.3.7f1
はじめに
方法
1.整列させたいオブジェクト群をPanelオブジェクトに入れる
2.そのPanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
3.各種設定行う具体例
実際にやってみましょう。
1.整列させたいオブジェクト群をPanelオブジェクトに入れる
パネルオブジェクト作成
今回Panelに色は不要なので透過を0にして透明にしておきます。
パネルの配下にボタンを入れる
2.PanelオブジェクトにGrid Layout Group(グリッドレイアウトグループ)コンポーネントを追加
Panelを選択
コンポーネントを追加
3.各種設定行う
ボタンのサイズやセルの間隔などが調整できます。
今回はこのように設定しました。
おわりに
これで手作業での等間隔調整とはおさらばです!
- 投稿日:2020-04-21T01:28:28+09:00
[Unity]Spriteの明度を真っ白まで上げられるシェーダーを用意する
はじめに
Unityで表示させたSpriteの明度を変えたい場合、シェーダーを使えばいろいろいじれるのですが
- デフォルトで設定されているマテリアル(Sprites-Default)ではシェーダーがいじれない
- シェーダー(Sprites/Default)がいじれるようになっても暗くはできるが明るくはできない
ということがあり苦戦しました。
内容はかなりシンプル && ネット上に同じような内容がありますが、自分なりの備忘録として残します。環境
- Unity: 2019.3.0f6 64bit
書いた内容
- やりたかったこと
- やったこと(ビルトインシェーダーを編集して自前のシェーダーを作成・適用した手順)
やりたかったこと
Unityでちょっとした画像(Sprites)を表示させたのですが、これを状況に応じてブラックアウト・ホワイトアウトさせたいと思いました。
やったこと
◆シェーダーがいじれない問題
画像の明度を変えるにはシェーダーをいじればいい、というようなことを見かけたので早速いじってみようとしたのですが…そもそもシェーダーがいじれませんでした。
対策:
どうやらデフォルトのマテリアル(Sprites-Default)ではシェーダーがいじれないようです。
おとなしく別のマテリアルを作成・アタッチしたところ、Sprites-Defaultをいじれるようになりました。◆暗くはできるが明るくできない問題
実際にSprites-Defaultでカラーピックをいじってみたところ、画像を暗くはできるのですが明るくはできませんでした。
(RGB値マックスで元画像と同じ状態)
Spriteを元画像以上に明るくするにはSprites-Defaultではだめなようです。
対策:
Unityのビルトインシェーダーを参考に、自前のシェーダーを用意すればよいとのことです。
以下手順です。1.Unityダウンロードアーカイブで任意のバージョンのビルトインシェーダーのソースコードを入手する
自分の環境に近いバージョンのものを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
内の変更を行いました。変更箇所1Shader "Sprites/Default_Custom"変更箇所2CGPROGRAM #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値を上げると画像が白くなります。
これでやりたいことは達成できました。
最後に
シェーダーというものに初めて触れました。(正確には初めて中身をいじりました)
今回いじる範囲についてはできるだけ理解して対応できたとは思いますが、シェーダーというものは非常に奥の深い世界だということも感じました…。
いずれはもっと理解を深めて、自らの作品の表現力をアップさせられる実力をつけたいところです。以上です。