20200407のUnityに関する記事は6件です。

C# メモリ上の数値の改ざんを防ぐ

成果物

C#のコンソールテスト用です
https://github.com/Oinary/SecureValue/blob/master/Program.cs

1.やりたいこと

・改ざんされちゃマズい数値を守りたい!(ゲーム内のHPやお金など)
・ファイルだけではなくメモリ上の数値も保護したい。(今回はInt型とFloat型)

2.何を使えば出来るか

XOR(排他的論理和)で解決。
https://qiita.com/kuuso1/items/778acaa7011d98a3ff3a

簡単に言うと2進数で2つの数を演算したとき
片方がTrue(1)ならTrue。      0 xor 1 → 1
両方がTrue又はFalse(0)ならFalse。  0 xor 0 → 0

これって同じ値で演算しなおすと元の値に戻るんです。
1010 xor 0110 → 1100
1100 xor 0110 → 1010

科学の力ってすげぇ(てきとう

3.実装してみた

まずXORを使うのには、元の値とそれを合わせる値が必要。
C#でランダムな整数をもらってきます。(これはちゃんと保存しましょう)

Random.Next()
https://docs.microsoft.com/ja-jp/dotnet/api/system.random.next?view=netframework-4.8

あとは ^ 演算子で保存、復元すれば解決!

SecureInt.cs
private int Seed;
private int Value;
public int _Value
 {
    get
    {
        return Value ^ Seed;
    }
    set
    {
        Seed = new Random().Next()//ランダムなInt
        Value = value ^ Seed;//あとはお好きに
    }
}

3-1.そうは上手くいかなかった

Int型は何も問題なく実装できましたが…。
Float型ってXORを直接は使えない。(馬鹿には分からなかった。

3-2.じゃぁどう回避しようか

ヒントがここにあった…。
https://qiita.com/nia_tn1012/items/d26f0fc993895a09b30b

Floatで後ろ23ビットは仮数部と呼ばれる、我々が目にする数が格納されているところがあります。
例 2.345 → 2345 (小数点を無くした値になります)
その仮数部を隠せば良さげです。
※これはイメージです

Sample
float F = 1.55f;//得たfloat
var I = BitConverter.ToInt32(BitConverter.GetBytes(F),0);//これをbyte[]にして、Int型にさせる
var SignificandPart = I << 9;//左に9ビットシフトすると仮数部だけ残る
var SecureValue = SignificandPart ^ Seed;//あとは煮るなり焼くなり
//戻すときはこの逆で

で出来上がりなのですが、まぁ操作多いんですよ。
なんかこう、もっとサクッとFloatをIntにできないんですかね…。

・・・あったわ

その参照記事の下に別の方法が書かれています。
ポインタを扱うこと がポイント♪ で内部値をInt型で取得できます。

SecureFloat.cs
private int SecValue;
private int Seed;
public unsafe float _Value
{
   get
   {
       var result = SecValue ^ Seed;
       return BitConverter.ToSingle(BitConverter.GetBytes(result), 0);//戻すときは一度byte[]にしてからFloatに変換。
   }
   set
   {
      CalculatingSeed();
      int v = *((int*)&value);//&valueでvalueのポインタを取得、(int*)でInt型のポインタを格納、最初の*でそのポインタの値を指す。
      SecValue = v ^ Seed;//あとはお好きに
   }
}

ポインタの使用は、本来はバグなど意図しない動作を防ぐために制限されています。
それを解除するため、unsafe を明示します。(VisualStudioの設定もお忘れずに)

これで守りたい値の保護方法が実装できそうです。

4.さいごに

不正の種類はいくつもあるので、それ相応の対応をしなければなりません。
が、あの手この手で不正してくるはずです。
実装するコストと見合っているかどうかも検討しないと、クオリティや製作時間に響いちゃいます。

僕みたいな初級の個人ゲームクリエイターならお遊び程度でいいんじゃないでしょうかね。

では初記事をご覧いただきありがとうございました。

※ってか一番大事なメモリエディタの画像なくね?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

期間限定無料の Unity Learn Premium の ML-Agents: Penguins が良かった

Unity Learn Premium が無料で提供されているものの、たくさんあるし、英語だしと怯んでいましたが、その中の一つをやってみたらとても良かったというお話です。

良かった理由

  1. わずか5時間で、
  2. 環境構築から始まって強化学習させたモデルを利用した、
  3. 魚を採って子どもに与えるペンギンを作って動かす体験ができます

ml-penguin.gif

どうやって学習するの?なにこの数値?とか、
なんかわからないから難しい、怖いというところから脱することができます。

5時間

頑張れば1日でできるぐらいの量なのが良いと思っています。長いと疲れるし、途中でき飽きちゃいますが、やるぞって決めてやり切れるぐらいの量。間延びしても2日あればやり切れるぐらい。

強化学習させたモデル

環境構築から始めたにもかかわらず、終わるときには学習した結果(モデル)が手元に残ります。Unity と python の繋ぎこみや、Machine Learningに必要な知識がある程度のレベルに隠蔽されているので、詰まることもありません。

動くペンギン

学習させた数値だけ見ていても実感はわきませんが、これは実際に魚を捕まえるのがうまくなったペンギンを見ることができます。Unity の良さでもあり、そしてその Unity の良さをきちんと体験できるものだと思いました。

どういう人にオススメ?

  • Machine Learning に興味があるけど、まだ知識がない人
  • Unity やってるけど、単純なのに飽きてきた人
  • 無料でやりたい人
  • 英語できなくても、google 翻訳でなんとかなります(自分はなった)
  • ちょっと厳しい人

時間はどれぐらい?

サイトでは約2.5時間となっていますが、ダウンロードとか、間に色々挟まったりして5時間程度かかりました。
(Unity や IDE はインストールした状態から開始しています。)

肝心の講義はこちら

注意

一番ハマったのが ML-Agents のバージョンです。更新が順次入っているので、このサイトのバージョン(0.13.x, 私は0.13.1でやった)に合わせてやったほうが良いです。そうでないとプログラムとかをいちいち最新バージョンに合わせて修正しないと動きません。

補足

これだけでは足りない(当たり前)

  • ハイパーパラメーターや学習モデルの話とかは、良くも悪くも出てこないので、そういうところは全く理解できません
  • 横展開したくても、現状のバージョンはペンギン専用らしいです

Unity Learn Premium が無料

「Unity Learn Premium」を3か月間無料化(6月20日まで) 
スクリーンショット 2020-04-07 22.14.07.png

ちょっと厳しい人

体験はできると思うけど、意味があるかは?が付くという意味で、ちょっと厳しい。

  • プログラムほとんど書けない人
    • 基本的な構文(if/for)とかが何か見ないと書けない人
  • Unityほとんど知らない人
    • Start/Update/FixedUpdate/rigidbody/GameObject を知らないレベルの人
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでPhotonVoiceを使用したときに他アプリケーションの音量が小さくなる問題

概要

PhotonVoice を使用した Unity 製アプリを起動した途端、別アプリケーションとして起動している Google Chrome 上の YouTube や Spotify 等の音量が極小になる。また、通話中の Discord に至っては音量だけではなくマイク入力も極小になるようだった。本事象は UnityEditor 上でアプリケーションを実行しても発生した。

同じ事象は PhotonVoice を使用していないと思われる LINE や Skype, Zoom の通話中でも発生しているが、Discord や Slack, Google Chrome 上の Facebook Messenger の通話中では発生していないので、何か解決方法があることが分かる。

確定的な原因は分からなかったが、対処方法は分かったので記事として残しておく。

各種バージョン

環境 バージョン
macOS macOS 10.15.4
Unity Unity 2018.2.21f1
Photon Unity Network PUN 1.91

(全体的にバージョンが古くてお恥ずかしい限りです)

対処方法

PhotonVoiceRecorder にある Microphone Type で「Unity」を使用する。
自分のプロジェクトでは「Photon」を使用していたが、これを「Unity」に変更したら解決した。

image.png

ただし、基本的には Unity マイクよりも Photon マイクのほうが何かと優秀なので、Mac で起動したときのみ「Unity」マイクを使用するようにするために下記コードを書いた。 (PhotonマイクのクライアントとUnityマイクのクライアント同士で音声通信が正常に出来ることは検証済み)

private void Start() {
  GetComponent<PhotonVoiceRecorder>().MicrophoneType = IsMacOs() 
    ? PhotonVoiceRecorder.MicAudioSourceType.Unity 
    : PhotonVoiceRecorder.MicAudioSourceType.Photon;

  // 念の為PhotonVoiceSettingも変更しておく
  PhotonVoiceSettings.Instance.MicrophoneType = IsMacOs() 
    ? PhotonVoiceSettings.MicAudioSourceType.Unity 
    : PhotonVoiceSettings.MicAudioSourceType.Photon;
}

// Macで実行されていたらtrue
private bool IsMacOs() {
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  return true;
#endif
  return false;
}

原因究明 (未解決)

下記のフォーラムで探して回ったが、とにかく同じ事で悩んでいる人が少なかった。
また、投稿があっても回答が無いパターンも多かった。

  • Unity Forum
  • Apple Developer Forums
  • Photon Engine Support Forum
  • Stack Overflow

似たような問題を抱えている人

本事象に一番近いなと思ったのは、Apple Developer Forums に投稿されていた下記の質問。
(もしかしたら全く関係無いかもしれないが)
VoiceProcessingIO lowers the volume of all othe... |Apple Developer Forums

VoIPアプリケーションでVoiceProcessingIO(kAudioUnitSubType_VoiceProcessingIO)オーディオユニットを使用してオーディオを録音および再生しています。ユニットが初期化されている場合を除き、すべてが正常に動作します。他に何かがオーディオを再生している場合、そのオーディオは非常に静かになりますが、出力はすべてフルボリュームで聞こえます。

こちらの投稿には回答が付いていなかったが、macOS のオーディオ API 周りの機能が原因である事が分かる。
(上記記事で紹介されていた kAUVoiceIOProperty_DuckNonVoiceAudio - AudioToolbox | Apple Developer Documentation のプロパティをドキュメントから参照したが、非推奨と書いてあったので対応出来なかった。)

全てのアプリケーションにおいて音声入力時に他のアプリケーションの音量が小さくなるのならここで諦めるが、上述した通り Discord や Slack の通話では音量が変わる事が無かったので、もう少し調べてみることにした。

Photon Voice のマイクタイプについて

公式ドキュメントの「Photon」マイクの説明を見ると、ネイティブのオーディオAPIとやりとりしている事が分かる。

Unityマイクは、ほぼ同じコードベースを使用して複数のプラットフォームをターゲットにすることを容易にするのに最適です。ただし、いくつかの点で、UnityのマイクAPIは制限されているか、あちこちにいくつかの問題があります。そのため、オーディオ入力デバイスと直接やり取りし、UnityのマイクAPIをバイパスする独自の方法を導入しました。これの主な理由の1つは、デバイスのハードウェアに組み込まれているエコーキャンセレーションを利用することです。 ※ Photon Voice For PUN | Photon Engine より引用

macOS の API (特にオーディオ周り)には詳しくないが、オーディオ API が本事象の原因であり、Photon マイクの実装がネイティブのオーディオ API を利用しているのならもしかして?と思ってマイクタイプを「Unity」に変更したら他アプリケーションの音量に影響を与えない事が出来た。

最後に

Unity マイクも内部的にはネイティブのオーディオ API を参照しているのでは?と思ったが、他アプリケーションの音量操作は Unity API 側で無効にされているという認識で良かったのだろうか。

結局、具体的に何のオーディオ API の何のパラメータが原因で、どのような場合に音量操作を行うのかというのは分からなかったので、もし詳しい方がいらっしゃいましたらご教示いただけますと幸いです。

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】初心者が覚えるべきDebug.Logの使い方

環境

Unity 2019.3.7f1

Debug.Logって?

Unity側で用意された標準機能 
Debug.Log()
は定型文です。呪文として覚えましょう!
開発中めちゃくちゃ使うので勝手に覚えちゃうと思います笑

どんな時に使う?

・変数の中身を知りたいとき
・何の処理が行われたかをわかるようにしたいとき(テキストを表示)
・処理が実行されたか確認したいとき

前準備 コンソールウインドウを開く

図1.png

このような画面が出ます。
ここにDebug.Logの中身が表示されます。
image.png

使ってみる

・変数の中身を知りたいとき

スクリプトを用意
 名前はTEST_scriptにしました。

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

public class TEST_script : MonoBehaviour{

    int a;//aというint型の変数を宣言

    void Start()
    {
        a = 10;//変数aの中身を10に設定
        Debug.Log(a);//コンソールウインドウに変数aの持っている数値を表示
    }
}

空のゲームオブジェクトを用意
ヒエラルキー上で右クリック→空のオブジェクト作成
image.png
空のオブジェクトが作成された!
image.png

先程作ったスクリプトを空のオブジェクトへドラッグ&ドロップ
インスペクターにスクリプトが割り当てられたことを確認
image.png

実行ボタン押す
image.png

変数aの中身が表示されました!
image.png

・何の処理が行われたかをわかるようにしたいとき

スクリプトのDebug.Log()のかっこ内を"ダブルクォーテーションで囲んで文字を入力

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定
        Debug.Log("aに10を代入");//コンソールウインドウにテキストを表示
    }
}

