20190524のC#に関する記事は7件です。

uGUIで動的にサムネイルを生成する

やりたいこと

  • ステージ一覧で、ステージマップのサムネイルを動的に生成して張りつけたい。
    • 一覧される各要素は、動的に生成され、レイアウトグループで配置されます。
  • uGUIで、動的にSpriteを生成してImageに貼り付けます。

やったこと

  • サムネイルの生成は時間がかかるので、非同期に行います。
  • 個々のサムネイルを自律的に生成させます。
private IEnumerator MakeThumbnail () {
    this.Loading.SetActive (true); // クルクルを表示
    this.Thumbnail.gameObject.SetActive (false); // サムネを非表示
    yield return null;
    var size = Mathf.Max (this.Level.Width, this.Level.Height); // 縦横大きい方
    var dx = (size - this.Level.Width) / 2; // 中央寄せのため横のパディング
    var dy = (size - this.Level.Height) / 2; // 中央寄せのため縦のパディング
    this.Texture2D = new Texture2D (size, size); // テクスチャを生成
    for (var y = 0; y < size; y++) {
        for (var x = 0; x < size; x++) {
            var color = this.Level.Matrix [x - dx, y - dy].Color; // 色を取得 (範囲外は自動判別)
            this.Texture2D.SetPixel (x, size - 1 - y, color); // 色を描き込む
            yield return null;
        }
    }
    this.Texture2D.Apply ();
    this.Texture2D.filterMode = FilterMode.Point;
    this.Thumbnail.sprite = this.Sprite = Sprite.Create (this.Texture2D, new Rect (0, 0, size, size), new Vector2 (0.5f, 0.5f));
    this.Thumbnail.gameObject.SetActive (true); // サムネイルを表示
    this.Loading.SetActive (false); // クルクルを非表示
}

// 自分が消えるときには、作ったデータも消す
private void OnDestroy () {
    if (this.Texture2D) { Destroy (this.Texture2D); }
    if (this.Sprite) { Destroy (this.Sprite); }
}

環境

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

【Unity】他のSceneに変数などの情報を渡すカンタンな方法

まずは Scene について説明

Scene とはゲーム画面というとわかりやすいんでしょうか。よく具体例で言っているのはロールプレイングゲームですね。フィールド歩く「マップ画面」と敵に遭遇したら切り替わる「バトル画面」は、それぞれ違う画面として管理した方が良さそうじゃないですか。そういうときに Scene で「マップ Scene」や「バトル Scene」という形でそれぞれの画面ごとに作ることができます。

他の Scene に変数の情報とか渡したい

こう書かれてもピンと来ないかもしれませんので以下のような Scene で構成されているゲームがあるとします。

  • タイトル画面
  • ゲーム画面
  • クリア画面

やりたいことはゲーム画面でプレイした結果をクリア画面に渡したいんです!具体的にいうとゲーム画面でクリアしたかどうかを bool 値で判定して、その bool 値をリザルト画面に渡したい。

方法1:public で static な変数を使う

public で static な変数を使えば他のスクリプトへの変数に参照できます。どこからでも変数を呼べるし格納もできるので Scene が違っていても変数に格納できます。以下にサンプルとなるソースを記載します。GamePlaying が実際に遊ぶゲーム画面にアタッチされており、GameResult がゲーム結果画面にアタッチされているモノとしてご確認ください。

▼【保存する場合のスクリプト】▼

using UnityEngine;

public class GamePlaying
{
    public static bool isClear = false;
    void Start () {
        //スタートからクリア判定を置く
        //isClear = true;
    }
}

▼【読み込みたい場合のスクリプト】▼

using UnityEngine;

public class GameResult
{
    void Start () {
        //ゲーム結果画面でGamePlayingの変数を読み込み
        if(GamePlaying.isClear){
            Debug.Log(" isClear が true なのでクリアしてる状態です");
        }
    }
}

共通で使用したい変数である isClear は、GameResult 側に宣言してもよいです。その場合は GamePlaying 側からはGameResult.isClearで参照することができます。

public で static な変数のリスクも知っておこう

