注:当ブログでは広告を利用しています。

UnityC#スクリプト軽量化作戦!FPS大幅上昇した秘密テク公開

おはよう、Unityをいじって1年以上が過ぎた。

慣れたからこそ、改めて軽量化に関し、
現時点でわかっている部分を伝えて、共に省略を目指したい。

 

キャッシュ:関数(メソッド)を書く前に型番と変数(+値)を決めよ

型名変数名

UnityはStart関数とUpdate関数から成り立つ。
Start関数の前型名、変数名をおく場所がある。

型名:int ,float ,string ,GameObject,クラス名など
変数:適当な未知数xなどを示す。上記画像例だとsomreやdoorID、rhStageなど。

※クラス名とは独自で作ったスクリプトの名前などを示す。
例えば私がSoundManagerスクリプトを作成したら、SoundManagerがクラス名となる。

private SoundManager(型番;クラス名) soundM(変数、英単語なら何でもOK);

始めのうちに型名と変数名、場合によって初期値を与えてしまう。
初期値を書いていなければ、C#独自の初期値(0やfalse,nullなど)になる。

はじめに初期値を設定すると、以降の関数(メソッド)で変数を使いまわせる

関数内でも型番と変数名を指定できるが、
指定した関数のみ効果を持ち、他の関数で使用できなくなる。

タグとstring

型番+変数+初期値設定をキャッシュという。キャッシュを早めにやっておく。
特に文字列ことstringは絶対にやっておくべきだ。

Invokeの中身もInvoke(stringで記す関数,時間);なのでキャッシュできる。

Invoke("stage" , 1);
//---------------//
praivate string stages = "stage";
Invoke(stages , 1);

string型は文字列(“”がついた状態)のままでなく
きちんと変数を置いて文字列をあらかじめ代入すると、
プログラミング的に効率化を図ってくれる。

 

影響あるようでない?bit数

bit数

上記画像元は下記リンクに記している。
パソコンでのbit数はメモリ量に影響を与える。

普通に創るならすべてint(32bit)で構わない。
私は気になるのでbyte(8bit)を良く使っている。

なお1バイト(byte) = 8bitだ。

byteでは使えない、intでしか使えない関数・変数もあるので注意が必要だ。
面倒ならすべてintで十分だ。

固定値であり、0以上255未満、intを入れなくても通じる場所はすべてbyteを入れている。

なおstring系の文字列は全角文字1文字をShift-JISでは2byte
UTF-8では3byte使用するそうだ。英数字はどちらも1byte使う。

UTF-8を主に使うと仮定すると、全角1文字で3byteより、使う時は注意が必要だ。
なるべく全角は使わないうえ、string系もあまり入れない方がいいのかもしれぬ。

bit最小値はbyte、bool、半角たった1文字だ。

文字系は基本2byteを使うので、
文字列を使用せずにboolかbyteに置き換えるのがいいかもしれぬ。

2つの真偽地ならboolを、複数ならbyteで分けると。

最もタグはstringを使わなければ無理だが。

画像元と参照:UnityC#で扱うクラス

参照:stringなど文字列のバイト数を取得

参照:組み込み型C#

 

値が固定されているならconstを使おう

const

「不変・固定化」させる変数と初期値について、
constで変数を固定化させた方がもっと早い

private const string Enemy = "Enemy";

参照サイトに「gameObject.tagへのアクセスが重たい」書いている。
始めにキャッシュして値を固定化すれば、早く対応できる。

実際にスクリプトを組んで計測した結果、
CompareTag(“Player”)直接値を代入するより、
タグを事前にキャッシュしたCompareTag(Player)方が早い。

※キャッシュ:private string Player = “Player”;を最初に置く

参照:gameObject.tagをイコールで比較した場合とCompareTagを使った場合の処理時間の比較【Unity】【最適化】