テキストが表示されました!
image.png

・処理が実行されたか確認したいとき

if分の中身が実行されたか見てみましょう。

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定

        if(a == 10)//aが10だったらif分の中身の処理実行
        {
            Debug.Log("if文の中身が処理された");//コンソールウインドウにテキストを表示
        }

    }
}

if分の中身が処理されたことがわかります
image.png

少し応用

"a="+a といれるとテキストと変数の中身を同時表示できます。

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定

        Debug.Log("a="+a);  

    }
}

image.png
表示された変数の内容がわかりやすくなります。

楽しいUnityライフを!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] Unity as a LibraryをSwiftから呼ぶ

基本的なところはここを見ながら進める。
https://qiita.com/tkyaji/items/7dbd56b41b6ac3e72635

SwiftでUnityクラスを作る。上の記事ならこんなかんじ。

class Unity: NSObject, UnityFrameworkListener, NativeCallsProtocol {
    static let shared = Unity()
    private let unityFramework: UnityFramework

    override init() {
        let bundlePath = Bundle.main.bundlePath
        let frameworkPath = bundlePath + "/Frameworks/UnityFramework.framework"
        let bundle = Bundle(path: frameworkPath)!
        if !bundle.isLoaded {
            bundle.load()
        }
        let frameworkClass = bundle.principalClass as! UnityFramework.Type
        let framework = frameworkClass.getInstance()!
        if framework.appController() == nil {
            var header = _mh_execute_header
            framework.setExecuteHeader(&header)
        }
        unityFramework = framework
        super.init()
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
        unityFramework.register(self)
        FrameworkLibAPI.registerAPIforNativeCalls(self)
        unityFramework.setDataBundleId("com.unity3d.framework")
        unityFramework.runEmbedded(withArgc: CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: launchOptions)
    }

