- 投稿日:2019-03-10T22:43:25+09:00
【Unity(C#)】ゲームオブジェクトを毎回違う場所に配置する方法
この記事は『プログラミング完全未経験からUnityでの開発現場に迎え入れてもらえた世界一の幸せ者』
の記事です。そのつもりでお読みください。
ランダムではない
毎回違う場所に配置すると書きましたが、
ランダムとは少しだけ違います。私がやりたかったことは2回連続で同じ場所には絶対に出ないという実装です。
なのでちょっと面倒でした。
↓↓↓補足(2019.3/11)↓↓↓
同じエリアに連続出現しないだけで座標は毎回ランダムにしたい
これです!まさにこれ!
コメントありがとうございます!考え方
上のとてもわかりやすい図のように分けた場合、
もし0に出現したら次は必ず1、2、3のどこかに出現するようにします。もっと効率の良い方法があるのかもしれませんが、ちょっと急いでたのでこのやり方で実装しました。
値を返すメソッドを用意
ランダムな値を渡すとその値と同じ値を返すメソッドを用意しました。
これにより、一度出現したエリアの番号を記録できます。int? RandomArea(int patternNum) { if (patternNum == 0) { holeParentPosition = new Vector3(randomX_A, holeParentPosition.y, randomZ_A); this.gameObject.transform.localPosition = holeParentPosition; return 0; } if (patternNum == 1) { holeParentPosition = new Vector3(randomX_B, holeParentPosition.y, randomZ_B); this.gameObject.transform.localPosition = holeParentPosition; return 1; } if (patternNum == 2) { holeParentPosition = new Vector3(randomX_C, holeParentPosition.y, randomZ_C); this.gameObject.transform.localPosition = holeParentPosition; return 2; } if (patternNum == 3) { holeParentPosition = new Vector3(randomX_D, holeParentPosition.y, randomZ_D); this.gameObject.transform.localPosition = holeParentPosition; return 3; } return null; }最終的なコード
public GameObject hole; Vector3 holeParentPosition; int[] patternNumber = { 0, 1, 2, 3 }; int patternArray; float randomX_A; float randomZ_A; float randomX_B; float randomZ_B; float randomX_C; float randomZ_C; float randomX_D; float randomZ_D; void Start() { holeParentPosition = this.gameObject.transform.localPosition; } void Update() { patternArray = Random.Range(0, patternNumber.Length); randomX_A = Random.Range(0.5f, 4.0f); randomZ_A = Random.Range(-5f, -1.5f); randomX_B = Random.Range(0.5f, 4.0f); randomZ_B = Random.Range(-9f, -5.5f); randomX_C = Random.Range(-4.0f, -0.5f); randomZ_C = Random.Range(-9f, -5.5f); randomX_D = Random.Range(-4.0f, -0.5f); randomZ_D = Random.Range(-5f, -1.5f); //コルーチン開始(一回で抜ける) if (ThisProjectSingleton.Instance.isGameStart) { StartCoroutine(HoleRandomCoroutine()); ThisProjectSingleton.Instance.isGameStart = false; } } int? RandomArea(int patternNum) { if (patternNum == 0) { holeParentPosition = new Vector3(randomX_A, holeParentPosition.y, randomZ_A); this.gameObject.transform.localPosition = holeParentPosition; return 0; } if (patternNum == 1) { holeParentPosition = new Vector3(randomX_B, holeParentPosition.y, randomZ_B); this.gameObject.transform.localPosition = holeParentPosition; return 1; } if (patternNum == 2) { holeParentPosition = new Vector3(randomX_C, holeParentPosition.y, randomZ_C); this.gameObject.transform.localPosition = holeParentPosition; return 2; } if (patternNum == 3) { holeParentPosition = new Vector3(randomX_D, holeParentPosition.y, randomZ_D); this.gameObject.transform.localPosition = holeParentPosition; return 3; } return null; } IEnumerator HoleRandomCoroutine() { int? tmpNum = 0; int? memoryNum = 0; while (/*ゲームオーバーの条件を記述*/) { yield return new WaitForSeconds(0.5f); tmpNum= RandomArea(patternNumber[patternArray]); //もしランダムな数字( tmpNum)が前回(memoryNum)と一致したら通過。別の数字をtmpNumに代入して抜ける while (tmpNum == memoryNum) { yield return new WaitForEndOfFrame(); tmpNum = RandomArea(patternNumber[patternArray]); } memoryNum = tmpNum; hole.SetActive(true); //ホールにボールが入るまで待つ yield return new WaitUntil(() => ThisProjectSingleton.Instance.isHoleEnter); ScoreText.ScoreAdd(); //ホールが消える yield return new WaitForSeconds(0.5f); hole.SetActive(false); ThisProjectSingleton.Instance.isHoleEnter = false; } }いま自分で読み返しても読みづらいしもっといい方法がありそうです。
こんな方法もあるよ~って方、コメントください。unity1week
unity1weekという企画がありまして、
その名の通りUnityを用いて一週間でゲームを作ろうというおもしろい企画です。私も参加するつもりなのですが、
そこで作るのはWebGLというブラウザ上で起動する形式です。せっかく作ったのにビルドとかアップロードの仕方がわからない!
と本番でならないようにunity1dayと称して、
簡単なゲームを作りunityroomにテストアップロードしました。今回紹介したゲームオブジェクトを毎回違う場所に配置する方法も用いているので
よかったら覗いてみてください。↓人のコード見た後にそのゲームをプレイするの結構おもしろいです。
- 投稿日:2019-03-10T21:09:16+09:00
Visual Studio Codeを使い、C#の開発環境を途中まで整える
今回はMicrosoftにより開発されたソースコードエディターであるVisual Studio Codeを使ってC#の統合開発環境を整えるところまでまとめたいと思います。
具体的な手順は以下の通りです。
- Visual Studio Codeをインストールする。
- .NET Core SDKをインストールする。
- Visual Studio Codeを開き、C#の拡張機能をインストールする。
- 試しにHello Worldのコードを実行してみる。
Visual Studio Codeをインストールする
まずVisual Studio Codeをインストールします。
以下のリンクを開き、「Download for [OS名] Stable Build」という
緑色のリンクを選択するとVisual Studio Codeのダウンロードが開始されます。右の記号を選択すると、詳細なインストーラの選択が可能となります。
ダウンロードしたインストーラを起動し、Visual Studio Codeのインストールを開始します。
各種設定は今回はデフォルトのままで行いました。.NET Core SDKをインストールする
次に、アプリケーション制作のためのプラットフォームを提供する、.NET Core SDKをインストールします。
以下のリンクから「Download .NET Core SDK」を選択し、ダウンロードします。先ほどと同じように、ダウンロードしたインストーラを起動し、インストールを開始します。
インストールの際に特に設定は要りません。C#の拡張機能をインストールする
そして、C#の開発環境を整えるためにC#の拡張機能をインストールします。
Visual Studio Code から Marketplaceでインストールできるようですが、
今回はWebブラウザからインストールします。Visual Studio Codeをインストールした状態で、
下記のリンクからC#の拡張機能のページへ移り、「Install」を選択します。
出現したポップアップ画面の「Visual Studio Codeを実行する」を選択します。するとVisual Studio Codeが開かれ、C#の拡張機能ページが表示されるため、
再度「Install」を選択します。選択してInstalledになるまで待ちましょう。Installedの表示になったらokです。
試しにHello Worldのコードを実行してみる。
Visual Studio Codeを開き、
左上のExplorerアイコンをクリックして、Open Folderを選択します。コードを入れる適当なフォルダーを選択します。
フォルダー名はVisual Studio Codeにおけるプロジェクト名となります。次に、上メニューより[View]>[Terminal]と選択し、(Ctrl+@でも可)
下部分に表示されたTerminal上でdotnet new consoleと実行します。
その際に、もし下記のエラーが出力された場合、dotnet : 用語 'dotnet' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。名前が正しく記 述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してください。 発生場所 行:1 文字:1以下の手順を踏むと、 解消される場合があります。
- [プログラムと機能]から[アンインストールまたは変更]へと移り、
- 最新版のMicrosoft Visual C++ Redistributable (x86)を選択し、修復を選択。
- 次に最新版のMicrosoft Visual C++ Redistributable (x64)を選択し、修復を選択。
- 最後に.NET Core SDK 1.0.1.を選択し、修復を選択。
- 4の修復が完了したら、Visual Studio Codeを再起動。
参考: https://stackoverflow.com/questions/40568758/dotnet-is-not-recognized-as-the-name-of-a-cmdlet
また、Terminalの背景色が蛍光ペンで塗りつぶされたようにおかしくなった場合には、PowerShellのプロパティから背景色を黒に合わせると(デフォルトのカラースキームのTerminalの背景色に合わせると)表示が正常に戻ります。
さて、「dotnet new console」とコマンドを打った時点で、既にHello Worldのコードは完成しています。(Program.ps)
そこでTerminalで
dotnet runと実行すると、「Hello World」と出力されます。
まとめ
今回はここまでにしたいと思います。
デバッグやクラスの追加はまた次回、ということで
自分もさらに勉強して知識や経験を吸収したいと思います。
- 投稿日:2019-03-10T19:35:18+09:00
WPF の ListBox と DataGrid で Dcitionary をバインドする
WPF の ListBox と DataGrid で Dcitionary をバインドする
名前と値を Dictionary を使ってバインドしようとして少しはまって結果的に ViewModel に Dictionary の Value についての Binding 設定を一切書かずにすっきりできたのでメモ。
開発環境
- Windows 10
- Visual Studio 2017
ソリューションの拡張機能
- Prism.Unity
新規プロジェクトの作成
Template Pack を参照ください。
RegionManagerにViewを登録
MainWindow に ContentView を登録
MainWindowViewModel.cspublic MainWindowViewModel(IRegionManager regionManager) { regionManager.RegisterViewWithRegion("ContentRegion", typeof(ContentView)); }
Person クラス を作成
Models フォルダを作り Person クラスを作成
Person.csclass Person { public string Name { get; set; } public string Sex { get; set; } public int Age { get; set; } }ContentViewModel を ViewModels に作成
バインド用プロパティを定義してコンストラクタでサンプルデータ設定
ContentViewModel.cspublic ContentViewModel() { this.PersonDictionaries = new Dictionary<string, Person>() { {"長男", new Person(){Name="Ichiro", Sex ="男", Age=10, } }, {"次男", new Person(){Name="Jiro", Sex ="男", Age=9, } }, {"三男", new Person(){Name="Saburo", Sex ="男", Age=8, } }, {"四男", new Person(){Name="Shiro", Sex ="男", Age=7, } }, {"長女", new Person(){Name="Goro", Sex ="男", Age=8, } }, }; this.Items = new Dictionary<string, Dictionary<string, string>>() { {"長男", new Dictionary<string, string>() {{"名前", "一郎"}, { "性別", "男" }, { "年齢", "20"}} }, {"次男", new Dictionary<string, string>() {{"名前", "二郎"}, { "性別", "男" }, { "年齢", "19"}} }, {"三男", new Dictionary<string, string>() {{"名前", "三郎"}, { "性別", "男" }, { "年齢", "18"}} }, {"四男", new Dictionary<string, string>() {{"名前", "四郎"}, { "性別", "男" }, { "年齢", "17"}} }, {"長女", new Dictionary<string, string>() {{"名前", "花子"}, { "性別", "女" }, { "年齢", "18"}} }, }; } private Dictionary<string, Person> _personDictionaries; public Dictionary<string, Person> PersonDictionaries { get { return _personDictionaries; } set { SetProperty(ref _personDictionaries, value); } } private Dictionary<string, Dictionary<string, string>> _Items; public Dictionary<string, Dictionary<string, string>> Items { get { return _Items; } set { SetProperty(ref _Items, value); } }
ContentView を Views に作成
ここで親データ(ListBox)と子データ(TextBlock or DataGrid)で直接バインド設定する
ListBox は x:Name で名前付けする
ListBox で Dictionary をバインドして、DisplayMenber に Key を設定して SelectedValuePath に Value を設定
Value は 名前付けした ListBox の SelectedValue を直接参照するため ViewModel 側でバインドプロパティを定義する必要がない
ContentView.xaml<UserControl x:Class="PrismDictionaryBinding.Views.ContentView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <ListBox x:Name="lb1" ItemsSource="{Binding PersonDictionaries}" DisplayMemberPath="Key" SelectedValuePath="Value" /> <Viewbox Grid.Column="1" > <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch"> <TextBlock Text="{Binding ElementName=lb1, Path=SelectedValue.Name}"/> <TextBlock Text="{Binding ElementName=lb1, Path=SelectedValue.Sex}"/> <TextBlock Text="{Binding ElementName=lb1, Path=SelectedValue.Age}"/> </StackPanel> </Viewbox> <ListBox x:Name="lb2" Grid.Row="1" ItemsSource="{Binding Items}" DisplayMemberPath="Key" SelectedValuePath="Value" /> <DataGrid Grid.Row="1" Grid.Column="1" ItemsSource="{Binding ElementName=lb2, Path=SelectedValue}" /> </Grid> </UserControl>
実行
上が Dictionary<string, person> 下が Dictionary<string, Dictionary<string, string>>まとめ
最初は SelectedItem をバインドしてそのプロパティセッターで対象データを表示しるということを ViewModel 側でやっていたんですが直接親コントロールとなる ListBox のプロパティを参照するようにしたことでシンプルに書くことが出来ました。
あと、SelectedItem の型を Dictionary にしていてエラーになってなぜかーと思っていたら KeyValuePair の存在をすっかり忘れていてハマりました…。
ソースは こちら に置いてあります。
- 投稿日:2019-03-10T18:55:24+09:00
【C#】GPS信号を使用して現在の時刻を取得する
なんでそんなことするの?
端末がインターネットに接続できない場合、サーバから現在時刻を取得できません。
GPS信号(NMEAフォーマットデータ)には、UTC時刻が含まれているため、
インターネットには繋がらないけどGPSは拾えるという特殊な環境である場合、選択肢となるかもしれません。Microsoft.WindowsAPICodePack.Sensors を使う
.Net標準であるGeoCoordinateWatcherで取得できる情報は、緯度・経度に限られているので、
Microsoft.WindowsAPICodePack.Sensors名前空間のSensorクラスを使用します。GPSセンサを用意
Sensorクラスを使うためには、GPSセンサが必要です。
イマドキのWindows端末には基本的にGPSセンサが搭載されていないので、用意する必要があります。とりあえず動作を試すだけであれば、amazon格安センサ( https://www.amazon.co.jp/gp/product/B01MA21TSX/ )で十分です。
ソースを動かすには、デバイスマネージャーのセンサーにGPSセンサーが追加されていれば問題ありません。
ソースコード
using Microsoft.WindowsAPICodePack.Sensors; // 位置情報GUID // 参考:https://docs.microsoft.com/en-us/windows/desktop/sensorsapi/sensor-category-location private static Guid SENSOR_DATA_TYPE_LOCATION_GUID = new Guid("055C74D8-CA6F-47D6-95C6-1ED3637A0FF4"); // GPSセンサの取得 Sensor GeolocationSensor = SensorManager.GetSensorsByTypeId(SensorTypes.LocationGps)[0]; // GPS信号を取得する度に、イベント実行 GeolocationSensor.DataReportChanged += DataReportChanged;// GPS信号受信時の処理 private void DataReportChanged(Sensor sender, EventArgs e) { // NMEAフォーマットデータ string[] gpsData = sender.DataReport.Values[SENSOR_DATA_TYPE_LOCATION_GUID][25].ToString().Split(','); // gpsData[1]:HHmmss.00 gpsData[9]:yyMMdd // NMEAフォーマットデータに含まれる時刻は、UTC時刻となる DateTimeOffset dto = new DateTimeOffset( DateTime.ParseExact(string.Format("{0}{1}", gpsData[9], gpsData[1].Substring(0, 6)), "yyMMddHHmmss", null), TimeSpan.Zero); }https://github.com/TakadaTentaro/GetGPSTime
GPS信号データは、DataReportChangedイベントのsenderを通じて取得します。
上記のGPSセンサを使用した環境では、
sender.DataReport.Values[SENSOR_DATA_TYPE_LOCATION_GUID]は、[0]:経度、[1]:緯度と続いていき、[25]にNMEAフォーマットの生データ(\$GPRMC,\$GPVTG,\$GPGNS...)が格納されています。
- 投稿日:2019-03-10T14:36:47+09:00
Windows Formでの高DPI対応でハマったところ
マニフェストファイルの設定
基本的には下記ページの通りに設定すれば、文字がボヤける現象をほぼ自動的に回避できるはずです。
Windows フォーム アプリの DPI Aware への変更自分のプロジェクトでは、単体の実行ファイルのみで動作させたときに適用されませんでした。
(マニフェストファイルが同一ディレクトリにある場合はそのファイルが読み込まれて回避設定が適用されます).csprojの設定
そこで、csprojのGenerateManifestsを次のようにfalseに変更しました。
これで単体でも回避できるようになりました。
プロジェクト設定画面のどこかに設定項目があるのかもしれないのですが、見当たりませんでした…。project.csproj<PropertyGroup> <GenerateManifests>false</GenerateManifests> </PropertyGroup>
- 投稿日:2019-03-10T12:13:07+09:00
【C#】画像生成の基本(Bitmap)
はじめに
【Java】簡単な模様を描くのコードを転用して、「簡単な模様の画像」をC#で生成してみました。
コード
- 以下の2つのライブラリを使うと、ラスター形式の画像(BMP,JPG,PNGなど)を操作することができます。
- System.Drawing;
- using System.Drawing.Imaging;
- 所望の座標のピクセルに対する色付けは、SetPixelメソッドを使います。
{Bitmapオブジェクト}.SetPixcel(x座標,y座標,色)
- 生成した画像の保存は、Saveメソッドを使います。
{Bitmapオブジェクト}.Save({保存先のパス}, {画像の形式})
- 余談ですが、System.Drawingは「GDI+」というグラフィックサブシステムを利用しているそうです。
- System.DrawingのAPIを見ると、「GDI+の基本的なグラフィックス機能を使用できるようにします」と書かれています。
ImageCreator.cspublic class ImageCreator { /// <summary> /// バツ印の画像を生成する。 /// </summary> /// <param name="size">画像の縦・横のサイズ。px数を指定する。</param> public static void CreateCrossMark(int size) { Bitmap bmp = new Bitmap(size, size); // 全ピクセルに色付け for (int row = 0; row < size; row++) { for (int col = 0; col < size; col++) { if (row == col || row + col == size - 1) { bmp.SetPixel(col, row, Color.White); } else { bmp.SetPixel(col, row, Color.Black); } } } bmp.Save(@"C:\image\cross_mark.png", ImageFormat.Png); } }生成された画像
- 以下のように「黒地に白のバツ印」の画像を生成できました。
- CreateCrossMarkメソッドの引数の値を変えることで、大小様々なサイズの画像を生成できました。
まとめ
- 単純な画像を生成するだけであれば、Bitmapクラスを使うことで比較的簡単に実装できます。
- ただし、Bitmapオブジェクトに対する操作は低速なので、Bitmapオブジェクトに対する操作の回数を極力減らすのが高速化のポイントになります。
- また、画像のリソースの解放処理をきちんとしておかないと、実用に耐えうるコードにはならないようです。
- 投稿日:2019-03-10T01:35:16+09:00
[Unity][ParticleSystem]3D座標を起点にuGUI上にパーティクルを発生・収束させる
サンプル動画
移動や連発にも対応してようやく納得いくものが出来た
— madoramu (@madoramu_f) 2019年3月8日
色々妥協してる部分もあるけど個人的には満足 pic.twitter.com/hWVOqxVhAw3Dアクションゲームなどで良くある、
「敵を攻撃したらパーティクルが発生して、UI上のゲージに向かって飛んでゲージが溜まる。」
というものを実装してみました。
(割と需要あると思っているのですが、どこにもサンプルが無かったので自作することに)サンプルプロジェクト
以下のGithubに上げてあります
https://github.com/madoramu/ParticleHorming
※サンプル動画は別プロジェクトの物なので、上記URLのプロジェクトは少し内容が異なります。環境
Unity2018.3
WindowsとAndroidで動作確認済み
重要:ScreenSpaceCamera設定のCanvasのみ対応しています実装方法
サンプルプロジェクトの中身を抜粋して説明していきます。
細かい部分などはプロジェクトを閲覧してください。メインカメラとUIカメラの用意・設定
メインカメラ
こちらはキャラクターの追尾、およびUI以外の描画を担当。
- CullingMaskで「UI」を除外する。
- Depthを「0」にする。
- UIカメラより低ければおk
UIカメラ
UIの描画のみ担当。
- メインカメラには絶対映らない場所に移動させる
- AudioListenerは外しておく
- ClearFlagsを「Depth Only」にする。
- CullingMaskで「UI」だけにする。
- Depthを「10」にする。
- メインカメラより高ければおk
上記二つのカメラ設定により、メインカメラの描画の後にUIレイヤーの情報が上に描画されます。
キャンバスの用意と設定(重要)
UI表示用・座標変換用で2つのScreenSpaceCamera設定Canvasを用意します。
- UI表示用にはUIカメラ、座標変換用にはメインカメラをそれぞれ設定する
- RectTransform以外のパラメーターは全て同じにする事
- 一応念のため
※何故設定カメラ以外同じパラメーターのCanvasを二つ使用したのかは感想に記載しています。
ParticleSystemの設定
ここは好みに合わせて弄って問題ありませんが、以下の2点は必須です。
- ParticleSystemオブジェクトのLayerは「必ず「UI」に設定する事」
- UI表示用のCanvas直下に配置する事
「何故World設定か?」
- 後述のパーティクル発生処理で解説しますが、ParticleSystemそのものを移動させるので、Localだとその移動にパーティクルも追従してしまうため。
「Rederer→Order in Layerについて」
- 上記画像には映っていませんが、今回はUIより前面に出したかったため値を増やしました。ここはお好みでおk。
パーティクル発生処理
ParticleSystem.Emitを使用して、意図的にパーティクルを発生させることが出来ます。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.Emit.html処理の流れ
- 3D座標からScreenSpaceCanvas上の2D座標に変換
- ゲームだと主に敵に攻撃が当たった時の、敵座標位置が3D座標になります。
- テラシュールブログを参考(というかほぼ丸パクリ)にして作成しました。
- 下記ページの「World Space を Screen Space Cameraへ」です。
- http://tsubakit1.hateblo.jp/entry/2016/03/01/020510
- 変換した2D座標にParticleSystemを移動
- Emitでパーティクル生成。
以下コード抜粋
ParticleHorming.cspublic void CreateParticle() { // 3D空間座標からカメラスクリーン上の座標に変換する Vector3 basePos = m_Emit3DTransformList.GetRandom().position; // GetRandom()についてはListExtensionsを参照 Vector2 screenPos = m_Camera.WorldToScreenPoint(basePos); // カメラスクリーン座標をキャンバス上のローカル座標に変換する Vector2 cameraCanvasPos = Vector2.zero; RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RaycasterCameraCanvasRectTransform, screenPos, m_Camera, out cameraCanvasPos); // 座標確認 Debug.LogFormat("rectPos{0}", cameraCanvasPos); // ParticleSystemを放出位置に移動させてEmit m_ParticleSystem.transform.localPosition = cameraCanvasPos; m_ParticleSystem.Emit(m_EmitParticleCount); }パーティクル更新(収束)処理
普段パーティクルをスクリプト側で操作することは余り無いですが、今回は特定位置に収束させたかったのでググった結果、公式サイトで以下のページが出てきました。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.GetParticles.htmlこのページを参考に以下の様な処理で更新させることにしました。
ParticleHorming.cs// 更新 for(int i = 0; i < m_ActiveParticleCount; ++i) { float rate = (1.0f - m_ParticleList[i].remainingLifetime / m_ParticleList[i].startLifetime); rate = Mathf.Pow(rate, m_ReactionDistance); // 指数関数を加えることにより、収束する勢いを変更できるようにしてる m_ParticleList[i].position = Vector3.Lerp(m_ParticleList[i].position, m_TargetTransform.position, rate); } m_ParticleSystem.SetParticles(m_ParticleList, m_ActiveParticleCount);今回は指数関数を使って、等速直線移動ではなく少しアレンジをしています。
ここに関しては書き方によって幾通りも表現が出来ると思います。感想
当初はScreenSpaceCameraのCanvas一つで解決できないか試行錯誤していましたが、キャラを追尾する = Canvasが移動する関係上、パーティクルが毎フレームぶれたり座標がおかしなことになったりした結果、今の形に落ち着きました。
冒頭でも言った通りScreenSpaceOverlay設定のCanvasには対応できないので、結構使いどころは限定的かも。
ですが、ParticleSystem上でパーティクルをいつも通り設定できるメリットは大きいので、個人的には満足度高めです。
- 投稿日:2019-03-10T00:01:28+09:00
Bit演算のちょっとしたテクニック備忘録。
初めに。
あくまで自分用のメモです。
最適化しきれていなかったり、時々間違えたりします。
間違いのご指摘や、何か他に良い方法をご存知でしたら、
コメントの方よろしくお願いいたします。使用言語
- C#
一覧
Abs
絶対値を返します。
public static int Abs(int num) => (num ^ (num >> 31)) - (num >> 31);
Sign
符号を返します。 (負数 => -1,零 => 0,正数 => 1)
public static int Sign(int num) => (num >> 31) - (-num >> 31);
Clamp
数値を a以上b以内 もしくは b以上a以内 に制限します。
public static int Clamp(int num, int a, int b) => (a + b + ((Abs(num - a) - Abs(num - b)) ^ ((b - a) >> 31)) - ((b - a) >> 31)) >> 1;
LSB
最下位ビットを取得します。
public static int LSB(int num) => num & -num;
MSB
最上位ビットを取得します。
public static int MSB(int num) => num & ~(FillMSBtoLowest(num) >> 1);
FillMSBtoLowest
最上位ビットから下位のビットすべてを1で埋めます。
public static int FillMSBtoLowest(int num) { num |= num >> 1; num |= num >> 2; num |= num >> 4; num |= num >> 8; return num >> 16; }
FillLSBtoHighest
最下位ビットから上位のビットすべてを1で埋めます。
public static int FillLSBtoHighest(int num) { num |= num << 1; num |= num << 2; num |= num << 4; num |= num << 8; return num << 16; }
BitCount
立っているビットの個数(1の個数)を取得します。
public static int BitCount(int num) { num = (num & 0x55555555) + ((num >> 1) & 0x55555555); num = (num & 0x33333333) + ((num >> 2) & 0x33333333); num = (num & 0x0F0F0F0F) + ((num >> 4) & 0x0F0F0F0F); num = (num & 0x00FF00FF) + ((num >> 8) & 0x00FF00FF); return (num & 0x0000FFFF) + ((num >> 16) & 0x0000FFFF); }