※CompareTagはboolでGameObject.tagはstringとわかった。
文字列のため、数字に比べて処理が複雑になるのだろう。

参照:const(コンパイル時定数)とreadonly(実行時定数)の違いを知る

 

コルーチン系のキャッシュは注意が必要

private IEnumerator fadeinTime;

void Start(){
fadeinTime = FadeinTime();
StartCoroutine(fadeinTime);}

最近コルーチンもキャッシュできると分かった。

型名で「IEnumerator」を指定し、Start関数で値を代入。
後は使うところで入力していけばいいわけだ。

ただしコルーチン系でも「一度しか使わない」ものはStart関数でいいが、
何度も使う(例:敵からダメージを食らう)場合、Start関数においてはいけない。

スタート関数はあくまでも一度のみ発動であり、以降は発動しなくなるからだ。

何度も発動させるなら、コルーチンキャッシュはしないほうがいい。
単純にStartCoroutine(FadeinTime());としたほうがいい。

 

同じ型番をひとまとめにしておく

private int hp;
private int mps = 2;
private int wwe ;
//-------------------//
private int hp , wwe , mps = 2;

上記はどちらも同じだ。コードの記述量が異なる。
どちらがコード処理にとって楽かと言えば後者だ。

前半は3行に対し、後半は1行で済ませている。
型番とアクセス修飾子(private,public,protectedなど)が同じなら、一つに束ねてしまおう

束ね方は半角コンマ「,」をつけて、変数をつなげ、最後に「;」をつけるだけ。

ただ「あれ、この変数は何に使うんだっけ」わからなくなる時が来るから、
変数を入力した後、「//一行」か「/* 複数列コメント */」を用いて、
「この変数はここで使う」記しておこう。

 

途中で型番を設定しない

for(int i = 0; i > 10; ++i)
{Debug.Log(i);}

//----------------------------

private int i;
for( i = 0; i > 10; ++i)
{Debug.Log(i);}

例えばforなどループ処理やOnCollision関係にて、
その場で型番と定数を定義する方法(上記コード上側)がある。

iも事前にキャッシュしたほうが、型番を定めているため、
for内でいちいち型番設定を行う必要がない

 

値が同じものはすべて等号(=)でつなぐ

float gravity = -9 ;//整数の場合、fをつけなくていい
movepos.y = gravity;
maxL.y = gravity;
//-----------------------//
movepos.y = maxL.y = gravity;

値が同じものはひとまとめにする。二行を減らし、一行にまとめられるので便利だ。

 

ベクトル”new Vector”をあまり使わない

float speed,gravitys;
void Update(){
this.transform.position = new Vector2( speed , gravitys);} 

//-------------------------// 

private Vector2 movepos; 

void Update(){ movepos.x = speed; movepos.y = gravitys; 
this.transform.position = movepos; }

先ほど型番とアクセス修飾子が同じものはひとまとめにし、
コード記述量を減らそうと書いたが、こちらは違う。

新しいベクトル(構造体)を設定する時、new Vector2(x , y)とnewを設定している。
newは設計図から実体を与えるために必要であり、
Startなど一度しか使わないところならnewを置いてもいい。

Updateなど何度も使うところでnewを繰り返すと、常に実体化させるため面倒くさくなる。
またベクトルの記述量も長くなる。

色々調べたところnew Vectorだと値においてプログラムは一気に読むのでなく、
まずx、次にy、次にzと常に確認を取りながら読み取るそうだ。

newを使わないで設定する方法として、
始めに型番+変数でベクトルを設定し、xとy(3次元はここにzがつく)を設定し、
設定したベクトル(ここではmovepos)を入れればいい。

 

計算は簡単なモノから複雑なものへ

float speed; 
int hp;
vector3 velocity = speeed * transform.forward * Time.deltaTime * hp;
//→修正
vector3 velocity = hp * speeed  * Time.deltaTime * transform.forward;