    var view: UIView {
        unityFramework.appController()!.rootView!
    }

    func showHostMainWindow(_ color: String!) {

    }
}

ViewControllerを作る。

class LaunchViewController: UIViewController {}

class ViewController: UIViewController {
    private let unityView = Unity.shared.view

    override func loadView() {
        super.loadView()
        view.addSubview(unityView)
        NSLayoutConstraint.activate([
            unityView.topAnchor.constraint(equalTo: view.topAnchor),
            unityView.leftAnchor.constraint(equalTo: view.leftAnchor),
            unityView.rightAnchor.constraint(equalTo: view.rightAnchor),
            unityView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
    }
}

後述するが、LaunchViewControllerなるものを作っておく。

AppDelegate.swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    lazy var window: UIWindow? = .init(frame: UIScreen.main.bounds)

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        window?.rootViewController = LaunchViewController()
        window?.makeKeyAndVisible()
        Unity.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
        window?.rootViewController = ViewController()

        return true
    }
}

起動時にUnityクラスを初期化しておく。
runEmbeddedはwindowが無いと上手く動かないので、先ほど作ったLaunchViewControllerでwindowを作り、そのあとでメインのViewControllerに差し替える。
起動直後にUnityを出さないのであれば、適当にwindowが出来てから呼べばOK

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JKがRustでgRPCで簡易マルチプレイサーバー書いてUnityで動かしてみた