上記のような形で public で static な変数を使用すれば、ほぼどこからでも参照できます。どこからでも参照できるというのは便利ではありますが、それはそれで意図しない場所から参照される場合もあります。特に人と作業される場合は「この変数は参照できるから利用しよう!」と変数に対して意図しない値を格納されたりすることもあるのでご注意ください。
「staticおじさん」という揶揄もあったりして多用しすぎるとよくない可能性もあるにはありますが、リスクなどを把握しながら上手く使い分けて行くことが重要だと思います。とりあえずは個人でやる分には上記の方法を使ってみてもイイかなと思っています悩んで停滞するよりは進めることの方が重要だと思うので。

方法2:DontDestroyOnLoad()を使用する

通常、他のSceneに切り替わった(遷移)場合は、遷移前のSceneのオブジェクトは全て破棄されます。DontDestroyOnLoad()を使用すれば、使用したSceneについて他のSceneに切り替わった(遷移する)場合でもオブジェクトが破棄されません。オブジェクト自体は残っているのでオブジェクトを検知して変数を参照したりオブジェクトを操作することが可能です。

▼【ゲーム画面にアタッチするスクリプト】▼

using UnityEngine;
using UnityEngine.SceneManagement;

public class GamePlaying : MonoBehaviour {

    public string test = "他のSceneで読み込まれるぜ!";

    void Start () {
        DontDestroyOnLoad (this);
    }

    //クリックしたら「GameResult」に遷移
    void Update () {
        if (Input.GetMouseButtonDown (0)) {
            SceneManager.LoadScene ("GameResult"); 
        }
    }
}

▼【結果画面にアタッチするスクリプト】▼

using UnityEngine;

public class GameResult : MonoBehaviour {

    void Start () {
        //オブジェクトを名前で探す
        GameObject resultObj = GameObject.Find ("ResultObject");
        //変数「test」を参照しDebug.Logに出力
        Debug.Log (resultObj.GetComponent<GamePlaying> ().test);

        //オブジェクトの位置情報を変更
        resultObj.transform.position = new Vector3 (
            resultObj.transform.position.x,
            resultObj.transform.position.y - 5,
            resultObj.transform.position.z
        );
    }
}

▼【ゲーム画面スクリーンショット】▼
DontDestroyOnLoad()-Playing.png

▼【結果画面スクリーンショット】▼
DontDestroyOnLoad()-Result.png

結果画面でtestという変数を参照していますが public な変数です。public を付けないと他からは参照できないのですが static でなくてもオブジェクトを通して参照できます。ちなみにざっくりと static について説明しますが static は静的なモノで最初に領域を確保されるため参照対象となる変数は1つしか存在しません。この説明だけだとわかりにくいですが、今回の場合を例にするとちょっとわかりやすいかも。
今回の場合はオブジェクトResultObjectの変数testを参照していますが、もし他のオブジェクトなら他のオブジェクトを探して、探し出したオブジェクトの変数testを参照できます。つまりオブジェクトの数だけ変数testが存在することになります。

▼【試しにstaticの変数を追加してみるが・・・】▼

using UnityEngine;
using UnityEngine.SceneManagement;

public class GamePlaying : MonoBehaviour {

    public string test1 = "他のSceneで読み込まれるぜ!";
    static public string test2 = "staticのテストだぜ";

    void Start () {
        DontDestroyOnLoad (this);
    }

    void Update () {
        if (Input.GetMouseButtonDown (0)) {
            SceneManager.LoadScene ("GameResult"); 
        }
    }
}

▼【GameObjectから参照しても参照できない】▼
TESTAAAA.png

方法3:永続的に保存する「PlayerPrefs」

プログラムおよびアプリ自体に値を保存してしまえば Scene を跨いでも受け取れるようになります。値を渡す目的だけで使うのは微妙かもしれません。ゲーム画面のスコアなどの記録したいモノであれば使ってもイイかなと。

以下にサンプルのソースを記載します。以下のことを気をつけてご利用いただければ幸いです。

  • 保存するときは必ずPlayerPrefs.Save()を忘れない
  • 保存や読み込みのキーは大文字小文字を区別するので注意

▼【保存する場合のスクリプト】▼

using UnityEngine;

public class GamePlaying
{
    void Start () {
        //「SCORE」というキーで、Int値の「20」を保存
        PlayerPrefs.SetInt("SCORE", 20);
        PlayerPrefs.Save();
    }
}

▼【読み込みたい場合のスクリプト】▼

using UnityEngine;

