【社会人用】ノートの取り方
今回も、特に書くことが無いので
最高に見やすいノートの取り方について書きたいと思います。
社会人になって、勉強ではなく様々な目的で使われるノート。
「 探しやすい・見やすい・加筆しやすい 」をモットーに
ノートの書き方を考えてきた、研究結果をまとめていきます。
メモ用と見返し用の2種類のノートを持つ
まず大事なのは、その場で 急いでメモを取るメモ用ノート
メモ用ノートを見やすい様にまとめる見返し用ノート
の2種類のノートを持つようにしましょう。
※メモ用ノートは、使用済み印刷物の裏面とかがオススメです。
作業の工程等、急いでメモしないといけない時に
一々見た目を気にしてメモできるわけがないです。
教えてもらっているときは、メモすることではなく、
作業を理解することに頭をフルに使いましょう。
全て聞き終わった後に、反復練習を含めて見返し用ノートに
綺麗にまとめましょう。後で見返せるようにまとめるのではなく
ノートにまとめることで体で覚えることができます。
今回は、見返し用ノートの書き方について解説します。
ノート書き方例
ノートの取り方例です。プロジェクトの残件をまとめて書いています。
- 一番上にカテゴリを大きく書く
このカテゴリは、見返した時の検索用です。
[]等のマークで囲うことで、
パラパラ見るだけでそのページのカテゴリが分かります。
大事なことは、左右2ページを1つのカテゴリにまとめることです。
カテゴリは左側のページにしか書いてはいけません!
なぜなら、ページを検索するとき、
パラパラめくりながら見ると、左側のページにしか目が行かないからです。
この手法を使えば、圧倒的にページの検索時間が短縮されます。
- 余白を持たせて書く
社会に出て学生時代とのノートの取り方の違いは、
一度書かれた内容に追記する場面が多々あるということです。
例えば、とりあえず質問だけまとめてノートにとっておき、
後日質問の返答をもらった時、前に記入した質問部分に加筆するのがベストです。
臨機応変にノートの内容を書き換えることが社会人ノートでは必須になります。
だからこそ、アホみたいに余白を作ってノートを書きましょう!
ノートを大きく使うことで、必ず見やすいノートになります。
※前述した、2ページで1カテゴリ使う事も
ノートを大きく使う第一歩になるんです。
以上が、私が社会に出て考え抜いたノートの取り方です。
皆さんも見やすさを追求した書き方を考えてみてください!
【VBA】自作汎用関数まとめ
今回は、書くことがないのでVBAのコードを公開したいと思います。
VBAでよく使う関数を一つのファイルにまとめて管理しています。
ファイル管理することで、インポートして呼ぶだけなので便利ですよ。
コード内容
関数をまとめるときの注意!
ファイルにまとめる方法は、
とても便利ですが一つだけ大きな問題があります。
参照設定の追加ができない!ということです。
関数を呼んだ時に、参照の追加ができないとエラーが出てしまい、
対応が面倒くさいことになってしまいます。
対応策としては、
Set fso_Default = CreateObject("Scripting.FileSystemObject")
のように、関数上でオブジェクトを定義する方法です。
関数を組み込む際に、「参照の追加」が必要になった時は、
追加せず、関数上で定義するやり方で組み込みを行いましょう。
このやり方は、他人にマクロを配布する時にも有効なやり方です。
以上です。
GitHubとの連携もやってみたかったので、良い練習になりました。
VBAは組み方次第で処理時間がえげつないぐらい変わるので
処理の速い組み込み方を皆さまと共有できればと思います。
UnityとWindowsフォームアプリの意識の違い
今回は、つい最近Unityで組み込みやってて
同時並行でWindowsフォームアプリでツールを作っていた時に
ハッ!としたことについてお話します。
一週間前にハッとしてから今まで内容をまとめようと
業務をほっぽり出して考えたのですが、全く考えがまとまらなかったので
意味の分からない部分が多々あると思います。
お手数をお掛けして申し訳ありませんが、くみ取ってください。。。
シーンではなく、オブジェクトに対してスプリクトを作る!
さっそく意味不明なタイトルです・・・
Windowsフォームアプリの仕様としまして、
- オブジェクトのイベント関数は一つのクラスファイル(【例】Form1.cs)にまとめる
- オブジェクトを呼び出すとき、必ずフォームをベースとして呼び出さないといけない
上記2つの仕様があります。この仕様に慣れると、
Unityの組み込みの自由度に、無意識のうちに枷を付けてしまうことになります。
Unityに出来てWindowsフォームアプリでできないこと・・・
『 オブジェクトに対してクラスファイルを設定できる 』です!
・・・だからなんなのか?
例として、ボタンを押すとエラー画面が出る簡単なアプリを作るとします。この仕様を、「Windowsフォームアプリ的思考(個人的)」と
「Unity的思考(個人的)」の2パターンで組み込んでみます。
Windowsフォームアプリ的思考の組み込み
▼ Test01_Main.cs
//============================================== // 変数 //============================================== public static GameObject Obj_Err; public static Text Txt_Value; //============================================== // 起動時イベント //============================================== void Start() { Obj_Err = GameObject.Find("Canvas/Panel_Error").gameObject; Txt_Value = Obj_Err.transform.Find("Value").GetComponent<Text>(); Obj_Err.SetActive(false); }
上記ソースを空オブジェクトに設定します。
シーン起動時に、
シーン内で変更を加えるオブジェクトを全て変数に定義することで
オブジェクトをまとめて管理できます。
▼ Test01_Tap.cs
//============================================= // エラー画面表示イベント //============================================= public void Tap_ErrorWindow_Open() { Tst_Main.Obj_Err.SetActive(true); Tst_Main.Txt_Value.text = "エラーの内容!"; } //============================================= // エラー画面閉じるイベント //============================================= public void Tap_ErrorWindow_Close() { Tst_Main.Obj_Err.SetActive(false); }
上記ソースが、「エラー画面の表示開始・終了」の処理です。
ボタン等のイベントで呼び出す関数をまとめて一つのファイルにしておく事で、
ボタンに設定するスプリクトファイルが共通化されます。
後は、各ボタンにInspectorウィンドウから設定します。
以上が、Windowsフォームアプリ的思考で組み込んでみたパターンです。
特徴としましては、
- オブジェクトの管理を1シーンでまとめて行っている(Test01_Main.cs)
- イベント関数の管理を1シーンでまとめて行っている(Test01_Tap.cs)
1シーンごとにまとめる方が見やすいし管理しやすい!。という考え方が
フォームアプリの組み込み方に毒された意固地な思考なんです。
※決して悪くはないとも思っています・・・
Unity的思考の組み込み
「Test02_Main.cs」は作りません
▼ Test02_Tap.cs
//============================================== // エラー画面表示イベント //============================================== public void Tap_ErrorWindow_Open() { Test02_ErrCntrl.SetOpenErrMsg("エラーの内容!"); }
エラー画面を出力するボタンの関数のみ記入しておきます。
共通オブジェクトとしてまとまらなかった
オブジェクトのイベントをこのファイルにまとめます。
▼ Test02_ErrCntrl.cs
// ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 変数定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ //=============================================== // 変数 //=============================================== public static GameObject Obj_Err; public static Text Txt_Value; // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // イベント関数 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ //============================================= // 起動時 //============================================= void Start () { Obj_Err= gameObject; Txt_Value = transform.Find("Value").GetComponent<Text>(); Button Btn_Ok = transform.Find("Btn_Ok").GetComponent<Button>(); Btn_Ok.onClick.AddListener(Tap_OkButton); Obj_Err.SetActive(false); } // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // サブルーチン関数 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ /********************************************************************* メソッド : Tap_OkButton 概要 : OKボタンタップ **********************************************************************/ public void Tap_OkButton() { Obj_Err.SetActive(false); } /********************************************************************* メソッド : SetOpenErrMsg 概要 : エラーパネル表示処理 **********************************************************************/ public static void SetOpenErrMsg( string str_Msg_Set) { Obj_Err.SetActive(true); Txt_Value.text = str_Msg_Set; }
上記ファイルは、エラー画面のパネルに設定します。
エラー画面のパネル以下のオブジェクトを1つにまとめて管理しています。
シーンごとにまとめるのではなく、同カテゴリのオブジェクトごとにまとめる!
これが、Windowsフォームアプリに出来なくてUnityにできる組み込み方だと思います。
Unity的思考の組み込み方の利点
ではこの組み込み方のなにが良いのでしょうか?
まとめて管理したほうが見やすそうでは?そんなことないです!
オブジェクトごとにまとめる利点を思いつくだけまとめました。
- 1つの cs ファイルで完結させることができる
1つのシーンには、様々な役割を持つオブジェクトがたくさんあります。
まとめて管理しようとすると、管理変数が膨大な数になってしまい、
どれがどれか分かりずらくなってしまいます。
1つの役割ごとにcsファイルをまとめることで
変数の中身も分かりやすく、
ほかのcsファイルとのつながりが最小限のやり取りで済みます!
※この辺の説明が上手くまとまらなかったんです・・・すみません((´;ω;`)
- 役割でまとめることで、別シーン・別プロジェクトでも使えるプレハブが作れる
1シーンでまとめると、似たような役割のオブジェクトを
別シーンで作りたいとき、スクリプト部分が移行できないです。
しかし、1つの cs ファイルで完結できていればそのcsファイルは
別のシーンでも問題なく動くのです!
より自由度の高いプレハブを作ることができるのです!
以上が、今回ハッ!としたことです。
これに気付いた時、洗脳が解けた感覚がしましたー
無意識のうちに組み込み方にダメな癖がついていて、
頭の固い自分の脳みそをぶんなぐってやりたいです。。。
スワイプの向きに弾を発射【Android用】【ロックマン風】
今回は、横スクロールアクション等で使えそうな
フリックした方向に弾を発射する仕様を
解説用に1から作ってみたいと思います。
※エミュレータ・実機で動作できるように弾発射以外の部分もたくさん書いたので、
発射部分のみ見たい方は「 目次:弾発射に関するコードの解説 」に飛んでください。
追記
【Unity】Android用フリック対応ボタン作った - のにっき
上記サイトで、フリック角度や方向を簡単に取得できるボタンの
ユニティパッケージ公開してます!この記事と合わせて見てみてください。
画像準備
- キャラ画像
適当にパワポで書きました
発射に合わせてアニメーションを付けようと思ったので
待機・発射用の画像を用意しました。
- ボタン画像
下記サイトの素材をお借りしました。
落とした画像をボタンっぽくして1枚の画像にしてます。
銃弾のフリーアイコン4 | アイコン素材ダウンロードサイト「icooon-mono」 | 商用利用可能なアイコン素材が無料(フリー)ダウンロードできるサイト
- 弾画像
下記サイトの「メテオ」の素材をお借りしました。
落とした画像をパワポでまとめて1枚の画像にしてます。
フリーエフェクト素材 - ゲーム素材 | ランスタのフリーBGM、効果音、ゲーム素材、3DCG
オブジェクト作成
- オブジェクト作成・配置
弾を発射するように適当にステージ・キャラ・ボタンを作成していきます
下図で注意が必要なことは、画面枠外にオレンジ色の枠を作っていることです。
これは、発射した弾が消えないと画面外で無限に動き続けるので、
弾の消える範囲を作っています。
画面外に作ったのは、画面外の敵にもある程度影響を与えたいためです。
- 弾丸オブジェクトについて
今回は、弾丸のプレハブを事前に10個作っています。
この理由は、発射時に「Resources.Load」で弾丸プレハブを作成するより、
オブジェクトを作っておいて、表示の切り替えでやりくりする方が処理が早いからです。
あと、見やすくて管理が楽です。
- Tagの追加
各オブジェクトがぶつかった際の種類を判別する「Tag」
このTagを追加していきます。※テスト用なので大雑把に追加してます。
Tag 0:Ground・・・・・地面
Tag 1:Wall・・・・・・壁
Tag 2:Bullet・・・・・・弾
Tag 3:Chara_Main・・・メインキャラ
Tag 4:OutLine・・・・・外枠
- 各オブジェクトの設定内容
オブジェクトに中身を設定していきます。
※赤枠の部分が追加した内容になります。
- キャラ、弾丸のアニメーション管理
キャラ:基本は待機アニメがループで流れて、発射時に発射アニメが流れる
弾丸:弾丸アニメが無限ループで流れる
スクリプト作成【ファイル作成】
いよいよ、弾を発射させる処理の部分を解説していきます。
まずは、スクリプトファイルを作成していきましょう。
▼作成するファイル名と、設定するオブジェクト名
・Ply_Bullet_Cntrl・・・「Nd_Bullet_0~9」に設定
→弾丸の衝突処理を記入
・Ply_Main・・・「ScriptCntrl」に設定
→エディター上で設定する変数、割り込みイベント等を記入
・Ply_TapEv・・・「Btn_Shot」に設定
→ユーザー操作(イベント)で呼び出す関数を記入
・Ply_Cns・・・設定しない
→全スクリプトで共通に使われる「変数・定数・クラス・関数」を記入
・Ply_Timer・・・設定しない
→タイマー系のイベントで呼ばれる関数を記入
スクリプト作成【コード記入】
説明がいる部分と要らない部分があってややこしいので、
とりあえず説明なしでソースコードを全部記入します。
必要な説明は後ろで行います。
・Ply_Bullet_Cntrl
using System.Collections; using System.Collections.Generic; using UnityEngine; using static Nm_Play.Ply_Cns; public class Ply_Bullet_Cntrl : MonoBehaviour { //******************************************************************************* // 衝突時に呼ばれるイベント //******************************************************************************* private void OnTriggerEnter2D(Collider2D col_Get) { //============================================================ // 衝突判定 ※衝突オブジェクトのタグで判定している //============================================================ if ((col_Get.gameObject.tag == Df_TagName[Df_Tag_No]) || (col_Get.gameObject.tag == Df_TagName[Df_Tag_MainC])) { return; } //============================================================ // 変数定義 //============================================================ SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //============================================================ // 衝突した弾丸オブジェクトを非表示 //============================================================ int i_SetId = 0; i_SetId = int.Parse(this.name.Replace(Df_Bullet_Name, "")); ObjIf.BulletIf.SetBulletNd_End(i_SetId); } }
・Ply_Main
using System.Collections; using System.Collections.Generic; using UnityEngine; using static Nm_Play.Ply_Cns; using static Nm_Play.Ply_Timer; public class Ply_Main : MonoBehaviour { // ■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 変数定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□ public GameObject Obj_Canvas_UI; public GameObject Obj_Canvas_Back; public GameObject Obj_Back; public Sprite[] Spr_Btn_On; public Sprite[] Spr_Btn_Off; // ■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 【イベント】関数一覧 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□ //***************************************************** // 開始時 //***************************************************** void Start() { //================================================= // オブジェクトクラス初期化 //================================================= // クラス初期化 Cls_ObjAll = new Obj_All(Obj_Canvas_UI, Obj_Canvas_Back, Obj_Back, Spr_Btn_On, Spr_Btn_Off); Cls_SceneOneIf = new SceneOneIf(); } //**************************************************** // 割り込み関数 //**************************************************** void FixedUpdate() { //------------------------------------------------ // 弾丸管理 //------------------------------------------------ if (Cls_SceneOneIf.cls_BtnIf[Df_BtnId_Shot] != null) { SetBullet_Shot(); } } }
・Ply_TapEv
using System.Collections; using System.Collections.Generic; using UnityEngine; using static Nm_Play.Ply_Cns; using static Nm_Play.Ply_Timer; public class Ply_TapEv : MonoBehaviour { /***************************************************************************** モジュール名: Tap_Shot_ 概要 : ショットボタン押下・離す処理 *****************************************************************************/ public void Tap_Shot_On() { //================================================================== // 変数定義 //================================================================== SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //================================================================== // ボタン押下処理 //================================================================== // ボタン変数を設定 ObjIf.BulletIf.i_ShotWait = 0; SceneIf.cls_BtnIf[Df_BtnId_Shot] = new BtnTapIf(Df_BtnId_Shot); // 画像設定 ObjIf.SetBtnImage(true, Df_BtnId_Shot); } public void Tap_Shot_Off() { //================================================================== // 変数定義 //================================================================== SceneOneIf SceneIf = Cls_SceneOneIf; //================================================================== // ボタン離す処理 //================================================================== // ボタン情報を変数に格納 SceneIf.cls_BtnIf[Df_BtnId_Shot] = null; // 画像設定 Cls_ObjAll.SetBtnImage(false, Df_BtnId_Shot); } }
・Ply_Cns
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace Nm_Play { public class Ply_Cns : MonoBehaviour { // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 変数定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ //======================================================================= // 変数 //======================================================================= public static Obj_All Cls_ObjAll; public static SceneOneIf Cls_SceneOneIf; //======================================================================= // 定数 //======================================================================= //----------------------------------------------------------------- // ボタン管理系 //----------------------------------------------------------------- // ボタン管理用ID public static int Df_BtnId_Shot = 0; public static int Df_BtnId_Max = 1; //----------------------------------------------------------------- // 弾丸管理系 //----------------------------------------------------------------- // 弾丸プレハブ名 public static string Df_Bullet_Name = "Nd_Bullet_"; // 弾プレハブ最大数 public static int Df_Bullet_Max = 10; // 弾発射ウェイト public static int Df_Bullet_Wait = 10; public static int Df_Bullet_Wait2 = 20; //----------------------------------------------------------------- // アニメータートリガー管理系 //----------------------------------------------------------------- // メインキャラ public static string Df_Trg_Main_Gun = "Trg_Shot"; //----------------------------------------------------------------- // 管理 //----------------------------------------------------------------- public static int Df_Tag_No = 0; public static int Df_Tag_Grnd = 1; public static int Df_Tag_Wall = 2; public static int Df_Tag_Blet = 3; public static int Df_Tag_MainC = 4; public static int Df_Tag_OutL = 5; public static string[] Df_TagName = new string[] { "Untagged", "Ground", "Wall", "Bullet", "Chara_Main", "OutLine" }; // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■■□■□■□ // // クラス定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■■□■□■□ /************************************************************************** * クラス名 : Obj_All 概要 : 全オブジェクト情報 **************************************************************************/ public class Obj_All { //===================================================================== // 変数定義 //===================================================================== //--------------------------------------------------------------- // ホーム画面 //--------------------------------------------------------------- public GameObject MainChara_Obj; public Transform MainChara_Posi; public Animator MainChara_Ani; public Image[] Btn_Sprite_Set; public Sprite[,] Btn_Sprite_Get; public BulletIf BulletIf; /************************************************************************** コントラクタ **************************************************************************/ public Obj_All ( GameObject Canvas_UI, GameObject Canvas_Back, GameObject Obj_Back, Sprite[] Spr_Btn_On, Sprite[] Spr_Btn_Off ) { //================================================================== // オブジェクト設定 //================================================================== //------------------------------------------------------------ // キャラ関係 //------------------------------------------------------------ MainChara_Obj = Obj_Back.transform.Find("Material/Chara_Main").gameObject; MainChara_Posi = MainChara_Obj.GetComponent<Transform>(); MainChara_Ani = MainChara_Obj.GetComponent<Animator>(); //------------------------------------------------------------ // バレット関係 //------------------------------------------------------------ BulletIf = new BulletIf(Obj_Back); //------------------------------------------------------------ // ボタン関係 //------------------------------------------------------------ // オブジェクト変数 Btn_Sprite_Set = new Image[Df_BtnId_Max]; Btn_Sprite_Set[Df_BtnId_Shot] = Canvas_UI.transform.Find("Panel_Btn/Btn_Shot").GetComponent<Image>(); // 貼り付け用ボタン画像 Btn_Sprite_Get = new Sprite[2, Df_BtnId_Max]; for (int i_Flg = 0; i_Flg < 2; i_Flg++) { // 貼り付ける画像配列取得 Sprite[] Spr_Set; if (i_Flg == 0) { Spr_Set = Spr_Btn_On; } else { Spr_Set = Spr_Btn_Off; } // 画像を変数に格納 for (int i_Type = 0; i_Type < Df_BtnId_Max; i_Type++) { Btn_Sprite_Get[i_Flg, i_Type] = Spr_Set[i_Type]; } } } /******************************************************************** メソッド名 : SetBtnImage 概要 : ボタン画像設定 ********************************************************************/ public void SetBtnImage(bool bl_IsOn, int i_BtnId) { int i_Flg = 0; if (bl_IsOn == false) { i_Flg = 1; } Btn_Sprite_Set[i_BtnId].sprite = Btn_Sprite_Get[i_Flg, i_BtnId]; } } /******************************************************************** * クラス名 : BulletIf 概要 : 弾丸情報 ********************************************************************/ public class BulletIf { //=============================================================== // 変数定義 //=============================================================== public int i_SetId = 0; public int i_BltCnt = 0; public int i_ShotWait = 0; public Dictionary<string, int> Dic_NameId = new Dictionary<string, int>(); public List<GameObject> l_Obj_Object; public List<Rigidbody2D> l_R2d_Vctl; /********************************************************************* コントラクタ *********************************************************************/ public BulletIf(GameObject Obj_Base) { // 変数初期化 i_SetId = 0; i_BltCnt = 0; i_ShotWait = 0; Dic_NameId = new Dictionary<string, int>(); l_Obj_Object = new List<GameObject>(); l_R2d_Vctl = new List<Rigidbody2D>(); // 変数設定 for (int i_LpCnt = 0; i_LpCnt < Df_Bullet_Max; i_LpCnt++) { // 事前に作成していた10個のプレハブオブジェクトを変数に格納 string str_Name = "Material/Bullets/" + Df_Bullet_Name + i_LpCnt.ToString(); Dic_NameId.Add(str_Name, i_LpCnt); l_Obj_Object.Add(Obj_Base.transform.Find(str_Name).gameObject); l_R2d_Vctl.Add (l_Obj_Object[i_LpCnt].transform.GetComponent<Rigidbody2D>()); // 発射までは非表示 l_Obj_Object[i_LpCnt].SetActive(false); } } /*********************************************************************** メソッド : SetBulletNd_Stat 概要 : 弾丸発射処理 ***********************************************************************/ public void SetBulletNd_Stat() { //================================================================== // 変数定義 //================================================================== Obj_All ObjIf = Cls_ObjAll; //================================================================== // 表示開始処理 //================================================================== // 弾数カウンタ加算 i_BltCnt = i_BltCnt + 1; // 表示ID設定 i_SetId = i_SetId + 1; if (i_SetId >= 10) { i_SetId = 0; } // 位置をキャラに合わせて表示ON l_Obj_Object[i_SetId].transform.position = ObjIf.MainChara_Obj.transform.position; l_Obj_Object[i_SetId].SetActive(true); // 速度追加 SetBulletSpeed(l_Obj_Object[i_SetId], l_R2d_Vctl[i_SetId]); } /************************************************************************ メソッド : SetBulletNd_End 概要 : 弾丸消去処理 ************************************************************************/ public void SetBulletNd_End(int i_EndId) { // ぶつかったオブジェクトを非表示にする l_Obj_Object[i_EndId].SetActive(false); } /************************************************************************ メソッド : SetBulletSpeed 概要 : 弾丸速度設定 ************************************************************************/ public void SetBulletSpeed(GameObject Obj_Set, Rigidbody2D R2d_Set) { //===================================================================== // 変数定義 //===================================================================== float f_Speed = 10f; float f_Kakudo = 0f; Vector2 Vct2_Stat, Vct2_End; Vector2 Vct2_Cal_S, Vct2_Cal_E, Vct2_Cal_Set; SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //===================================================================== // 速度追加 //===================================================================== //--------------------------------------------------------------- // 角度設定 //--------------------------------------------------------------- // 開始・終点座標から角度計算 Vct2_Stat = SceneIf.cls_BtnIf[Df_BtnId_Shot].GetNowTapPoint(); Vct2_End = SceneIf.cls_BtnIf[Df_BtnId_Shot].vct3_StatPosi; Vct2_Cal_S = new Vector2(1, 0); Vct2_Cal_E = Vct2_Stat - Vct2_End; f_Kakudo = Vector2.Angle(Vct2_Cal_S, Vct2_Cal_E); // 座標から向き設定 if (Vct2_Stat.y - Vct2_End.y < 0f) { f_Kakudo = f_Kakudo * (-1f); } // 座標が同じなら前に発射書き換え if (Vct2_Stat == Vct2_End) { f_Kakudo = 0; } //--------------------------------------------------------------- // 速度追加 //--------------------------------------------------------------- Vct2_Cal_Set.x = Mathf.Cos(Mathf.Deg2Rad * f_Kakudo) * f_Speed; Vct2_Cal_Set.y = Mathf.Sin(Mathf.Deg2Rad * f_Kakudo) * f_Speed; R2d_Set.velocity = Vct2_Cal_Set; //========================================================= // オブジェクト設定 //========================================================= //--------------------------------------------------- // キャラ角度、アニメ設定 //--------------------------------------------------- ObjIf.MainChara_Ani.SetTrigger(Df_Trg_Main_Gun); if ((-90 <= f_Kakudo) && (f_Kakudo <= 90)) { ObjIf.MainChara_Posi.eulerAngles = new Vector3(0, 0, 0); } else { ObjIf.MainChara_Posi.eulerAngles = new Vector3(0, 180, 0); } //---------------------------------------------------------------- // バレット角度 //---------------------------------------------------------------- Quaternion Quat_Set = Quaternion.identity; Quat_Set.eulerAngles = new Vector3(0, 0, f_Kakudo + 90); Obj_Set.transform.rotation = Quat_Set; } } /*********************************************************************** * クラス名 : SceneOneIf 概要 : シーン内情報 ***********************************************************************/ public class SceneOneIf { //================================================================== // 変数定義 //================================================================== public BtnTapIf[] cls_BtnIf; /*********************************************************************** コントラクタ ***********************************************************************/ public SceneOneIf() { cls_BtnIf = new BtnTapIf[2]; } } /*********************************************************************** クラス名 : BtnTapIf 概要 : ボタンタップ情報 ***********************************************************************/ public class BtnTapIf { //================================================================== // 変数定義 //================================================================== public int i_BtnType = 0; public Vector3 vct3_StatPosi; /*********************************************************************** コントラクタ ***********************************************************************/ public BtnTapIf(int i_TypeSet) { // タップID設定 i_BtnType = i_TypeSet; // 現在のタップ位置取得 vct3_StatPosi = GetNowTapPoint(); } /*********************************************************************** モジュール名: GetNowTapPoint 概要 : タップ座標取得 引数 : なし 戻り値 : Vector2:タップ中の座標 ***********************************************************************/ public Vector2 GetNowTapPoint() { //============================================================ // エディター・実機ごとにタップ位置取得 //============================================================ Vector2 Vct2_Ret = new Vector2(); // エディター if (AppConst.IsEditor == true) { Vct2_Ret = Camera.main.ScreenToWorldPoint(Input.mousePosition); } // Android実機 else { for (int i_LpCnt = 0; i_LpCnt < Input.touchCount; i_LpCnt++) { Touch touch_One = Input.GetTouch(i_LpCnt); Vct2_Ret = Camera.main.ScreenToWorldPoint(touch_One.position); // 複数タップされる可能性があるので、適切なタップ位置を取得 // ※ここの判定は機種固有のものだと思われます if ((i_BtnType == Df_BtnId_Shot) && (Vct2_Ret.x > 0)) { break; } } } //================================================================ // 2828 デバッグ用テキスト ※後で消す! //================================================================ Text Txt_Set = GameObject.Find("Canvas_Back/Text").GetComponent<Text>(); Txt_Set.text = "開始:「 " + vct3_StatPosi.x + " , " + vct3_StatPosi.y + " 」\r\n"; Txt_Set.text = Txt_Set.text + "終了:「 " + Vct2_Ret.x + " , " + Vct2_Ret.y + " 」\r\n"; Txt_Set.text = Txt_Set.text + "弾数:" + Cls_ObjAll.BulletIf.i_BltCnt + ""; //================================================================= // 戻り値設定 //================================================================= return Vct2_Ret; } } /**************************************************************************** * クラス名 : AppConst 概要 : App作成前提の定義 ****************************************************************************/ public class AppConst { //======================================================================= // エディター用コンパイルかどうか //======================================================================= #if UNITY_EDITOR public static bool IsEditor = true; #else public static bool IsEditor = false; #endif } } }
・Ply_Timer
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using static Nm_Play.Ply_Cns; namespace Nm_Play { public class Ply_Timer : MonoBehaviour { // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 【発射系】関数定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ /*************************************************************************** メソッド : SetBullet_Shot 概要 : バレット発射処理 ***************************************************************************/ public static void SetBullet_Shot() { //====================================================================== // 変数定義 //====================================================================== SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //====================================================================== // ショットボタン押下中判定 //====================================================================== if (SceneIf.cls_BtnIf[Df_BtnId_Shot] == null) { return; } //====================================================================== // 弾丸発射処理 //====================================================================== //---------------------------------------------------------------- // タイマー完了判定 //---------------------------------------------------------------- ObjIf.BulletIf.i_ShotWait--; if (ObjIf.BulletIf.i_ShotWait > 0) { return; } //---------------------------------------------------------------- // 弾丸発射 //---------------------------------------------------------------- ObjIf.BulletIf.SetBulletNd_Stat(); //---------------------------------------------------------------- // タイマー値初期化 //---------------------------------------------------------------- if (ObjIf.BulletIf.i_BltCnt >= 3) { ObjIf.BulletIf.i_BltCnt = 0; ObjIf.BulletIf.i_ShotWait = Df_Bullet_Wait2; } else { ObjIf.BulletIf.i_ShotWait = Df_Bullet_Wait; } } } }
以上が、今回組み込んだソースコードになります。
別プロジェクトでゲームを作ってるものからブログ用に抜粋したものなので、
余計なコードが入っているかもしれませんが気にしないでください。
弾発射に関するコードの解説
上記のコードは実行できるように弾以外の部分が
弾を発射する部分について掘り下げていきます。
・弾発射時の仕様フロー
1.「発射」ボタンを押す
↓
2.ボタンをタップされている間、一定間隔で弾を発射する
↓
3.フリックの方向に弾プレハブを発射
↓
4.弾が何かとぶつかったら消える
・仕様解説
1.「発射」ボタンを押す
「Ply_TapEv」ファイルの「Tap_Shot_On()」関数
この関数で、ボタン押下開始時の座標を保持します。
/*********************************************************************** モジュール名: GetNowTapPoint 概要 : タップ座標取得 引数 : なし 戻り値 : Vector2:タップ中の座標 ***********************************************************************/ public Vector2 GetNowTapPoint() { //============================================================ // エディター・実機ごとにタップ位置取得 //============================================================ Vector2 Vct2_Ret = new Vector2(); // エディター if (AppConst.IsEditor == true) { Vct2_Ret = Camera.main.ScreenToWorldPoint(Input.mousePosition); } // Android実機 else { for (int i_LpCnt = 0; i_LpCnt < Input.touchCount; i_LpCnt++) { Touch touch_One = Input.GetTouch(i_LpCnt); Vct2_Ret = Camera.main.ScreenToWorldPoint(touch_One.position); // 【A】複数タップされる可能性があるので、適切なタップ位置を取得 // ※ここの判定は機種固有のものだと思われます if ((i_BtnType == Df_BtnId_Shot) && (Vct2_Ret.x > 0)) { break; } } } //================================================================= // 戻り値設定 //================================================================= return Vct2_Ret; }
このコードで、現在タップしている座標を取得できます。
エディターではマウスのクリック位置、
Android実機ではTouchクラスの「position」という要素を取得しています。
この時、「Input.GetTouch(番号)」で取得できるTouch情報は、
ボタンのタップ情報に限らず、
5か所タップされていた場合は5つのタップ情報が格納されています
なので、機種仕様に合わせて判定で適切なTouchクラスを取得してください
※ソースの【A】部分を編集する
例としては、「タップ座標がボタンの画像範囲内の座標なら取得」とかだといいと思います。
2.ボタンをタップされている間、一定間隔で弾を発射する
割り込み処理でタイマー値を減算させることで
一定時間で弾を発射する仕様になります。
//**************************************************** // 割り込み関数 //**************************************************** void FixedUpdate() { //------------------------------------------------ // 弾丸管理 //------------------------------------------------ if (Cls_SceneOneIf.cls_BtnIf[Df_BtnId_Shot] != null) { SetBullet_Shot(); } } /*************************************************************************** メソッド : SetBullet_Shot 概要 : バレット発射処理 ***************************************************************************/ public static void SetBullet_Shot() { //====================================================================== // 変数定義 //====================================================================== SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //====================================================================== // ショットボタン押下中判定 //====================================================================== if (SceneIf.cls_BtnIf[Df_BtnId_Shot] == null) { return; } //====================================================================== // 弾丸発射処理 //====================================================================== //---------------------------------------------------------------- // タイマー完了判定 //---------------------------------------------------------------- ObjIf.BulletIf.i_ShotWait--; if (ObjIf.BulletIf.i_ShotWait > 0) { return; } //---------------------------------------------------------------- // 弾丸発射 //---------------------------------------------------------------- ObjIf.BulletIf.SetBulletNd_Stat(); //---------------------------------------------------------------- // タイマー値初期化 //---------------------------------------------------------------- if (ObjIf.BulletIf.i_BltCnt >= 3) { ObjIf.BulletIf.i_BltCnt = 0; ObjIf.BulletIf.i_ShotWait = Df_Bullet_Wait2; } else { ObjIf.BulletIf.i_ShotWait = Df_Bullet_Wait; } }
毎割り込みでタイマー変数(ObjIf.BulletIf.i_ShotWait)を減算して、
0になったら弾発射関数を呼び出しています。
関数呼び出し後、変数にウェイト定数(Df_Bullet_Wait、_Wait2)を再設定します。
発射した弾数(ObjIf.BulletIf.i_BltCnt)が3個になったら大ウェイト(Df_Bullet_Wait2)
を設定する仕様になっています。
3.フリックの方向に弾プレハブを発射
//--------------------------------------------------------------- // 角度設定 //--------------------------------------------------------------- // 開始・終点座標から角度計算 Vct2_Stat = SceneIf.cls_BtnIf[Df_BtnId_Shot].GetNowTapPoint(); Vct2_End = SceneIf.cls_BtnIf[Df_BtnId_Shot].vct3_StatPosi; Vct2_Cal_S = new Vector2(1, 0); Vct2_Cal_E = Vct2_Stat - Vct2_End; f_Kakudo = Vector2.Angle(Vct2_Cal_S, Vct2_Cal_E); // 座標から向き設定 if (Vct2_Stat.y - Vct2_End.y < 0f) { f_Kakudo = f_Kakudo * (-1f); } // 座標が同じなら前に発射書き換え if (Vct2_Stat == Vct2_End) { f_Kakudo = 0; } //========================================================= // 弾オブジェクトを設定 //========================================================= //--------------------------------------------------------------- // 速度ベクトルを設定 //--------------------------------------------------------------- Vct2_Cal_Set.x = Mathf.Cos(Mathf.Deg2Rad * f_Kakudo) * f_Speed; Vct2_Cal_Set.y = Mathf.Sin(Mathf.Deg2Rad * f_Kakudo) * f_Speed; R2d_Set.velocity = Vct2_Cal_Set; //--------------------------------------------------------------- // 画像の角度を合わせる //--------------------------------------------------------------- Quaternion Quat_Set = Quaternion.identity; Quat_Set.eulerAngles = new Vector3(0, 0, f_Kakudo + 90); Obj_Set.transform.rotation = Quat_Set; }
上記のソースでタップの方向に弾を発射できます。
・変数概要
Vct2_Stat:現在タップしている座標
Vct2_End:ボタンタップ開始時の座標
f_Kakudo:計算後の角度
f_Speed:弾の速さ
R2d_Set.velocity:設定する弾のRigidbody2Dクラス変数
Obj_Set.transform.rotation:設定する弾の画像の角度
・処理概要
「// 角度設定」
フリック角度を計算
「// 速度ベクトルを設定」
弾画像に計算した角度に向かって進む力を設定
※.タップ座標が開始・現在どちらも同じなら前に飛ばす仕様
「// 画像の角度を合わせる」
画像が進行方向に向くように設定
4.弾が何かとぶつかったら消える
//*************************************************************************** // 衝突時に呼ばれるイベント //*************************************************************************** private void OnTriggerEnter2D(Collider2D col_Get) { //========================================================================= // 衝突判定 ※衝突オブジェクトのタグで判定している //========================================================================= if ( (col_Get.gameObject.tag == Df_TagName[Df_Tag_No]) || (col_Get.gameObject.tag == Df_TagName[Df_Tag_MainC]) ) { return; } //========================================================================= // 変数定義 //========================================================================= SceneOneIf SceneIf = Cls_SceneOneIf; Obj_All ObjIf = Cls_ObjAll; //========================================================================= // 衝突した弾丸オブジェクトを非表示 //========================================================================= int i_SetId = 0; i_SetId = int.Parse(this.name.Replace(Df_Bullet_Name, "")); ObjIf.BulletIf.SetBulletNd_End(i_SetId); } /************************************************************************ メソッド : SetBulletNd_End 概要 : 弾丸消去処理 ************************************************************************/ public void SetBulletNd_End(int i_EndId) { // ぶつかったオブジェクトを非表示にする l_Obj_Object[i_EndId].SetActive(false); }
上記ソースで弾がぶつかった時に消去されるようになります。
「// 衝突判定」部分は、「未定義、メインキャラ」のタグでは消えない判定を行っています。
理由は、弾発射時に必ずキャラにぶつかってしまうからです。
このTAG判定部分を変更することで、弾が貫通するオブジェクトを作ったりできます。
「// 衝突した弾丸オブジェクトを非表示」では、
オブジェクト名から、何番目のプレハブを非表示にするのか判別する仕様です。
以上が、フリック角度に合わせて弾を発射する仕様です。
言いたいこと以外の部分がめちゃくちゃ多かったので異常な長さに・・・
昨日書き始めたのですが予想以上に書くことが多すぎて2日かかりました。
相手がどこまで知っている前提で書くのか。
この要素ってものすごい大事ですね・・・
【C#6】別スクリプトの関数・定数を簡潔に呼び出す方法
今回は、スプリクトファイルを跨いで定数などを呼び出すときの
コードを簡潔に書けるようになる方法を書いていきます。
目次
参照部分の簡潔化
例えば、「Test_A.cs」と「Test_B.cs」の2つがあり、
Test_Aに定義された定数を取得する時にどうするでしょうか?
- Test_A.csの中身
public class Test_A: MonoBehaviour { public const int Df_Prm = 10; }
- Test_B.csの中身
public class Test_B: MonoBehaviour { public void SetCaliculateText() { string str_Set=""; // ↓この部分に注目!!! str_Set = Test_A.Df_Prm ; } }
このように取得すると思います。
今回の方法を使えば、「この部分に注目」と書かれている部分。
スプリクトをまたいだ時に記入する必要がある
参照部分を書かずに定数を取得することができます!
例でいえば、
str_Set = Test_A.Df_Prm ;
が
str_Set = Df_Prm ;
このように簡潔化できます。
いちいち全ての定数や関数に参照部分を書くのは
とても面倒くさくて見づらくなるので、とってもすっきりすると思います。
事前準備【C#6.0導入手順】
今回の方法を行うには、C#6.0のバージョンをUnityで使用できるようにしないといけません。
なので、たぶん「Unity2017以降」にしか実行できません・・・
設定方法を下図に記入しておきます。
「Fileタブ」→「Build Settings...項目クリック」→下図参照上記手順で準備完了です。
ちょっと古いと余計なエラーを生んでしまうので、
できれば最新のUnityに更新してから行ってください。
参照簡潔化方法
まずは呼ばれる側のスプリクトです。※上記の例でいえば「Test_A.cs」
- 【Common_Function .cs】ソースコード
// *-*-*-*-**-****-*-*-*-*-*-*-*-*-*-**-**-***- // NameSpace定義 // *-*-*-*-**-****-*-*-*-*-*-*-*-*-*-**-**-***- namespace Common { public class Common_Function : MonoBehaviour { // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 関数 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ /************************************************************* モジュール名: GetCaliculateTest 概要 : 10加算して文字列にして返す 引数 : int i_GetVal:計算する値 戻り値 : string:計算後、文字列型にした値 **************************************************************/ public static string GetCaliculateTest(int i_GetVal) { //======================================================== // 引数に10加算して文字列に変換 //======================================================== string str_Ret = ""; str_Ret = (i_GetVal+10).ToString(); return str_Ret; } } }
// *-*-*-*-**-****-*-*-*-*-*-*-*-*-*-**-**-***- // NameSpace定義 // *-*-*-*-**-****-*-*-*-*-*-*-*-*-*-**-**-***- namespace Common { public class Common_Value : MonoBehaviour { // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ // // 変数定義 // // ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□ //===================================== // 定数 //===================================== public const string Df_Msg = "「Common_Function」で定義してます"; public const int Df_Prm = 10; } }
今回は、定数・変数をまとめるファイルと関数をまとめるファイルの
2種類のファイルを用意しました。
手順としては、class全体を「namespace 名前区間名」で囲むだけです。
次に、呼ぶ側の組み込み方法になります。
- 【SetText.cs】ソースコード
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using static Common.Common_Function; using static Common.Common_Value; public class SetText : MonoBehaviour { //********************************************** // テキストオブジェクト //********************************************** public static Text Obj_Text; //********************************************** // シーン起動時 //********************************************** void Start () { //========================================= // オブジェクト初期設定 //========================================= Obj_Text = GameObject.Find("Panel/Text").GetComponent<Text>(); Obj_Text.text = Df_Msg; // 余分な文字を書かずに定数を取得できてる! } //********************************************** // ボタン押下時 //********************************************** public void SetCaliculateText() { //========================================= // 別スクリプトの関数で計算! //========================================= Obj_Text.text = GetCaliculateTest(Df_Prm); // ↑ 余分な文字を書かずに定数、関数を取得できてる! } }
手順は簡単。
using static 名前空間名.クラス名(スプリクトファイル名);
この定義を記入するだけです。
これで、呼ばれる側のファイルで定義した関数や定数は
参照部分を簡略化して記入することができます!
共通化したクラスを取得する時など、
参照部分を書かないといけないからクラス名を短めの名前にしよう!
なんて心配をしなくてもいいようになります。
UnityでC#6.0が使えるなんて知らなかった・・・
ぜひご活用ください!
【初心者向け】Spriteの管理・分割について
今回は、画像の管理方法です。
対象は、
1枚の画像を分割するやつやりたいけど、
参考サイトとかみてもピンとこないなぁ~
と思っている方限定です!
docs.unity3d.com
上記のサイトの意味がよく分からない方(私)が、
そういうことか!と思った時のお話になります。
Sprite=画像じゃない!
皆さんは、画像をオブジェクトに設定する時にどうしているでしょうか?
私は取り込んだ画像をそのままD&Dで設定することが多いです。
そのせいで、Sprite型に設定しているものは
取り込んだ画像を設定していると思ってました。
違いました!実際は、上図の画像データを展開した先にあるやつが設定されています。
ではその中身は何なのか?画像をクリック→上図の「Sprite Editor」ボタンをクリック
すると、画像が新しいウィンドウで表示されます。
その画像の枠に線があることに注目してください!
その枠こそがSprite型の中身です!!
Spriteタイプの画像データは、
取り込んだ画像の、指定の範囲(青線で囲んだ部分)のみを切り取った画像なんです!
つまり、1枚の画像を分割するということは
画像内の青線の枠をいっぱい作って、下図のように
オブジェクトに設定するデータをたくさん作ろう!ということです
ここまでの内容が、僕が画像分割を学んだ時にしっくりこなかった部分です。
分割しても画像データ1つだからどーなってんの?って思ってました・・・
画像の分割方法
実際の分割手順をご説明します。
やったことない人向けですので簡単な分割方法をそのまま載せます
- 取り込んだ画像の初期設定
- 「Sprite Editor」での分割処理と結果
以上になります。
初めに話した部分が、独学で適当に学んでいる私には
気づくのに時間がかかってしまいました。。。
分かるとめちゃくちゃ簡単。
かつ画像管理がやりやすいのでぜひご活用ください。
【VBA】ショートカットキー設定時の注意
こんにちは。
今回は、Excelの自作関数にショートカットキーを設定する際、
適当にやって躓いてしまった事を書いていきます。
ショートカットキー設定方法は2つある
- その①:「開発」のタブから設定
上記の方法で、組み込みなしでショートカットキーを設定できます。
注意点は、
・キーを登録できるのは、引数・戻り値がないPublicな関数のみ
・モジュールファイルのファイル名(オブジェクト名)と、
そのファイルの中の関数名を同じにすると「図中.③」の
関数名の部分がめちゃくちゃ長くなる
- その②:Workbookイベントを捕まえてマクロで設定
ブックを開いた時のイベント内で、
ショートカットキーを設定するマクロを組み込みます。
注意点は、ブックを閉じるときに
設定したショートカットキーを初期化させないと、
全てのExcelを閉じないとショートカットキーが残るということです。
' ブック起動時イベント Private Sub Workbook_Open() ' ショートカットキー設定 Application.OnKey "指定のキー", "指定の関数名" End Sub ' ブック閉じる時イベント Private Sub Workbook_BeforeClose(Cancel As Boolean) ' ショートカットキー解放 Application.OnKey "指定のキー" End Sub
※「指定のキー」部分に入力する定数は下記リンク参照
https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.onkey
※「指定の関数名」部分は
”オブジェクト名.関数名”の書き方で記入
キー設定時の注意!
ここからが今日躓いたことなのですが、
その①の方法でキーを設定した場合、
エクスポートした後もショートカットキー情報が残る!!
ということです。。。
つまり、
モジュールファイルをエクスポートして別のブックにインポートした時
エクスポート前に「その①」の方法でキー設定を行っていると、
インポートしたブックの方にも自動的にキー設定されています。
なので、ショートカットキーを設定した覚えがないのに
勝手に関数が呼び出されてしまいます・・・
私は今回、マクロ形式ブックでその①方法でキー設定して、
アドイン形式のブックにインポートしてその②方法でキー設定した為
意図しないショートカットキーが潜んでいて気づくのに時間がかかりました・・・
その①の方法でキー設定を管理するのは簡単ですが、
エクスポートすることを考えるならその②で設定する方が
キー設定の管理ができるので断然おススメです!