こんにちは、あんはるです!

コロナで暇なので、紹介してなかったプロジェクトを紹介したいと思います.

突然ですけど、このGIF見てみてください.
右のウィンドウと左のウィンドウはサーバー経由で座標を共有しあっています〜
これが簡易マルチプレイです!
image.png

きっかけ・目的

荒野行動を始めると、100人のユーザーがリアルタイムに走っててすごいなぁと思いました。どうやったらこんなサーバ作れるのだろうという興味がきっかけです。

とりあえず、自前で実装してみたい!となったのでやってみます。

 このプロジェクトの構成

バックエンド

  • gRPC
  • MongoDB

フロントエンド

  • Unity

です。
上のデモはローカルで完結させてます。

なぜgRPC?

Unityで、リアルタイムに処理したいという時に、MagicOnion – C#による .NET Core/Unity 用のリアルタイム通信フレームワークがよく記事に書かれています。

MagicOnionの通信は、gRPCを用いています。

また、Protocol BufferでRPCの定義をするだけで、ホスト、クライアントのコードが生成されることに無駄のなさを感じでクールだなと感じだので、使ってみたいと思いました。

なぜMongoDB?

速度が求められるので。

マルチプレイサーバー

ソースコードは、https://github.com/anharu2394/multiplay-grpc-server