public class GameResult
{
    void Start () {
        //「SCORE」というキーで保存されているInt値を読み込み
        int resultScore = PlayerPrefs.GetInt("SCORE");
        Debug.Log("保存されている点数:" + resultScore )
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Convert.ToDouble(floatValue)での誤差

浮動小数点数で誤差が出るという知識自体は持っているのに、実際出るまで忘れてることが多いですね。

Convertは意識しないで使うとたまに躓きます。

Console.WriteLine((double)1.234f);
Console.WriteLine(Convert.ToDouble(1.234f));
Console.WriteLine((double)Convert.ToDecimal(1.234f));
//出力結果
//1.23399996757507
//1.23399996757507
//1.234

こんなことにいまだに躓くので恥さらしの記事。

小数(浮動小数点数型)の計算が思った結果にならない理由と解決法
Decimal型はいつ使うか?

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

歴史から知る「なぜ絵文字対応は面倒なのか」

はじめに

企画さんから、
「名前入力の際に絵文字を * でエスケープしてほしい(例:ハッピー:tada:→ハッピー*)」
という要望がきたので、それに対応するまでの流れをまとめたいと思います。(対応したとはとは言ってない)

Unicodeに絵文字が導入されるまで

こういった一部の文字をエスケープしたい場合、for文でcharをチェックするなり正規表現で弾くなりすると思いますが、絵文字の場合はそう上手くはいきません。

これには Unicode が絵文字を表示する仕組みが関係します。
絵文字が導入されるまでを時系列で振り返りながら、仕組みを知っていきましょう。

1990年代前半

制作当初、Unicode では1文字を2バイト固定で表現しようと計画されていました。
これによって、収録できる文字が最大65536文字になりますが、

  • Shift_JIS などの経験から可変長文字コードが面倒なことがわかっていたこと
  • 当時、中国・日本・韓国などの文字をまとめても20000個程度だったこと

などが理由で、問題ないだろうと判断されていました。
実際、Unicode 1.0 が策定された際は65536個以内に収まっていました。

これ以降、2バイト固定長、のちに UTF-16 と呼ばれるルールはC#やJavaなどのプログラミング言語に採用されるようになります。(char を2バイトとして扱う)

1990年代後半

当初、2バイト(65536文字)もあれば十分だろうと判断されていた Unicode ですが、技術者だけでなく言語学者も参画してもらったところ、65536文字では足りないことが明らかになります。

そこで、2文字1組(4バイト)として扱うサロゲートペアというルールが定められました。
これによって、扱える文字は増えたわけですが、当初定めていた2バイト固定長が崩れる形となり、UTF-16 は1文字2バイトまたは4バイトの可変長となってしまいます。

この結果、発生したのがUnicodeを使用したプロジェクトでのバグです。
当初、2バイトで1文字を扱っていたことで、サロゲートペアなどの4バイト文字がきた時に対処できなくなってしまいました。
しかし、サロゲートペアで表現する必要がある文字は一般人が知らないようなマイナー文字がほとんどだったため、特に対策されないプロジェクトが存在する形となりました。

2010年代前半

この状況に一石を投じたのが絵文字でした。

もともと日本の携帯電話などで浸透していた絵文字は、その扱いやすさから Emoji として世界でも扱われるようになります。(大統領からも Emoji を生み出したことに感謝の意を示されたらしいです)

絵文字は4バイトで表現されますが、上記の通り世界各国で使用されているため、技術者はサロゲートペアに対応せざるを得なくなりました。
これによって、今まで対応されていなかったマイナー文字も対応される形となり、結果的にバグ対策がなされる形となっていきます。

なぜ絵文字対応は面倒なのか

今回の記事のタイトルでもある、「なぜ絵文字対応は面倒なのか」
これは、

絵文字は4バイトで表現されますが、上記の通り世界各国で使用されているため、技術者はサロゲートペアに対応せざるを得なくなりました。

が理由となっていることがわかりました。
プログラミング言語的に置き換えると、charが2バイトで扱われている場合、絵文字などの4バイトは正しく1文字と判定されなくなるなどの問題が発生します。

なので、絵文字対応をするためには、この4バイト文字を正しく1文字扱いできればいいことがわかります。
幸い、IsSurrogateなどのサロゲートペアを検知する関数が各言語に存在するかと思われるので、そちらで判定すれば、上記の問題は解決します。

これで絵文字対応は完了...ということにはなりませんでした。
これには絵文字が導入されてからの歴史が関係します。

絵文字が導入されてから

もともとは日本の携帯電話だけにあったものが、iPhone の登場を筆頭に絵文字は世界的に人気となりました。
人気のコンテンツはより人の目を集め、それによって起こる問題も存在します。
主な例としては、人種差別やLGBT問題などが挙げられるでしょう。

参考記事:「絵文字に平等をサポートしてください」人種差別の指摘にゆれるUnicode

ただ、こういった「複数の肌色を用意してほしい」「男と男の絵文字も用意してほしい」といった要望は、日本の携帯電話での使用をベースに作られた絵文字には含まれていませんでした。

この解決策として、これまでの経緯を振り返ると、新たに4バイト文字として肌色別の絵文字を追加するという方法が考えられますが、これでは絵文字を検索する際に面倒になってしまいます。

そこで取られたのが、複数の絵文字を組み合わせて一つの文字を作るという方法でした。

複数の絵文字からなる絵文字

これまでの話では、たとえ1文字が2バイトであろうと4バイトであろうと1コードポイントで表現されていました。(異体字セレクタだと2コードポイントになりますが...)

ここでいうコードポイントとは、文字の集合の中でどこに配置されているかの位置になります。
これは、Unicode だと、U+○○○ のような形で表現され、単純計算で U+0000 ~ U+10FFFF が存在します。
例えば、「?」だと U+1F389 に該当します。

さて、先ほど挙げた「複数の絵文字からなる絵文字」ですが、これは複数のコードポイントから1文字として扱われます。

具体例を挙げます。
6AA54B84-84B9-403A-9C1F-6E46309D4F35.png

肌色違いなどの絵文字を表現する場合は、人の顔を表現する絵文字に色を表現する絵文字を追加することで表現できます。
また、この画像では2文字の絵文字を結合していますが、3文字4文字を結合して1文字を表現することもあります。(「?‍?‍?‍?」4人家族など)

この現象は簡単に確認ができます。実際に肌色違いを試してみましょう。

?+ ?=??

こちらは上記の画像の上の肌色違い生成式を文字に起こしたものです。
「?」をコピーして検索バーなどの適当の場所に貼り付けた後、「?」をコピーして貼り付けた後ろに「 ?」を貼り付けてください。
肌色違いが生成されたでしょうか?

このように、ある決まった文字が連続で続いた場合、1文字として扱う仕組みがあります。
それが書記素クラスタです。

なお、今回は絵文字を例に挙げていますが、書記素クラスタは「が」などにも利用されています。「か」に濁点の文字が結合されているのです。(1コードポイントの「が」も存在します)

# Ruby
irb(main):001:0> "が".length
=> 2

# C#
> WriteLine("が".Length);
2

Rubyはコードポイント、C#は2バイト単位でカウントするので、「が」は2バイト文字が2つ並んでいることがわかります。(U+304B U+3099

つまり、真に絵文字に対応するということは、こういった1コードポイントを超えた文字にも対応することになります。
これが面倒な理由になります。

各言語での挙動

1コードポイントを超えた文字に対応するためには、前述の通り書記素クラスタを用いる必要があります。
これが使われていなかったり、バージョン違いだったりすると正しく対応することができません。

言語別に挙動を見ていきましょう。

Ruby

まずは Ruby 2.3.8 を試してみます。

補足
Ruby のstring.lengthではコードポイントを数えてしまいます(例:肌色違いならU+1F471 U+1F3FBのため2文字扱い)。
なので、結合してできる肌色違いなどの文字を1文字扱いする正規表現\Xを使用しています。

irb(main):001:0> RUBY_VERSION
=> "2.3.8"
irb(main):002:0> "が".scan(/\X/).count
=> 1
irb(main):003:0> "?‍?‍?‍?".scan(/\X/).count
=> 7

どうやら正しく文字数をカウントすることができなかったようです。

これは Ruby 2.3.8 での正規表現の\Xがこれらの絵文字に対応していないことが原因となります。
\Xが絵文字に対応するのは Ruby 2.4.0 以降になります。

参考:https://docs.ruby-lang.org/ja/latest/doc/news=2f2_4_0.html

そのため、このバージョンで書記素クラスタを用いるためにはActiveSupportを使う必要があります。

irb(main):001:0> require 'active_support/multibyte/unicode'
=> true
irb(main):002:0> ActiveSupport::Multibyte::Unicode.unpack_graphemes("が").count
=> 1
irb(main):002:0> ActiveSupport::Multibyte::Unicode.unpack_graphemes("?‍?‍?‍?").count
=> 4

今度は、書記素クラスタを用いた文字数カウントになりますが、一部変更はかかっているものの、やはりおかしなカウントがされています。
これは、今回使用した ActiveSupport 5.0 が Unicode 8.0.0 以下のバージョンに基づいて文字数カウントを行なうためです。

正しくカウントするためには、Unicode 9.0.0 以降に対応した Ruby か ActiveSupport が必要になります。
なお、Unicode 9.0.0 に対応したのも Ruby 2.4.0 以降になります。

次は Ruby 2.6.2 での挙動を見ていきましょう。

irb(main):001:0> RUBY_VERSION
=> "2.6.2"
irb(main):002:0> "が".scan(/\X/).count
=> 1
irb(main):002:0> "?‍?‍?‍?".scan(/\X/).count
=> 1

Ruby 2.6.2 では正規表現\Xが絵文字に対応しており、Unicode 9.0.0 にも対応しているので、正しく絵文字をカウントできているようです。

C#

次は C# の挙動を見ていきましょう。

補足
C# のstring.Lengthでは char の数を数えています。(例:肌色違いならU+1F471 U+1F3FBで、どちらも4バイト文字なので、2+2で4文字扱い)
なので、4バイト文字や結合してできる肌色違いなどの文字を1文字扱いするStringInfoを使用します。

> System.Console.WriteLine(new System.Globalization.StringInfo("が").LengthInTextElements);
1
> System.Console.WriteLine(new System.Globalization.StringInfo("?‍?‍?‍?").LengthInTextElements);
7

結果が Ruby 2.3.8 で正規表現\Xを使用した時と同じ挙動ですね...
StringInfoのリファレンスを見てみましょう。

リファレンスを見た限り、特に絵文字に関する記述はありません。
ただ、

.NET Framework 4.6.2 では、文字の分類に基づくUnicode 標準、バージョン 8.0.0します。 .NET Framework 4.6.1 から .NET Framework 4 向けに基づくはUnicode 標準、バージョン 6.3.0します。 .NET Core でに基づくはUnicode 標準、バージョン 8.0.0します。

ということなので、どちらにせよStringInfoでも正しく絵文字を取り扱うことが難しそうです。

では、C#ではどうやって絵文字を扱うのか。
厳密にやるためには、外部のライブラリを頼る方法が一番かと思います。

++C++; // 未確認飛行 C さんのサイトで公開されているGraphemeSplitterを使うなどがいいかもしれません。

参考:https://ufcpp.net/blog/2017/10/graphemesplitter/

まとめ

絵文字の歴史と対応方法を紹介しました。
こういった絵文字の記事、閲覧環境によっては正しく表示されないことがあるので辛いところです...

おまけ

冒頭で企画さんから依頼されたもので、

「名前入力の際に絵文字を * でエスケープしてほしい(例:ハッピー:tada:→ハッピー*)」

こちらは最終的に、絵文字は入力を受け付けないという仕様に変更されたため、System.Globalization.UnicodeCategoryにて絵文字関連の文字は弾くという対応になりました。

今回はUnityでの絵文字対応で、最終的にはこういったコードに落ち着きました。

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

public class NewBehaviourScript : MonoBehaviour
{
    [SerializeField] InputField _inputField;

    private void Start()
    {
        _inputField.onValidateInput += ValidateInput;
    }

    private char ValidateInput(string text, int charIndex, char addedChar)
    {
        var category = char.GetUnicodeCategory(addedChar);
        switch (category)
        {
            case System.Globalization.UnicodeCategory.Surrogate:
            /*
            case System.Globalization.UnicodeCategory.Control:
            case System.Globalization.UnicodeCategory.OtherNotAssigned:
            など、その他必要なものがあれば追加
            */
                return '\0';
        }

        return addedChar;
    }
}

参考文献

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

配列とループ処理について質問

質問です。

要素数が20の1次元配列に整数100~119を順に格納するには
どのようなコードを書けばよいでしょうか?

ループ処理は必ず使いたいです。

ちなみに、以下のようなコードを書きましたが、そこから先が
でてこず困っています。

int num = new int[20];

for(int i=100; i<120; i++)
{
  num[]=i;
}
Console.WriteLine(num[]);

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

AtCoder AGC021 A - Digit Sum 2(300点)

問題概要

問題のリンク

$N$ 以下の正の整数の $10$ 進法での各桁の和の最大値を求めてください。

制約条件

  • $1≤N≤10^{16}$
  • $N$ は整数である

考えたこと

やることは一見とてもシンプル!$1$から$N$までの整数を、それぞれ各桁の和をとっていき最大値を求めたい。
だが制約をみたらわかる通り、全探索はとても間に合わない。

求めたいのは最大値なのでできるだけ9が多いほうがいいのは自明である。よって$(N-1)*9+N桁目の値f$が答えとなる。この時、$N$の$1$から$N-1$桁目が全て9である場合、$f$は$N$桁目の値であるが、そうでない場合、$N$桁目の値 - $1$が$f$となる。(そうしないと$N$より大きい値の各桁の和をとることになるので。)

解答

a.cs
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args) {
        long n = long.Parse(Console.ReadLine());
        long l = digitLength(n);
        long f = digitFirst(n);
        Console.WriteLine((l-1)*9 + f);
    }
    static long digitLength(long x) {
        long length = 0;
        while(x>0) {
            length++;
            x /= 10;
        }
        return length;
    }
    static long digitFirst(long x) {
        long first = 0;
        List<long> digit = new List<long>();
        while(x>0) {
            first = x%10;
            digit.Add(x%10);
            x/=10;
        }
        for(int i = 0; i < digit.Count()-1; i ++) {
            if(digit[i] != 9) {
                first -= 1L;
                break;
            }
        }
        return first;
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity2018.4.0f1でシリアル通信できない問題

はじめに

ArduinoをUnityとつなげていろいろしていて,LTS版が出たことを機にUnity2018に環境を移行させようとしたところエラーが発生したのでメモっときます.

環境

  • OS:Windows10
  • Unity2018.4.0f1
  • Arduino Uno

なお,UnityとArduinoの接続に関してはこちら「UnityとArduinoをシリアル通信」にお世話になっております.

エラー内容

いつものようにシリアル通信を行うためにAPI Compatibility Levelを.NET 2.0 Subnetから.NET2.0へ変更
(やり方は,こちらを参考にお願いします.)
(Unity2018.4.0f1ではAPI Compatibility LevelがOptimizationではなくConfigurationにある点に注意)

そして,「UnityとArduinoをシリアル通信」からお借りした「SerialHandler.cs」をAdd Componentしたところ...

Consoleに以下のような表示が

Assets\SerialHandler.cs(3,17): error CS0234: The type or namespace name 'Ports' does not exist in the namespace 'System.IO' (are you missing an assembly reference?)
Assets\SerialHandler.cs(20,13): error CS0246: The type or namespace name 'SerialPort' could not be found (are you missing a using directive or an assembly reference?)

erro1.PNG

また,「SerialHandler.cs」をVS2017で開くと,erro2.PNG

思いっきりエラーが出てます.

要約すると「System.IOにPertsってやつなんていないよ!」ってことなので,用意してあげたいと思います.

解決方法

調べたら,Microsoftの公式でUnityに.NETのdllファイルを新たに入れてあげる方法がありました.

「Unity で.NET 4.x を使用する」

上記リンクの「.NET との互換性を利用する」ってところを参考に行います.

  1. このリンクから「system.io.ports.4.6.0-preview5.19224.8」をダウンロード(2019/05/24現在のファイル名です.)して,拡張子を「.nupkg」から「.zip」へ変更し,解凍
  2. 解凍したフォルダ内の lib/netstandard2.0 に移動し、System.IO.Ports.dll をコピー
  3. Unity プロジェクトの Assets フォルダに、Plugins という名前の新しいフォルダを作成し,System.IO.Ports.dll ファイルをペースト
  4. さっきと同じAssetsフォルダに link.xml という以下のファイルを作成
link.xml
<linker>
  <assembly fullname="System.Core">
    <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
  </assembly>
</linker>

以上です.

結果

もう一回「SerialHandler.cs」をVS2017で開くと
safe1.PNG
エラー表示が消えました~

UnityのConsoleにも表示が消えていると思います!
いやー,無事解決できてよかった!

(追記)
実は, Edit > Project Setting > Player > Inspector > Other Settings > Configuration にある Scripting Runtime Version を .NET 3.5 Equivalent に変更してもエラーは消えます.
.NET 4 にこだわる必要がない方はそっちでもいいかもしれませんね (-_-;)

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