参照サイトによれば、計算の仕方一つにも処理を軽くする工夫がある。
intやfloatの計算は比較的簡単でも、ベクトルや回転(クォータニオン)は複雑だ。

上記式は小数点×ベクトル×小数点×整数となっている。
参照サイトによると、小数点×ベクトル計算後、再び小数計算を行うと、
二度同じ計算をしなければならないそうだ。

そこで整数×小数×ベクトル(クォータニオン)と軽い順番からやると、
スクリプトにとっても処理が楽だという。

計算をしているならぜひ見直してほしい。
いっそ計算とベクトルの代入を分けたほうが、プログラムとして楽かもしれない。

参照:Unityでの最適化について

 

計算の応用:整数で単純化へ


private Vector2 playerpos , newposition , newplayerpos , distancepos;
private int distanceint;

protected void Destances(){
playerpos = player.transform.position;
newposition = this.transform.position;
newplayerpos = playerpos - newposition;
distancepos.x = (int)playerpos.x;
distancepos.y = (int)playerpos.y;
distanceint = (int)Mathf.Floor(distanpos.magnitude);
}

上記コードは主人公と敵の距離計算だ。
様々なサイトでは距離を測るやり方として
Vector3.sqrMagnitude:二乗の三平方定理を推奨している。

※Vector2.sqrMagnitude:でも可。sqrMagnitude=x^2 + y^2

ただ距離が大きいほど差も非常に大きく(万単位)になり、かえって厄介だ。

そこで主人公と敵の距離をベクトル引き算として、引き算した値を整数化し、
ルートを計算して四捨五入し、即座に整数化させている

(int)は小数floatを強引に整数へ変化させる道具だ。
小数を省いて少しでも楽できるようにしている。

記事を書いているときに、二乗でもいい方法が思いついた。
現在、自分はこちらを使っている。

private Vector2 playerpos , newposition , newplayerpos ; 
private int distanceint ,disX , disY; 
private int const maxDis = 150 , maxY = 60;
//

//------------//

protected void Destances(){ 
playerpos = player.transform.position; //主人公座標
newposition = this.transform.position; //敵の座標
newplayerpos = playerpos - newposition; 
disX = (int)newplayerpos.x; //整数化して計算簡略化
disY = (int)newplayerpos.y; //整数化=小数点切捨
distanceint = (disX*disX) + (disY*disY); //三平方の定理から斜辺の値2乗を出す
//sqrMagnitudeはfloat型で小数点を出す計算のため不採用。
distanceint = Mathf.Clamp(distanceint, 0, maxDis);//最小値と最大値設置
//distanceintの値がmaxDis = 150を超えた場合、distanceint = 150(最大値)
RangeEnemy();
} //Destances

void RangeEnemy(){
//カメラの高さと広さによって場合分け
if(disY >= maxY  || distanceint >= maxDis){//最大値を超えた
//敵を止める処理(Rigidbody2D.constraints)など
}else if(disY < maxY || distanceint < maxDis){
//敵を動かす処理など
}
} //RangeEnemy

このようになるべく小数値の計算よりも整数の計算を行ったほうが単純だ。

 

静的staticを使って固定化した値を次々代入

axisH = Input.GetAxisRaw(Horizontal) ;
if ( axisH < 0 ) {
this.transform.localScale = new Vector(-1 ,1);
} else if ( axisH > 0 ) {
this.transform.localScale = Vector2.one; // (1 , 1)
}

//---------------------------//
(GameManagerスクリプトにて)
public static Vector2 minusOne = new Vector(-1 ,1 );
//---//
axisH = Input.GetAxisRaw(Horizontal) ;
if ( axisH < 0 ) {
this.transform.localScale = GameManager.minusOne;
} else if ( axisH > 0 ) {
this.transform.localScale = Vector2.one;
}

new Vector(-1 ,1);とGameManager.minusOneの違いだ。
一か所しか使わないならnewで十分だろう。

