ここに書かれていることは全てフィクションで、筆者自身の経験や実在の人物・企業・団体等とは一切関わりが無いということを了解できる方のみ、先を読み進めてください。またちっとも楽しくも、ためになるわけでも、ましてや気分爽快になる話でもありません。ご理解ください。
“負け犬の遠吠え” の続きを読む2019 -> 2020
2019年は、本当に惨憺たる一年だった。
年がら年中を通して、気分が沈むような事ばかり起こった。死にたいという気持ちを吐き出すためだけのアカウントを作ったりもした。
この一年はなんだったのだろうか。
今までのツケが回ってきたのかもしれない。俺が何を悪いことをしたものかとばかり思っていたが、もしかしたらこれは全て自業自得、因果応報だというような気もしてくる。
仕事。2020年の1月いっぱいには会社の解散が確定している。もともと厳しい状況だったのはずっと前からだった。遠からず転職せざるを得ないだろうと思っていたからそれ自体に何か嫌悪の情はないが、やはり自分のキャリアの中途半端さを思うと惨めな気持ちになる。やりたいことだってあるつもりだけれど、それがどうも社会とマッチしていない、見つからない。あるいはそれとも、俺が伝えられてないだけなのか。最近、本質的な意味でコミュニケーションが苦手だなとつくづく思う。咄嗟の機転というか、いわゆる頭の回転と呼ばれるような物が鈍いんだと思う。何度も何度も文章を推敲を重ねてようやく、自分の言いたかったことがわずかに表せるような。それだって、言葉をこねくり回しすぎて、本当に言いたかったことなのか分からない。
仕事だけじゃない。人間関係もひどい物だった。いくらこちらから仲良くしたいと思ったって、どんどんどんどん自分の重りだけを積み上げていくばかりでは秤が釣り合うことはない。ようやく釣り合ったと思えば、突然相手の分銅が消えてしまうことだってある。我が意のままにならぬところに寄りかかっていればその分だけ、スカされた時に大きくバランスを崩してしまう。
そもそも、気分の浮き沈みに左右されすぎなんだ。落ち込んで1週間くらい何も手につかないことが何度もあった。感情が入り組みすぎているんだ、ある程度切り離せるようにならなきゃ、できることもできなくなっちまう。
本当にロクでもない一年だった。ろくでなしなのは俺か。いいことだっていくつかあったはずなのに、霞んでしまった。終わり悪しければ。これ以上、辛いことばかりならいっそとも思う。その度に親の顔が浮かぶ。
ゲーム中にスマホをブルっとバイブさせよう
この記事の要旨
iOS/Androidのそれぞれで、スマホをバイブさせる実装を行う。参考記事
基本的に以下のQiitaを読めばわかる人にはわかるんだと思います。なので、ド初心者の自分が詰まったところを中心に紹介。 https://qiita.com/mrhdms/items/3201baf851a91875fa29Unityでモバイル端末のバイブレーションをコントロールする
iOS向けの実装
1 2 3 4 5 6 7 8 9 10 11 12 |
IOSUtil.cs #if UNITY_IOS && !UNITY_EDITOR [DllImport ("__Internal")] static extern void _playSystemSound(int n); #endif public static void PlaySystemSound(int n) //引数にIDを渡す { #if UNITY_IOS && !UNITY_EDITOR _playSystemSound(n); #endif } |
1 |
using System.Runtime.InteropServices; |
1 2 3 4 5 6 7 8 |
IOSUtil.mm #import <Foundation/Foundation.h> #import <AudioToolBox/AudioToolBox.h> extern "C" void _playSystemSound (int soundId) { AudioServicesPlaySystemSound(soundId); } |
するとこのファイルをXCodeで編集できるようになったので、上記のコードをコピペし、UnityプロジェクトのAssets>Plugins>iOSに、適当な名前を付けて保存しておきます。
以上でiOSの方はおしまいです。実機にビルドしてみれば、呼び出しのタイミングでスマホがぶるっと震えることを確認できました。
Android向けの実装
AndroidはiOSに比べるとシンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
AndroidUtil.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public static class AndroidVibrator { #if UNITY_ANDROID && !UNITY_EDITOR public static AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); public static AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); public static AndroidJavaObject vibrator = currentActivity.Call<AndroidJavaObject>("getSystemService", "vibrator"); #else public static AndroidJavaClass unityPlayer; public static AndroidJavaObject currentActivity; public static AndroidJavaObject vibrator; #endif public static void Vibrate(long milliseconds) { if (isAndroid()) vibrator.Call("vibrate", milliseconds); else Handheld.Vibrate(); } private static bool isAndroid() { #if UNITY_ANDROID && !UNITY_EDITOR return true; #else return false; #endif } } |
おわり!
EasySave3でローカルハイスコア機能を作ろう
この記事の要旨
定番アセット”EasySave3″を使って、シンプルなハイスコアの記録と表示の機能を作る。記録や読み込みのタイミングは”Arbor3″でのステート管理を利用。概観
下記の3つのクラスで実装しました。- ScoreManager.cs
- 一回のプレイのスコアを記録するクラス
- HighScoreManager.cs
- 上記のスコアを、保存されているハイスコアと比較し、必要なら上書きして保存するクラス
- HighScoreDescriber.cs
- 保存されたハイスコアをUI上に表示するクラス
一回のプレイのスコアを記録する
みなさん各自のゲームで実装されていると思うので参考程度に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class ScoreManager : MonoBehaviour { public int Score { get; private set; } TextMeshProUGUI petalNum; ComboBonus comboBonus; HighScoreManager highScoreManager; HighScoreDescriber highScoreDescriber; void Start() { petalNum = GameObject.Find("PetalNum").GetComponent<TextMeshProUGUI>(); petalNum.text = "0"; comboBonus = GameObject.Find("Combo").GetComponent<ComboBonus>(); highScoreManager = GetComponent<HighScoreManager>(); } [Button] public void AddScore(int score) { int bonusRate = comboBonus.Rate(); Score += score * bonusRate; petalNum.text = Score.ToString(); } //arborでResultステートに入ったタイミングで呼ぶ public void RefreshLevel1HighScore() { highScoreDescriber = GameObject.Find("View - Ranking(Clone)").GetComponent<HighScoreDescriber>(); List<int> currentHighScores = highScoreManager.CheckLevel1HighScore(Score); highScoreDescriber.DescribeHighScore(currentHighScores); } } |
HighScoreDescriberクラスをStart()でなく独自のタイミングでGetComponentでキャッシュしているのは、HighScoreDescriberクラスを付与したオブジェクトがPrefab化されており、リザルト画面へ遷移したタイミングで生成されるようにしているためです。
生成後のタイミングでRefreshLevel1HighScore()をArborのSendEventGameObjectを使って呼んでいます。
RefreshLevel1HighScore()では、後述する「ハイスコアの更新確認」「UIへの反映」も合わせて呼んでおり、このメソッドがハイスコア周りの処理の根っこになっています。
結果のスコアを、保存されているハイスコアと比較
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
public class HighScoreManager : MonoBehaviour { List<int> defaultHighScores = new List<int> { }; List<int> Level1CurrentScores { get; set; } = new List<int>(); private void Start() { Initialize(); Load(); } [Button] void Initialize() { defaultHighScores = new List<int> { 20, 16, 14, 12, 10, 8, 6, 4, 2, 0 }; Level1CurrentScores = new List<int>(); } [Button] void Load() { Level1CurrentScores = ES3.Load<List<int>>("level1",defaultValue:defaultHighScores); } [Button] public List<int> CheckLevel1HighScore(int currentScore) { int minIndex = Level1CurrentScores.FindIndex(x => x < currentScore); //ランクインしなかった時の例外を潰す必要がある try { Level1CurrentScores.Insert(minIndex, currentScore); Level1CurrentScores.RemoveAt(10); Save(); return Level1CurrentScores; } catch (System.ArgumentOutOfRangeException ex) { Debug.Log("ランク外だったみたいですね"); Save(); return Level1CurrentScores; } } [Button] void Save() { ES3.Save<List<int>>("level1", Level1CurrentScores); } [Button] void Delete() { ES3.DeleteKey("level1"); } } |
Loadメソッドでは、EasySave3に用意されているES3.Loadメソッドを用いて保存されているハイスコアをロードしています。
まずは、FindIndexを用いて、ロードされたハイスコアの中から”結果スコアより大きい値のうち最小値が格納されているインデックス”を探します。
それが存在すれば=ハイスコアにランクインしていれば、Insertで結果スコアを挿入し、はみ出た末尾の要素を削除後、上書きでSaveメソッドを実行します。
存在しなければ例外処理の方に進み、保存されているハイスコアには手を入れずそのまま値を返します。(一応Saveを入れてますがいらなかったかも)
Saveメソッドの中ではEasySave3に用意されているES3.Saveメソッドを用いて、”level1″という名前のキーにハイスコアを保存しています。
保存したハイスコアをUI上で表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class HighScoreDescriber : MonoBehaviour { HighScoreManager highScoreManager; TextMeshProUGUI[] HighScores = new TextMeshProUGUI[3]; int currentScore; //startだとDescribeHighScoreを呼ぶタイミングに間に合ってないっぽい void Awake() { highScoreManager = GameObject.Find("ScoreManager").GetComponent<HighScoreManager>(); HighScores[0] = GameObject.Find("Score1st").GetComponent<TextMeshProUGUI>(); HighScores[1] = GameObject.Find("Score2nd").GetComponent<TextMeshProUGUI>(); HighScores[2] = GameObject.Find("Score3rd").GetComponent<TextMeshProUGUI>(); } public void DescribeHighScore(List<int> Level1CurrentScores) { for (int i = 0; i < 3; i++) { HighScores[i].text = Level1CurrentScores[i].ToString(); } } } |
DescribeHighScoreメソッドで、渡されたハイスコアを頭から3つ、スコア表示用のオブジェクトに放り込んでいます。
できたのがこちら
1回目のプレイ結果である「21」というスコアが、2回目のプレイの結果時にも残っていることがわかります。参考記事
DoozyUIとArborで開発しやすくリッチなUIを作ろう
この記事の要旨
DoozyUIで作ったイケてるアニメーションのUIボタンの挙動を、Arborで制御して、画面遷移をラクに作ろう!DoozyUIの操作
DoozyUI自体の最初のイントロダクションは、下記Qiitaが参考になります。https://qiita.com/da-1/items/36fa311c09d3bbe9fdc0
DoozyUIを触ってみた
というかこの記事に書かれてるママですね、ボタンを作って、好きなアニメーションをつけましょう。
Arborの操作
UIButtonTransitionに、生成したボタンのインスタンスを演算ノード経由で渡してあげれば、そのボタンを押した時に遷移する先を制御できます。こんな感じ。かんたーん。
悪徳そうに見えて実はゲーム制作を勧めているだけのブログ記事
やっ!どうも!
どう?最近、毎日に「ハリ」ある?女の子にフラれちゃったりとかさ、仕事がうまくいかないとか、 家と職場だけを往復してるな~みたいな虚無感に襲われたりしてない?……
あるよね!!いや、あるんだよ!わかるわかる!俺も君くらいの年の時にさ、そういう人生がどうしようもなく思える時あったんだよね、だからすげーわかるの、その気持ち。辛いよね?だよね~~!!
今日はさ、そのつらい気持ちを少しでも和らげる方法を教えてあげたくて来てもらったんだけど……、どう?聞きたい?
……いやいやいや!ぜんぜん怪しくない!!
その方法ってのがさ、
毎日自分で自分のゲームを作るだけ、っていうやり方なんだよね……!
え?お金かかるんでしょって……?実はね……、
タダなの!
Unityっていうゲームを作れるソフトがタダでも使えるから、それ使えばタダでゲーム作れちゃう。すごくない!?
だってさ、普段ゲーム遊ぼうと思ったら、5000円とか払ってソフト買うわけでしょ?
それを自分で作ったらさ……
タダで遊べちゃう!!びっくりだよね!!
あ、ただ、これだけは買ってもらったほうがいいかも……
……パソコン!
パソコンないとね、Unityは使えないの!なるべくいいパソコンだと嬉しいけど、別にノートパソコンでも大丈夫!え?パソコン売りつけるつもりなんだろうって?
……しないしない!!俺電器屋さんじゃないもん。
とにかくさ、ゲーム作ってる間って、いろんな嫌なこととか悲しいこと辛いことを忘れられるんだよね。
そうやって没頭してると、いつの間にか自分だけのゲームが出来上がってるってワケ!これ、すごくない?!
……ゲーム作るの難しいんだろって?えーと、今まで絵を描いたり作曲したり、プログラミングの経験はある?え?ない?一個も?あちゃー、そうなんだ……
……それでも大丈夫なの!
アセットストアっていう、絵とか3Dモデルをダウンロードできる仕組みがあって、そこからゲームに使える素材をそのまま手に入れることができちゃうんだよね。有料のものもあるんだけど、タダで使えるものもあるから安心していいの!
それでも何から勉強したらいいのか分からないって顔してるじゃん。教えてくれる人がいないと不安だって顔に書いてあるよ、わかりやすいね~~~!!!
そういう時はさ、ここにおいでよ!
だーかーら、大丈夫だって!これもタダ!出会い系とかでもないし怖い人もいないよ!マジ、マジだってw
あとさ、ゲーム作れるようになったらやっぱり人に遊んでもらいたいよね……?
……だよね!なるんだよ!人に遊んでもらいたく!
始めのうちは作ったものが動くだけでうれしいんだけどさ、だんだん自分の自己満足じゃ我慢できなくなってきてさ、人に遊んでもらって褒めてもらったりしたくなるんだよ。
でさ……そうやって褒めてもらえると……
超気持ちいいの!!
わかる?!超気持ちよくなれるんだよ!!ぜひ君にも体感してほしいな~~~!!
しかもさ、ここだけの話なんだけど……
Unity1weekっていうパーティーが3か月にいっぺんくらい開かれてるんだよ……知らなかったでしょ?
人の作品を遊ぶと自分の作品を遊んでもらいやすくなるの!
期間中は#unity1weekのハッシュタグや、さっきの開発者ギルドでみんなが自分のゲームの制作状況を公開しててさ、週末なんかは阿鼻叫喚の地獄絵図になってるの……
そう、地獄だよ……
……でも、最高に楽しいんだってば!!
みんな徹夜でゲーム作っててさ、いい大人たちが「3時間しか寝てないわー」とか「魔剤キメたわー」とか言ってんの。
これってまるで……
漫画やアニメの文化祭みたいな青春じゃない??
大人になって、こんな経験できることある?しかもそれが3か月に一回だよ??
でもさ、基本的にみんな、インターネット上だけの顔も知らない人同士なわけじゃん?そんな人たちとは結局仲良くなれないって思ってない……?
……そう、なれちゃうの!!だってみんな、同じゲーム制作者で、ゲームが大好きなんだよ!!?なれるでしょ!仲良く!
実はときどき、オフ会とか勉強会も開かれてるからそういう場で顔を合わせることも……あーーこれオフレコね!
ほら、とにかくさ……やりたくなってきたでしょ?やろうよ!今日から!ゲーム制作!!
https://unity.com/ja
これ……Unityの公式Webサイトね……!
え?ここのコーヒー代?
……いいのいいの俺払っとくから!今日はありがとね!君がゲーム制作に興味持ってくれたら俺はそれでいいんだって!
じゃ!またね!
EngineのDocumentsを勝手に和訳してみる:How to install the TopDown Engine
イントロダクション
どのバージョンのUnityを利用していようとも、かならず空のプロジェクトにこのアセットをインポートしてください。そうすれば、エンジンのプロジェクト設定がきちんとインポートされます。 本アセットの機能は、Unityパッケージのものをいくつか利用しています。インポートしただけではいくつかエラーがでるでしょうが、その解消方法がこのページに書いてあります。アセットをインポートする
下記の手順で本アセットをインポートしてください。- Unity Hubから新しいプロジェクトを作成:Unityバージョンは2019.1で、3Dプロジェクトで作成してください。
- アセットストアから本アセットをインポートしてください。(くれぐれも空のプロジェクトに)
- インポートすると、CinemachineおよびPostprocessingの参照エラーが表示されるでしょうが、パニックにならず、落ち着いてこの記事を読んでください。:)
Unity 2019.1以上の場合
インストールすると、大量のエラーに見舞われるでしょう。大丈夫です、そういうものです。エラーを修正するためには、ファイルエクスプローラから(Unityからではなく) TopDown Engineのルートフォルダに あるmanifest.jsonファイルをコピーしあなたのプロジェクトのPackagesフォルダへペーストしてください。(もし既に存在する場合は上書き)Unityを再起動するか、Packagesフォルダを再インポートする必要があるかもしれませんが、大体はそのまま動きます。LWRP, HDRP あるいはマニュアルでのパッケージ管理
マニフェストファイルを置換すると、簡単かつ迅速に本アセットを動かせるようになりますが、この方法にはいくつか問題が残ります。例えば、LWRPやHDRPといった、利用するパッケージを自分自身でコントロールしたい場合です。そういった場合は、依存するアセットを全て手動でインストールすると良いでしょう。その場合に必要なアセットはCinemahine,2D Pixel Perfect, PostProcessing Stackの3つです。Unity 2018.3以下の場合
空のプロジェクトへのアセットインポートが完了したら、TopDown Engineは準備完了です。 CinemachineかPostProcessingに関するエラーが出ている場合は、こちらからアセットのプロジェクトセッティングとパッケージマニフェストをダウンロードしてください。Unityを終了し、これらのファイルをダウンロードしたらあなたのプロジェクトへコピーしてください。manifest.jsonファイルはproject/Packagesディレクトリへ、ProjectSettings.assetファイルは ProjectSettingsディレクトリへ格納してください。これら2つのファイルを上書きしたら、再度Unityをひらけばうまくいくはずです。 それでもダメなら、あなたがこれまで行った手順、起こったことをサポートへメールで送ってください。あなたの助けになれたら嬉しいです。どうしてこれらのエラーが出るの?
本件は、Unityがアセット制作者に対し、アセットストアへのProject Settingsフォルダ(入力設定や品質などを含む)のアップロードは許可しているものの、どのアセットを使用するか記述するmanifest.jsonファイルのアップロードを許可していないために発生する問題です(今回の例で言えばPostProcessingとCinemachine)。近い将来修正されるようですが、しばらくの間は上記の手順を踏んでください。カメラがズームインしすぎてる
Unityのバージョンが2018.3以下の場合、いくつかの設定が失われてしまうために発生することがあるようです。でも心配なく。2Dの場合は、MainCameraのPixel Perfect CameraコンポーネントのAssets Pixels Per Unitの値が16になっていること、仮想カメラのorthographic sizeが6.9となっているか確認してください。3Dの場合は、仮想カメラ(大体の場合CM vcam1という名前)を選択し、field of viewの値を40に設定してください。TopDown EngineのDocumentsを勝手に和訳してみる:Introduction to the TopDown Engine
はじめに
自分の理解を深める&備忘録としてTopDown Engineのドキュメントを和訳してみます。
公式でもなければ英語ネイティブでもないので参考程度に。
まずは“Introduction to the TopDown Engine”から。
はじまるよー
TopDown Engineのイントロダクション
- TopDown Engineってなに?
- インストールしたらエラー出たんだけど / カメラがうごかないんだけど!
- どこからはじめればいいの?
TopDown Engineってなに?
TopDown Engineはトップダウンビューゲームの制作のためのフレームワークです。Corgi Engineの制作者によって開発され、Unity Asset Storeから購入できます。
非常に軽快で、機能が多く、モバイルでも作りやすく、安定しておりかつ拡張性も持ったゲームエンジンとして、クオリティとプレイフィールを重視しています。Unityを使っていますぐ、あなたオリジナルのトップダウンビューゲーム(2Dでも3Dでも!)を作り始めましょう。
あらゆるトップダウンビューゲームの基礎として動作するようデザインされています。例えば、Binding of Isaacのようなダンジョンを探索するものから、レトロなゼルダのようなアドベンチャーゲーム、ファイナルファイトのような敵をすべて殲滅するものや、Hotline Miamiのような銃を使うゲームまで、ゲーム画面を上部から移すようなカメラ配置のゲームならあらゆるものが制作できます。
軽快、本番リリースにも利用可能、万能、軽量、拡張も容易なので、あなたのプロジェクトをグンと加速させてくれます。
インストールしたらエラー出たんだけど / カメラがうごかないんだけど!
アセット内にある”IMPORTANT-HOW-TO-INSTALL.txt”ファイルのinstall instrucionsを確認してください。パートごとに分かれたドキュメントも用意してあります。
どこからはじめればいいの?
ドキュメントのすべてに目を通す必要はありません。このエンジンはUnityの練習となることも念頭に置いて制作されており、多くのヘルプも詰め込まれています。これがあなたの初めてのUnityプロジェクトでないなら、おそらく自分で解決できるでしょう。もし何かわからないことがあれば、いつでもここに戻ってきてください。
左側にあるメニューから各項目へ進むことができます。このドキュメントは機能にフォーカスしています。もしコード自体に疑問点があれば、API Documentの方を参照するのが良いでしょう。また、コードのコメントを直接読むのもおすすめです。たいていの疑問は、コメントでカバーしています。
機能のリストがほしかったり、「この機能はあるのかな?」と思ったら、こちらのページを見てください。変更履歴や、そのほか役に立つものがあります。
ビデオチュートリアルもあります。
それでも解決しなければ、いつでもアセットストアのサポートリンクからメールで連絡してください。
TopDown Engine 使ってみる【インストールと最小構成】
TopDown Engineとは
TopDown Engine は見下ろし型のアクションゲームを簡単に作るためのスクリプトやデモ素材が含まれる有料アセットです。
敵AIやマップ、インベントリなどの仕組みを組み合わせることで、オールドスタイルのゼルダやホットラインマイアミライクなゲームを作ることができます。
具体的にどんなことができるかは、公式のツアーガイドを見たり、アセット内に含まれるデモシーンをプレイしてみるとわかってきます。
インストール方法
アセットストアからインポートするだけではエラーが表示されてしまいます。
ChinemachineとPostProcessingをPackageManagerからインストールすることで解消されますので焦らずに。
最小構成
このアセットを使ってゲームを作るには、「かならずシーンにこれを置いてね!」という最小構成のオブジェクトがあります。
公式ドキュメントMinimal Scene Requirements
空っぽのシーンにまずはこれを配置しましょう。Demos>Minimal2Dに置いてあるオブジェクトをまるっとシーンにコピーにするだけでなんとかなりました。
これだけでもう、シーンにキャラクターが登場し、移動したりインベントリを開いたり、銃を撃って攻撃することができます。再生して色々やってみましょう。
いつもだったら三日くらいはかけてそうな処理がたった十分程度でできてしまいました。
丸いコアラのやつは、試しに置いてみたマトです。
次回は、NPCキャラクターの設置とそのAIを作っていきます。