Rustで書いてみた

このプロジェクトを書いた当時、一番Githubスター数が多かったgrpc-rsを使いました。

Protocol Bufferでマルチプレイサーバーの使用を定義。
UserPositionは、ユーザーのidとどこにいるかを表しています。
ConnectPositionで双方向ストリーミングで座標を同期しています。

multiplay.proto
syntax = "proto3";
package anharu;

service Multiplay {
  rpc GetUsers(GetUsersRequest) returns (stream GetUsersResponse);
  rpc SetPosition(stream SetPositionRequest) returns (SetPositionResponse);
  rpc ConnectPosition(stream ConnectPositionRequest) returns (stream ConnectPositionResponse);
}

message GetUsersRequest {
  string room_id = 1;
}

message GetUsersResponse {
  repeated UserPosition users = 1; 
}

message UserPosition {
  string id = 1;
  double x = 2;
  double y = 3;
  double z = 4;
}

message SetPositionRequest {
  string id = 1;
  double x = 2;
  double y = 3;
  double z = 4;
}

message SetPositionResponse {
  string status = 1;
  string id = 2;
  string error = 3;
}

message ConnectPositionRequest {
  string id = 1;
  double x = 2;
  double y = 3;
  double z = 4;
}

message ConnectPositionResponse {
  repeated UserPosition users = 1; 
}

service User {
  rpc Create (CreateUserRequest) returns (CreateUserResponse);
}

message CreateUserRequest {
  string name = 1;
}
message CreateUserResponse {
  string id = 1;
}

そして、protoから生成されたコードを使って、それぞれ実装していきました。

マルチプレイクライアント

ソースコードは、 https://github.com/anharu2394/multiplay-grpc-client
Unityなのでc#で書いてます。

Unityはそもそも、gRPCを使う環境を整えるのに時間がかかりました...

https://note.com/npaka/n/n050b1aba7772
これを参考にすると分かりやすいと思います!

ストリーミングして、サーバーから座標が送られてくるごとに、キャラクターの座標を更新するという感じでやりました!

サーバーの動作確認がしたいだけなので、UIや見た目などは超手抜きですが、ジャンプのアニメーションをつけたり少しゲームっぽくして見ました!

 まとめ

おそらく、本番環境では使い物にはならないかもしれませんが、ローカルの中でもgRPCの双方向ストリーミングが体感できてよかったです〜〜

RustもgRPCも頑張ります〜〜!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む