複数かついくつかのスクリプトで使うなら、
一つの大本スクリプト(ここではGameManager)に値を設定し、
いろんなスクリプトで使いまわしたほうが楽だ。

staticは複数のスクリプトにまたがって使える道具で、関数も扱える。
staticにはpublic(他スクリプトでも使用可)のほか、
private(そこでしか使えないが、関数をまたがって使える)もある。

なおベクトルにはVector2.one;のように最初から使えるものがある。
参照(Unity公式)のStatic変数を参考にしてみよう。
なければ私のように一つ作ってしまおう。

参照:UnityのVector(のstatic変数参照)

 

軽い[SerializeField]–GetComponentよりも

private string front ="front";

[SerializeField] Animator anim;  
//インスペクター上から直接アタッチ
//---------------------//

private Animator anim;  
void Start(){anim = GetComponent<Animator>(); }
//----------------------//
void Update(){anim.Play(front);}
[SerializeField]もGetComponentも重たさはあまりかわらない。

[SerializeField]からインスペクターに直接入れたほうが楽だ。
GetComponentはスクリプトの行を長くさせるためだ。

[SerializeField]から直接アタッチすれば、
Start関数にGetComponentを代入せず、直接値を代入できる

GetComponent軽量化1

インスペクターの設定が若干面倒くさいが、
プレハブ化すれば、スクリプトにアタッチしたゲームオブジェクト以外の参照がなくなるため楽だ。

参照:【Unity】SerializeFieldでセットするかGetComponentで取得するか迷った

 

隠れてGetComponentを使っているtransform、Cameraには

ベクトルの足し算と代入

調べたところ、TransformはこっそりGetComponentが入っている。
CameraはFindGameObjectWithTagを使っているそうだ。

ついでにthis.gameObjectも何かが入っていると聞いた。

とはいえ最新のUnityはほぼキャッシュ化されているそうだ。

一応キャッシュ化しておこう。そのまま使うより早いし、行も短くできるので。
Cameraのキャッシュはこちら。

private new Camera camera;
private CameraCtrl cameraC;//Cameraオブジェクトに張り付けたスクリプト
void Start () {camera = Camera.main;
cameraC = camera.GetComponent<CameraCtrl>();}
//new をつけたほうが、警告が出にくくなる。

一方でtransformやgameOBjectは

private Tranform trans;
private GameObject myob;
private string Muteki = "Muteki";

void Start(){trans = this.transform;
myob = this.gameObject;}

void Update(){trans.position = movepos;
myob.layer = 10;
myob.tag = Muteki;}

すでにある値をいちいちキャッシュ化しておくのは面倒くさい。
面倒だけど通常より処理が速い。

 

インスペクターはGameObjectよりスクリプトなどクラスを

[SerializeField] SoundManager ses;
[SerializeField] GameObject sound;

「sound」という名前のGameObjectがある。
アタッチする際、目的がスクリプトのみなら直接スクリプト名(上記コード上)を入れたほうが早い

もちろん直接オブジェクトを扱うならGameObjectがいい。

例えばSetActive(true/false)を使ってオブジェクトを非表示/表示なら、
GameObjectをインスペクターに入れるといい。

どちらのやり方であろうと別スクリプトから値を代入できるのは、
publicとついたアクセス修飾子のみだ。

publicは基本、インスペクター上からも設定できる。
インスペクター上で設定する気のないpublicは[System.NonSerialized]をつけよう。

[System.NonSerialized] public int hp = 2;

また関数を別スクリプトで使うやり方もある。
インスペクターからファイルを代入した後、

public void Xyz(){//処理}

をつければ、普通に使えるよ(通常の関数はprivate)。

 

真偽boolと遅延関数Invokeを使ってUpdate量を減らす

void Update(){
if(mutekiget){//無敵へ
timeMuteki += Time.deltaTime;
if(timeMuteki < 12) {
this.tag = MutekiPlayer;
StartCoroutine("Muteki");}
else {
timeMuteki = 0;
Invoke("MutekiOff",0.5f);}
} }

void MutekiOff(){mutekiget = false;}

Update系は毎秒起きに更新するため、
中の値が同じだと、常に同じ値を新規に入れて更新する。

同じ値なのに新規に入れて更新する……無駄でしかない。
一度入れたらもう入れなくていいのに。

そこでboolとInvokeを使って、
値を入れたらUpdate関数内でも値を更新させない処理を行う。

Invoke(“関数名” , 秒数);で使える。

やり方として、まずboolでtrueかfalse(初期値)のどちらかのみ、
特定の関数が発動するかを考える。

再生時に即発動させたいならfalseを、何かを取得した時ならtrueに設定だ。

ここではmutekiget=trueの時のみ、中の式が発動する。
falseの時は一切発動しないわけだ。

※一応テストとしてDebug.Log(“適当な言葉”);を入れて、
中の関数が働いているかテストしよう。

上記スクリプトでは12秒を越えた後、遅延発動ことInvokeが働く。
ここでは0.5秒後に関数MutekiOffへ向かう。

MutekiOffではmutekiget = false;にするため、
Update内にあるmutekiget 以降の働きが停まる

ちなみにmutekiget は無敵のアイテムをとるとtrueになるよう設定している。
(上記スクリプトには書いていない)

 

一度発動した後、繰り返しを防ぐ(Update内)

bool changeon;//初期値はfalse

void LateUpdate(){
if(!changeon) { //初期入力,早い
clip = clipold;//clipにclipold代入
bgms = bgmData.bgm[clip];
loopStart = bgms.LoopStart;
Invoke("LoopInput" , 0.55f);}
void LoopInput(){ changeon = true;}

boolとInvoke関数の合わせ技でUpdateに何度も同じ値入力を防ぐ方法をもう一つ。

bool changeon = false;が初期値であるため、
Unity再生ボタンを押したら即座に発動する。

0.55秒経ったらLoopInput関数に飛び、changeon = trueに変換。
changeonをfalseにする要素はシーン変更(場所移動など)以外なくなる。

値を入力したら、お役御免の働きを持っている。

Invoke関数の秒数は1(=1f)秒もあれば長いほうだ。
Debug.Logを使いながら、どれくらいで発動するかを見極めよう。

 

おまけ:”void Update()”量を減らし、まとめる

さらにUpdateはvoid update()量を一つに束ねる方法がある。
Updateもメモリを使うので、一つに束ねるとメモリが浮く。

上記リンクから飛んで参考にしてほしい。

 

リストの()に指定の数字を入れる

List<int> listB = new List<int>();

//(キャパシティ)こと()内に数字を入れるとメモリに優しい
List<int> listB = new List<int>(4);

//次のように省略できる
List<int> listB = new(4);

//使用後はリストを空にしてメモリ確保
void Ondestroy(){
for(int i = 0; i < listB.Length; i++){
listB[i] =null; }//中身を空白にしてメモリ解放
listB.Clear();
}

//listがGameObjectならnull代入前にDestroy()も入れておくと確実に中身を消せる。

scriptableobject内でリストを使う際、
()の中にあらかじめリストに必要な数字を入れたほうが軽い。

数字を入れないと、新しく数を追加するたびにいろいろ更新しなければならないが、
初めから数字を指定しておくと、いろいろのいくつかを省略できるからだ。

ついでにscriptableobjectはデータ保存調であり、
主人公や敵のHPほか、データを収納できる。

スクリプト内の呼び出しより早く処理できるので、
まだ入れていない人は上記動画を参考に入れよう。

 

消去:DestoryよりSetActiveよりenabled

[SerializeField] Animator anim; //敵アニメ
[SerializeField] SpriteRenderer spR; //敵画像
[SerializeField] BoxCollider2D boxC; //当たり判定や床との接触判定
[SerializeField] Rigidbody2D rb2d;

private GameObject gameO ;

void Start(){gameO = this.gameObject}

void Owatta(){
Destroy(gameO);//ヒエラルキーから姿を消す
gameO.SetActive(false);//ヒエラルキーには残るが、プレイ時から消える。
anim.enabled = rb2d.enabled = boxC.enabled = false;
//ヒエラルキーにも残るしプレイ時もついたままだが、処理は最も軽い
}

enabledはgameObjectにアタッチされた部品を引報じ/表示できる。

SetActiveはgameObject本体を非表示、表示できる。

Destroyはヒエラルキーから存在を消去できる。

Destoryを行うと、ごみとしてたまるそうだ。
ゴミ箱の要領が大きいとUnityにも影響が出るため、基本使わない。

※Destroyはメモリ確保のために必要。後述。

面倒さで言えばenabledだ。

アタッチ部品が多いならSetActive(false)にした方が便利だ
メモリの軽さならenabled=falseのほうが早い。

SetActiveを上手く利用した機能として、プールがある。
球などを使いまわす機能だ。

上記動画を参照に、ぜひ作ってDestroyを使わないよう設定してほしい。

 

シーン変化前にDestroyとnullでメモリ確保を

private GameObject nowObject ;
//キャッシュ化
void Start(){nowObject = this.gameObject;}
//すったもんだでプレイ中に処理した後

//シーン変更で呼び出される
void OnDestroy(){
Destroy(nowObject); nowObject = null;
}

シーン変更をはじめ、二度と使わないゲームオブジェクトは、
OnDestroy関数を読んだうえ、
Destroy(中身はGameOBject);とGameOBjectをnull設定にすると、
メモリ解放にとてもいいと、調査して分かった。

GameObjectはもちろんSpriteなども、
使うシーン以外では使わない、シーン切り替え時は
必ず二つの作業をしておくと、別のシーンにメモリを引き継がないため、
サクサクとゲームプレイできる。

List系はClear();を使えばいい。

調べたところC#(unity)はシーンが変わると自動的に消してくれる
あまり気にしなくていいのだが、一部は残ったままだという。

残ったものをnullとDestroyで確実に消し、メモリを楽にさせてあげよう。

 

結論:些細なものも次々キャッシュしたほうが早い

start関数と継承

結局、型番と変数で些細なものでもキャッシュしたほうが早い。
特にstring型の文字は関数を動かす前に型名と変数名を置くと(キャッシュ)、
値が決まっているから早く処理できる。

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

[SerializeField] Rigidbody2D rb2d;
//GetComponentを省くため、[SerializeField]でインスペクターから直接代入。

private const string Horizontal = "Horizontal" , Jump = "Jump" ,
Fire1 = "Fire1" , Enemy = "Enemy" , Player ="Player";
//""ではさむ文字列はすべてキャッシュ化
private string thistag;
private GameObject gameO;
private Transform mytrans;
private Vector2 movepos , mypos;
private float speed , axisH;
private WaitForSeconds wfs002 = new WaitForSeconds(0.02f);
//コルーチンで使うWaitForSecondsもここでキャッシュ

void Start(){
gameO = this.gameobject;//変数に入れたほうが早くなる
mytrans= this.transform;//これもキャッシュしたほうが早い
thistag = gameO.tag;//このスクリプトがついているときのタグ。
}

void Update(){
if( Input.GetButtonDown(Jump)){//処理}
//JumpやHorizontalなどもstringとして処理できる
}

void FixedUpdate(){
mypos = mytrans.position;
movepos.x = speed * axisH; movepos.y = gravity;
//x,y、Vector3ならzも使って分ける。
rb2d.AddForce( movepos );//new Vectorを使わない
}

void OnCollisionEnter2D(Collision2D dobject){
if (dobject.gameObject.CompareTag(Enemy)
&& gameO.CompareTag(Player))
{StartCoroutine("Damage");}
//"Damage"はstringでなくIEnumerator。Invokeも同じ。注意が必要。
}

//シーン変更時に掃除してメモリ確保
void OnDestroy(){
Destroy(gameO);gameO = null;
}

参考になれば幸いだ。

 

追記結論:if判断はなるべくboolで

自分で書いた通り、string系によるif判断を限りなく減らしてbool
複数ならbyteやintに分けて判断した。どうしても無理なものだけstringにした。

intをできる限りbyte,sbyteにすると、結構な割合でスクリプトの整理につながった。

bit数を考慮したうえでプログラミングを行うと、
結構な割合でスクリプトを軽くできる。

お願い

めがびちゃんからお知らせ♪

お知らせ

megabe-0へ訪問した"本当"の理由

まさか記事の書き形一つでこうなるとは…

お願い1

Writer軽い自己紹介

ティラノスクリプトや小説家になろう、ピクシブ他で物語を書きながら、 「私が気になった事件」の裏側を作家の視点で書いているおっさん。

プロフィール画像は自画像でなく、Megabe-0ブログのマスコット、めがびちゃん。

 

雷が苦手で、光を見ると頭が固まる(元から固い)。 月初めは墓参りと神社参拝を行い、賽銭箱へ1万円を入れた際、とても気持ちがすっきりした。

 

■ 簡単な自分史 ■

0歳:釧路のある病院で生まれる。暇さえあれば母乳を吸って、ご飯を4膳食べても体重が落ちるほど、母のダイエットにものすごく貢献したらしい

 

3歳:行方不明になり、全裸で海を泳ごうとしたところ、いとこのお姉さんに発見され、この世へ留まる

 

8歳:自分のお金でおもちゃのカードを初めて買い、経済を知る。なぜか父親に怒られ、家出するがすぐに見つかる。

 

12歳:学校で給食委員長になる。委員長として初めて全校生徒の前にて演説する際、原稿用紙を忘れてアドリブで笑いを誘いながらも何とかやり過ごし、多くの生徒に名前と顔を覚えてもらう。また、運動会の騎馬戦では変なアドリブを行い、多くの笑いを誘った。

 

18歳:初めて好きな人ができたけれど、告白が恥ずかしくてついにできず、別れたことを今でも根に持っている(妻となる人にははっきり言えてよかった)

 

21歳:大学在学中、アルバイトを始める。人手不足かつとても忙しい日々を過ごしながら「どうせなら自分から楽しいことをしていきたいなあ⇒起業って選択肢があるのか」働き方の選択肢を見つける

 

27歳:自分で作った会社がうまくいかず、一度たたんで都落ち。実家でとことん自分を責める日が続く。「何をやっても駄目だな、お前は」など。自分を責めても自殺ができず、体中から毒素があふれ出て苦しい日々を送る。寝るのも怖かった日々。

 

28歳:「このままじゃいけない」決心を決め、小学校からの勉強をやり直す。高校の勉強で躓きながらも、学び直すうちに「自分は何もわかっていなかったんだなあ」大切な教えに気づかされる。 加えて、小説やイラストなど「今までの自分が手を出さなかった分野」に手を伸ばしてみた。

 

29歳:「定義」と「自己肯定」こそが生き方を決めると気づかされ、不安な日々が起きても、心が強くなったと感じる。でも子供の誘惑にはめっぽう弱くなる。

 

35歳:人生初の交通事故(物損)に出会う。冬道の運転で車を上下に大回転(スピンではない)を体型氏、何とか命を取り留め、なぜ生きているのかわからない状態に陥る。

自分の生き方はすべて自分が握っている。わずかな瞬間にしか現れない「自分の真実」を表に引きずり出し、ピンチからチャンスを生み出す発想や視点をブログやメルマガ他で提供中。