20190305のC#に関する記事は9件です。

Excelからコピペしてcsvにする簡易ツール

要点

Excelのセルをコピーしたテキストはtsvなので、これをReplaceで置換してcsvに保存するチャレンジ。

経緯

作業効率化のために、Excelからcsvを吐き出したいものの、
昨今はセキュリティの都合上現場は外のネットワークに繋がらず、VBAのソースもコピペできないことも多いです。
さて困ったけど、どうやってcsvファイルを作ろうかと考えたとき、Excelからセルをコピーしたときの特徴を利用すればよいと分かりました。

Excelからコピーしたセルは、テキスト上ではtsvで持っているので、区切り文字を\tから,に置換すればよいのです。

完成品の外観

適当にテキストボックスを配置し
(※AcceptsEnter, AcceptsTabをオン(true)にしてください)
CSV_00.PNG

セルをコピーして
CSV_01.PNG

ペッと貼り付けるとファイルパスが出るので開くと
CSV_02.PNG

一瞬でcsvファイルの出来上がり!
CSV_03.PNG

通常版とワンライナー版

通常版

CopyTsvToCsv_Normal.cs
string[] sepArr = new string[] { "\r\n" }; // Split用
string toCsv = content.Replace("\t", ","); // tsv→csvへ
string[] lines = toCsv.Split(sepArr, StringSplitOptions.RemoveEmptyEntries); // 行を分割
File.WriteAllLines(fi.FullName, lines); // 上の行を削除してFile.WriteAllText(fi.FullName, toCsv)でもOK

ワンライナー

CopyTsvToCsv_One-Liner.cs
File.WriteAllLines(fi.FullName, content.Replace("\t", ",").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));

応用プラン

  • ファイルパス、ディレクトリパスから変換できるようにしてもOK
    • 後日書きます

ソース

以下、上記のまとめです。

CopyTsvToCsv.cs
        private void TxbInputTsv_TextChanged(object sender, TextChangedEventArgs e)
        {
            DateTime dtNow = DateTime.Now;
            string fileName = string.Format("out_{0}.csv", dtNow.ToString("yyyyMMddHHmmss"));
            FileInfo fi = new FileInfo(Path.Combine(di.FullName, fileName));

            if (fi.Exists) return;

            OutPutCsv(fi, ((TextBox)sender).Text);
        }

        private void OutPutCsv(FileInfo fi, string content)
        {

            if (string.IsNullOrEmpty(content.Trim())) return;

            try
            {
                // ワンライナー版
                // File.WriteAllLines(fi.FullName, content.Replace("\t", ",").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));

                string[] sepArr = new string[] { "\r\n" };
                string toCsv = content.Replace("\t", ",");
                string[] lines = toCsv.Split(sepArr, StringSplitOptions.RemoveEmptyEntries);
                File.WriteAllLines(fi.FullName, lines);

                TxbInputTsv.Text = string.Format("Save: {0}", fi.FullName);
                Thread.Sleep(5000);
                TxbInputTsv.Text = "";
            }
            catch(Exception ex)
            {
                TxbInputTsv.Text = ex.ToString();
            }
        }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(個人的に)よく使うLinq拡張

概要

よく使うLinq拡張をまとめました

https://github.com/kuroshio-ice/Linq.Expansion

コード

Index付きforeach

var hoge = new List<int>() { 1, 3, 5 };
foreach (var (index, value) in hoge.WithIndex())
{
    Console.WriteLine($"index: {index}, value: {value}");
}
結果
index: 0, value: 1
index: 1, value: 3
index: 2, value: 5

項目の文字列結合

var hoge = new List<int>() { 1, 3, 5 };
var str1 = hoge.JoinString(":");
Console.WriteLine($"str1: {str1}")
var str2 = hoge.JoinComma();
Console.WriteLine($"str2: {str2}")
結果
str1: 1:3:5
str2: 1,3,5

要素分割foreach

var hoge = new List<int>() { 1, 3, 5 };
foreach (var h in hoge.Chunk(2))
{
    Console.WriteLine($"hoge: {h.JoinComma()}");
}
結果
hoge: 1,3
hoge: 5

要素のランダム取得

var hoge = new List<int>() { 1, 3, 5 };
var rand = new Random();
var h = hoge.Sample(rand);
Console.WriteLine($"h: {h}");
結果例
h: 5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】スワイプ、フリックで分岐するSafari風スクロール【C#】

【Unity】スワイプ、フリックで分岐するSafari風スクロール【C#】

はじめに

スワイプした分スクロールできて、かつフリックすると速度をもってスクロールできる、iOS標準ブラウザのSafari風のUXのスクロール方法を実装したい!

ついでに2本指での拡大と縮小も実装しました。(なぜ?)
応用時はクランプなど用いてスクロール範囲を制御してください。

荒い実装ではありますが、そこそこ良い動きになったので備忘録かつ共有。

開発環境

OS: MacOS Mojave
開発環境: Unity 2018.2.14f1 personal
開発言語: C#

ソースコードとその説明

SwipeManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SwipeManager : MonoBehaviour {
    //フリック時のスピード
    private float x_speed = 0;
    private float y_speed = 0;

    //カメラ拡大縮小時のスピード(実装環境によって要調整)
    private float cameraSpeed = 0.4f;

    //初期位置
    private Vector2 startPos;

    //最初のタップからの経過時間
    private float duration = 0;

    //オブジェクトの移動比率を操作する変数(実装環境によって要調整)
    private float moveRatio = 0.5f;

    //スワイプするオブジェクト(この場合スクロールビューのコンテンツ)の外部参照
    public GameObject obj;
    //拡大縮小用カメラの外部参照
    public Camera cam;

    void Update()
    {
        //経過時間の計算
        duration += Time.deltaTime; 

        //一本指での操作(スワイプ、フリック)
        if(Input.touchCount == 1){
            //タップ情報の取得
            Touch touch = Input.GetTouch(0);

            //タップ状態の分岐
            switch(touch.phase){
                //タップ開始
                case TouchPhase.Began:
                    //タッチ開始座標、時間取得
                    this.startPos = Input.mousePosition;
                    duration = 0;
                    break;

                //タップ中、指が動いている
                case TouchPhase.Moved:

                    //オブジェクト移動(スワイプ)
                    Vector3 nowPosi = obj.transform.localPosition;
                    nowPosi.x = nowPosi.x - touch.deltaPosition.x*moveRatio;
                    nowPosi.y = nowPosi.y - touch.deltaPosition.y*moveRatio;
                    obj.transform.localPosition = nowPosi;

                    break;

                //タップ終了
                case TouchPhase.Ended:

                    //タップ終了位置取得
                    Vector2 endPos = Input.mousePosition;

                    //触れていた秒数でフリックとスワイプ分岐
                    if(duration <= 0.5){
                        float x_flickLength = endPos.x - this.startPos.x;
                        float y_flickLength = endPos.y - this.startPos.y;

                        // フリックの長さを速度に変換する
                        this.x_speed = x_flickLength / 500.0f;
                        this.y_speed = y_flickLength / 500.0f;
                    }else{

                        //フリック判定じゃない場合はcameraのTranslate速度を0にする
                        this.x_speed = 0;
                        this.y_speed = 0;
                    }
                    break;
            }
        }

        //オブジェクト移動(フリック)
        obj.transform.Translate(this.x_speed, this.y_speed, 0);

        //毎フレーム減速させる
        this.x_speed *= 0.8f;
        this.y_speed *= 0.8f;

        //2本指での操作(ピンチイン、アウト)
        if (Input.touchCount == 2){

            // 両方のタップ情報を取得
            Touch touchZero = Input.GetTouch(0);
            Touch touchOne = Input.GetTouch(1);

            // 前フレームでのタップ位置
            Vector2 touchZeroPrePos = touchZero.position - touchZero.deltaPosition;
            Vector2 touchOnePrePos = touchOne.position - touchOne.deltaPosition;

            // 各フレームのタッチ間の距離
            float preTouchDeltaMag = (touchZeroPrePos - touchOnePrePos).magnitude;
            float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

            //各フレーム間の距離の差
            float deltaMagnitudeDif = preTouchDeltaMag - touchDeltaMag;
            //タッチ間の距離の変化からカメラの平行投影サイズを変更
            cam.orthographicSize += deltaMagnitudeDif * cameraSpeed;

            // 平行投影サイズは0以上になるようにする(クランプの範囲は要調整)
            cam.orthographicSize = Mathf.Clamp(cam.orthographicSize, 0f , 2.0f);
        }        
    }
}

終わりに

TouchScriptなどの便利なアセットを使用するとおそらく早かったのですが、スクリプトで実装してもそこまで時間がかからないのと、自分でスクリプトを書いた方が拡張性に富むと思ったのでこのような実装をしました。どなたかの助けになれば幸いです。

参考文献

「フリックとスワイプの違い」
https://enjoy.sso.biglobe.ne.jp/archives/swipe_flick/
「Unity C#で時間の取得」
http://webbeginner.hatenablog.com/entry/2015/09/04/053623
「ピンチによる拡大」
https://unity3d.com/jp/learn/tutorials/topics/mobile-touch/pinch-zoom
「【Unity2D】スワイプでオブジェクトを上下左右自由自在に動かす方法」
https://miyagame.net/swipe/

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

C#でむりやりOpenCVを使った話。

C#でOpenCVを頑張って使います。
結論から言うと、PythonでOpenCVを動かし、その結果をTCP通信を介してC#に送るというかなりクソ面白い設計になってしまったので参考になるかはわかりません。

前書き

こんにちは。
この記事は高専カンファレンス×学生LT in 東京で話した内容に少し加えた内容です。
初めてのQiita記事&初めてのMarkdownなので間違い等ありましたらご連絡ください。

C#でOpenCVが使えないのだが...

 長々と話してもしょうがないのでさっさと本題に移りましょう。
 私の場合、NuGetパッケージからOpenCVのライブラリをダウンロードしてきて使用するという方法をとったとき、謎のエラーが連発しNuGetからOpenCVを使う気が失せてしまったので仕方なく別の方法をとる必要がありました。
 そこでできるやつ(Python)に任せてC#はその結果だけを受け取るという方法を取り、そして実際に試したことを書いていきます。

Pythonを使ってOpenCVを使おう

1.IronPythonを使う

 IronPythonとは何か。

IronPythonとは、.NET FrameworkおよびMono上で動作するPythonの実装である。(引用:Wikipedia)

 らしいです(適当)。もっとかみ砕くとC#とかで簡単に動かせることのできるPythonだよ。ってことです。
 しかしこのIronPythonでOpenCVを動かそうとしたときOpenCVのライブラリがうまく読み込ませませんでした。詳しい原因は不明ですが、おそらくPythonとIronPythonが本質的に別のものだからだと思います(誰か詳しい人教えてください)。

2.Pythonファイルの外部ファイルとしてC#から起動する

Proceess.Start(@"FileName.py");

 こうするだけでファイルの起動はでき、返り値も簡単に取得できます(詳しくは別の記事を参照してください)。
 が、これにも問題があります。それは遅延の問題です。OpenCVをPythonで使用するときの初期化処理には1秒ほど時間がかかり、いちいち起動し直していては実用性がありません。

3.TCP通信を使用する

 結論としてこの方法をとりました。なんでこんな仕様にしたんだというお叱りあると思いますが設計したのが朝の三時なので仕方ないですね()。
 
 さて、実装ですがC#側でもPython側でも大したことはしていませんので参考にしたリンクだけ貼っておきます。TCPクライアント・サーバープログラムを作成する
 少しだけ付け足すと、クライアントからはデータを受け取る必要がないので送信する部分は全部カットでき、何回もデータを受け取る必要があるのですべてをwhile(true)でくくってください。
 一応使用したコードを這っておきます(変数の宣言やusingディレクディブについては書いていないので適当に補完しながら見てください)

while (true) {
    listener.Start(); //開始

    TcpClient client = null;
    try { client = await listener.AcceptTcpClientAsync(); } //受け取り
    catch (Exception) { return; }


    if (client == null)
        return;
    NetworkStream ns = client.GetStream(); //クライアントからストリーム情報を取得
    ns.ReadTimeout = 10000;
    ns.WriteTimeout = 10000;

    MemoryStream ms = new MemoryStream();

    byte[] resBytes = new byte[256];
    int resSize = 0;
    do {
        //データの一部を受信する
        resSize = ns.Read(resBytes, 0, resBytes.Length);
        //Readが0を返した時はクライアントが切断したと判断
        if (resSize == 0) break;
        //受信したデータを蓄積する
        ms.Write(resBytes, 0, resSize);
        //まだ読み取れるデータがあるか、データの最後が\nでない時は受信を続ける
    } while (ns.DataAvailable || resBytes[resSize - 1] != '\n');
    //受信したデータを文字列に変換
    string resMsg = Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
    ms.Close();
    //末尾の\nを削除
    resMsg = resMsg.TrimEnd('\n');
    //Console.WriteLine(resMsg);
    CheckMessage(resMsg); //Pythonから送られてくる座標データを解析して適切に処理するすごーい関数。
}

 次にPython部分の実装です。といってもsocketの機能が強いのであまりコードは書いていません。

def Send(msg):
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    host = "127.0.0.1"
    port = 51018
    client.connect((host,port))
    client.send(str(msg).encode())

Send("this is Message") 

 これだけです。そして、実際に動かし遅延を調べた結果がこちら。

2018-10-14.png

 左側がC#、右側がPythonになっていて、数字は時間を表しています。御覧の通りそれぞれで時間の差があまりないことがわかると思います。

 そして、OpenCVのマーカー検出ライブラリArUcoを使用して得た情報をformに送って表示した結果がこちら

Marker_Demo.gif

 赤いのがカメラからの情報を座標変換してもう一度表示したものです。あまり誤差がないのがわかると思います。

まとめ

 本当はC#だけでOpenCVを使えるまで頑張ったほうがいいのですが、Pythonの練習とネットワークの勉強も兼ねてTCP通信を使用してみました。
 
 余談ですが、PythonからC#に送る情報は文字列なので、座標の情報や、idを送る際にすこし工夫が必要だと思います。私の場合は特定の文字列で区切り、正規表現を活用して情報を取り出しました。

 以上です。ありがとうございました。

参考

 IronPython https://ja.wikipedia.org/wiki/IronPython
 サーバのコード https://dobon.net/vb/dotnet/internet/tcpclientserver.html

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

世界にひとつの、宝探しゲームをつくろう!(Unity入門)

これからUnityをつかって、ゲームを作っていきます♪
まずはUnityってナニ?というおはなしからスタートです!

Unityとは

カンタンに言うと、ゲームを作るキットです。

スマホ版のどうぶつの森や、スーパーマリオラン、白猫プロジェクトもUnityで作られています。
しかし、Unityはゲーム以外のものも作ることができます。
最近では、手術のシミュレーションにも使われたりしているみたいですよ。

そんなUnityを使って、今回は宝探しゲームを作っていきます!
下のQRコードまたはURLから、今回作るゲームのサンプル動画を見ることができるよ。

Unityにさわってみよう

まずはUnityにさわってみるところから、はじめていきましょう!

画面の見かた

どこになにがあるのかをカンタンにせつめいするよ。

Scene(シーン)

Scene.png
ゲームに出てくる物体(オブジェクト)は全部ここにあるよ。
ここでオブジェクトの場所を自由に変えることができるよ。

Game(ゲーム)

Game.png
いわゆる「プレイ画面」のこと。
ゲームをプレイする人は、この画面を見てプレイするよ。

Hierarchy(ヒエラルキー)

Hierarchy.png
Sceneにあるモノ(オブジェクト)の一覧だよ。
いまは、カメラ(MainCamera)とライト(Directional Light)があるよ。

Project(プロジェクト)

Project.png
このゲームで使える素材が全部入っているところだよ。

Inspector(インスペクター)

Inspector.png
オブジェクトなどをクリックすると、そのオブジェクトの情報(じょうほう)が出てくるよ。

カメラの情報をチェック!

ためしにカメラ(MainCamera)の情報を見てみよう!
まず、Hierarchyの「MainCamera(メインカメラ)」をクリックしてみよう。
Hierarchy_maincamera.png

InspectorにMainCameraの情報が出てきたかな?
Inspector_maincamera.png
オブジェクトの大きさや場所などを、きっちり変えたいときはここで数字を変えるとうまくいくよ。

Console(コンソール)

Console.png

エラーや、メッセージが出てくるところだよ。
赤いビックリマークが出てきていないときは、気にしなくて大丈夫だよ。

Cube(キューブ)であそぼう

下の画像(がぞう)とおなじ画面になっているかな?
ちがっていたら、まわりのお兄さんお姉さんに聞いてみよう♪
スクリーンショット 2019-02-13 13.36.38.png

Cubeを出そう

ひとつのキューブを出すよ。
cube_create.png

Cubeの作りかた

①「Create」をクリック
②「3D Object」をクリック
③「Cube」をクリック
(「Create」から、色んなものを作ることができるよ!)

CubeがSceneにあらわれたかな?
cube_scene.png

いろんな場所、むきから見てみよう

いま出したCubeをいろんな場所、むきから見てみよう!

①いろんな場所から見る

まずはいろんな場所から見てみよう。
ハンドツール✋をえらんでね。
camera_move.png

Sceneの上でクリックしながらマウスを動かしてみよう!
camera_movenow.png
Cubeをいろんな場所から見ることができるようになったかな?

②いろんなむきから見る

Sceneの上で 「右クリック」 しながらマウスを動かしてみよう!
いろんなむきから見ることができたかな?
kakudo.png

Cubeを動かそう

次に、さっき作ったCubeを動かすよ。
移動ツールをクリックしてね。
yajirusi_sentaku.png

動かしたいモノ(Cube)をクリックしよう!
やじるしが出てきたかな?
yajirusi.png

まずは上に動かしてみよう!
上に向いている黄緑色のやじるしを、クリックしながらマウスを上に動かそう。
yajirusi_y.png
Cubeが上に動いたかな?
動かなかったら、まわりのお兄さん・お姉さんに聞いてみよう!

「Game」が、プレイ画面だったね。
あれ?GameにCubeがいないね。
look_game.png

<ミッション>
Gameから見てCubeが見やすい場所になるように、
3つのやじるし(青・赤・黄緑)を使ってCubeを動かしてみよう!
cube_game.png

分からないことがあったら、まわりのお兄さん・お姉さんに聞いてね。

ミッションクリアしたら、ゲームを保存(ほぞん)しよう!
⌘Commandキーをおしながら、Sキーをおすとセーブできるよ!

宝探しゲームを作ろう!

それでは宝探しゲームを作っていきます!
わからないことがあったら、まわりのお兄さん・お姉さんに聞いてみましょう♪

Sceneをひらこう

宝探しゲーム用のSceneをひらくよ。
まずはProjectの、Sceneというフォルダの右にある三角▶をクリック。
scene_click.png

「Tutorial」と「Main」のふたつが出てきたね。
Mainが、宝探しゲームのSceneだよ。
Mainを ダブルクリック して、ひらこう!
main_click.png

こんな画面が出てきたらOK!
次にすすもう♪
スクリーンショット 2019-03-05 15.09.10.png

プレイヤーを動かそう

さっそく、プレイヤー(主人公)を動かしていくよ。

コードをつくろう

動かすためには「コード」がひつようだよ!
「Scripts」フォルダの、「CharacterControllerScript」をダブルクリックしてひらこう!
script_open.png

すこしまつと、こんな画面が出てくるよ。
この画面にならなかったらら、まわりのお兄さん・お姉さんに声をかけてね。
スクリーンショット 2019-02-26 12.45.14.png

変数を作ろう

プレイヤーを動かすのに使う変数を作っていくよ。

まずは「characterController」という名前の変数を作るよ。
赤いしかくの中のコードを、自分で書いてみよう!
hensu1.png

この調子で、あと4つ変数を作ろう!
赤いしかくの中のコードを書いてね。
hensu2.png

また、下のコードも書こう。
これは、さっき作った変数「characterController」を使うための初期設定だよ。
start.png

①前に動くようにする

上やじるしキーをおしたら、プレイヤーが前にすすむようにしよう。

「○○キーがおされたら、△△歩動かす」は、Scratchだと「ずっと」の中に入れるよね。
Unityでは、「ずっと」のブロックのかわりに「void Update()」を使うよ。
update.png

上やじるしキーで前にすすむは、
Scratchであらわすと、こんなコードになるね。
スクリーンショット 2019-02-28 10.49.41.png

Unityだと赤いしかくの中のようなコードになるよ。
画像を見ながら書いてみよう!
ue.png

コードが書けたら保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

プレイヤーが動くか確認してみよう♪
Unityにもどって、実行ボタン▶をおしてね。
上やじるしキーで、前にすすむようになったかな?

②うしろに動くようにする

次は、下やじるしキーをおしたら、うしろに動くようにしよう!
Scratchだと、こんなコードになるね。
スクリーンショット 2019-02-28 10.56.21.png

Unityだと、こんなコードになるよ。
画像を見ながら書いてみよう!
shita.png

コードが書けたら保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

プレイヤーが動くか確認してみよう♪
Unityにもどって、実行ボタン▶をおしてね。
下やじるしキーで、うしろにすすむようになったかな?

③右に動くようにする

右やじるしキーをおしたら、右に向くようにしよう!
Scratchだとこんなコードだよ。
スクリーンショット 2019-02-28 11.38.08.png

これをUnityで書くと、こんなコードになるよ!
画像を見ながら書いてみよう♪
migi.png

コードが書けたら保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

プレイヤーが動くか確認してみよう♪
Unityにもどって、実行ボタン▶をおしてね。
右やじるしキーで、右をむくようになったかな?

④左に動くようにする

左やじるしキーをおしたら、左に向くようにしよう!
Scratchだとこんなコードだよ。
hidari.png

これをUnityで書くと、こんなコードになるよ!
画像を見ながら書いてみよう♪
hidari.png

コードが書けたら保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

プレイヤーが動くか確認してみよう♪
Unityにもどって、実行ボタン▶をおしてね。
左やじるしキーで、左をむくようになったかな?

⑤ジャンプできるようにする

スペースキーをおしたら、ジャンプできるようにしよう!
Scratchのブロックだと、こんな組み合わせになるコードをUnityで書いていくよ。
スクリーンショット 2019-02-28 13.39.43.png

ちなみにUnityでは、こんなコードになるよ。
画像を見ながら書いてみよう!
jump.png

コードが書けたら保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

プレイヤーが動くかカクニン!

さいごにUnityにもどって、実行ボタン▶をおしてね。
プレイヤーが行きたい方向に動けるようになったかな?
また、ジャンプできるようになったかな?
カクニンしてみよう!

宝箱をゲットできるようにしよう

タグを作ろう

Unityさんは、宝箱が宝だと分かっていないから、
Unityさんに「これは宝だよ!」と教えてあげよう。

そのために「タグ」という機能を使うよ。
まず宝のタグを作ろう!

Hierarchyの、宝箱(Treasure1)をクリック。
treasure_click.png

いまはタグ(Tag)が「Untagged」になっているね。
(Untaggedは、タグなしという意味だよ)
untagged.png

Untaggedをクリックして、Add Tag...をクリックしよう。
Add Tag...は、タグをふやすという意味だよ。
addtag1.png

プラスボタン(+)をクリックして、新しいタグを作ろう。
plus_button.png

名前は「Treasure」がおすすめだよ。
(Treasureは、英語で宝という意味だよ)
※日本語は使えないよ!
treasure_input.png

名前を打ったら、「Save」(セーブ)をクリック!
tag_save.png

いま打った名前が出てきたかな?
treasure_dekita.png

タグができたら、またHierarchyから宝箱(Treasure1)をクリックしてね。
treasure_click.png

いま作ったタグをえらぼう!
tag_click.png

宝をゲットできるようになったかカクニンするよ。
実行ボタン▶をクリックして、プレイヤーを動かし宝箱に体当たりしてみよう!

宝箱が消えたらOKだよ!

ゲームを保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

宝箱をふやそう

宝箱のかずを5こにふやすよ!
Hierarchyの宝箱(Tresure1)を右クリックして、
「Duplicate」をクリック!
Duplicateは、「複製(ふくせい)」という意味だよ。
duplicate.png

3つのやじるしを使って、宝箱を好きなばしょに動かそう!
treasure2_idou.png

おなじやりかたで、宝箱をぜんぶで5こにしよう!
treasure5.png

5こにふやせたら、実行ボタンをおしてゲームで遊んでみよう!
ぜんぶゲットできるかな?

ゲームを保存(ほぞん)しよう!
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

ゲームをパワーアップさせよう

ステージをかえよう

ステージを作りこんで、見た目も本格的なゲームにしちゃおう!
スクリーンショット 2019-02-15 14.30.00.png

作りかたはこちら

BGMをつけよう

好きな音楽をながして、もっとカッコいいゲームにしよう♪
作りかたはこちら

ゲームが完成したら…

自分のゲームで遊んでみよう!
また、まわりのお兄さん・お姉さんやお友だちにも遊んでもらってね♪

さいごにゲームを保存(ほぞん)してね。
⌘Commandをおしながら、Sキーをおすとセーブできるよ!

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

【はじめてのUnity】宝探しゲームをつくろう!(Unity入門)

この記事は古い記事です

最新バージョンの記事はこちら

Unityとは

カンタンに言うと、 ゲームを作るキットです

スマホ版のどうぶつの森や、 スーパーマリオラン、 白猫プロジェクトもUnityで作られています
しかし、 Unityはゲーム以外のものも作ることができます
最近では、 手術のシミュレーションにも使われたりしているみたいですよ

Unityにさわってみよう

まずはUnityにさわってみるところから、 はじめていきましょう

画面の見かた

Scene(シーン)

Scene.png
ゲームに出てくる物体 (オブジェクト) は全部ここにあるよ
ここでオブジェクトの場所を、自由に変えることができるよ

Game(ゲーム)

Game.png
いわゆる「プレイ画面」のこと
ゲームをプレイする人は、この画面を見てプレイするよ

Hierarchy(ヒエラルキー)

Hierarchy.png
Sceneにあるモノ(オブジェクト)の一覧だよ
いまは、カメラ(MainCamera)とライト(Directional Light)があるよ

Project(プロジェクト)

Project.png
このゲームで使える素材が全部入っているところだよ

Inspector(インスペクター)

Inspector.png
オブジェクトなどをクリックすると、そのオブジェクトの情報(じょうほう)が出てくるよ

カメラの情報をチェック

ためしにカメラ(MainCamera)の情報を見てみよう
まず、Hierarchyの「MainCamera(メインカメラ)」をクリックしてみよう
Hierarchy_maincamera.png

InspectorにMainCameraの情報が出てきたかな?
Inspector_maincamera.png
オブジェクトの大きさや場所などを、きっちり変えたいときはここで数字を変えるとうまくいくよ

Console(コンソール)

Console.png

エラーや、メッセージが出てくるところだよ
赤いビックリマークが出てきていないときは、気にしなくて大丈夫だよ

Cube(キューブ)であそぼう

下の画像(がぞう)とおなじ画面になっているかな?

スクリーンショット 2019-02-13 13.36.38.png

Cubeを出そう

ひとつのキューブを出すよ
cube_create.png

Cubeの作りかた

①「Create」をクリック
②「3D Object」をクリック
③「Cube」をクリック
(「Create」から、色んなものを作ることができるよ)

CubeがSceneにあらわれたかな?
cube_scene.png

いろんな場所、むきから見てみよう

いま出したCubeをいろんな場所、むきから見てみよう

①いろんな場所から見る

まずはいろんな場所から見てみよう
ハンドツール✋をえらんでね
camera_move.png

Sceneの上でクリックしながらマウスを動かしてみよう
camera_movenow.png
Cubeをいろんな場所から見ることができるようになったかな?

②いろんなむきから見る

Sceneの上で 「右クリック」 しながらマウスを動かしてみよう
いろんなむきから見ることができたかな?
kakudo.png

Cubeを動かそう

次に、さっき作ったCubeを動かすよ
移動ツールをクリックしてね
yajirusi_sentaku.png

動かしたいモノ(Cube)をクリックしよう
やじるしが出てきたかな?
yajirusi.png

まずは上に動かしてみよう
上に向いている黄緑色のやじるしを、クリックしながらマウスを上に動かそう
yajirusi_y.png
Cubeが上に動いたかな?

「Game」が、プレイ画面だったね
あれ?GameにCubeがいないね
look_game.png

<ミッション>
Gameから見てCubeが見やすい場所になるように
3つのやじるし(青・赤・黄緑)を使ってCubeを動かしてみよう
cube_game.png

ミッションクリアしたら、ゲームを保存(ほぞん)しよう
⌘Commandキーをおしながら、Sキーをおすとセーブできるよ

宝探しゲームを作ろう

それでは宝探しゲームを作っていきます

Sceneをひらこう

宝探しゲーム用のSceneをひらくよ
まずはProjectの、Sceneというフォルダの右にある三角▶をクリック
scene_click.png

「Tutorial」と「Main」のふたつが出てきたね
Mainが、宝探しゲームのSceneだよ
Mainを ダブルクリック して、ひらこう
main_click.png

こんな画面が出てきたらOK
次にすすもう
スクリーンショット 2019-03-05 15.09.10.png

プレイヤーを動かそう

さっそく、プレイヤー(主人公)を動かしていくよ

コードをつくろう

動かすためには「コード」がひつようだよ!
「Scripts」フォルダの、「CharacterControllerScript」をダブルクリックしてひらこう
script_open.png

すこしまつと、こんな画面が出てくるよ

スクリーンショット 2019-02-26 12.45.14.png

変数を作ろう

プレイヤーを動かすのに使う変数を作っていくよ

まずは「characterController」という名前の変数を作るよ
赤いしかくの中のコードを、自分で書いてみよう
hensu1.png

この調子で、あと4つ変数を作ろう
赤いしかくの中のコードを書いてね
hensu2.png

また、下のコードも書こう
これは、さっき作った変数「characterController」を使うための初期設定だよ
start.png

①前に動くようにする

上やじるしキーをおしたら、プレイヤーが前にすすむようにしよう

「○○キーがおされたら、△△歩動かす」は、Scratchだと「ずっと」の中に入れるよね
Unityでは、「ずっと」のブロックのかわりに「void Update()」を使うよ
update.png

上やじるしキーで前にすすむは
Scratchであらわすと、こんなコードになるね
スクリーンショット 2019-02-28 10.49.41.png

Unityだと赤いしかくの中のようなコードになるよ
画像を見ながら書いてみよう
ue.png

コードが書けたら保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

プレイヤーが動くか確認してみよう
Unityにもどって、実行ボタン▶をおしてね
上やじるしキーで、前にすすむようになったかな?

②うしろに動くようにする

次は、下やじるしキーをおしたら、うしろに動くようにしよう
Scratchだと、こんなコードになるね
スクリーンショット 2019-02-28 10.56.21.png

Unityだと、こんなコードになるよ
画像を見ながら書いてみよう
shita.png

コードが書けたら保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

プレイヤーが動くか確認してみよう
Unityにもどって、実行ボタン▶をおしてね
下やじるしキーで、うしろにすすむようになったかな?

③右に動くようにする

右やじるしキーをおしたら、右に向くようにしよう
Scratchだとこんなコードだよ
スクリーンショット 2019-02-28 11.38.08.png

これをUnityで書くと、こんなコードになるよ
画像を見ながら書いてみよう
migi.png

コードが書けたら保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

プレイヤーが動くか確認してみよう
Unityにもどって、実行ボタン▶をおしてね
右やじるしキーで、右をむくようになったかな?

④左に動くようにする

左やじるしキーをおしたら、左に向くようにしよう
Scratchだとこんなコードだよ
hidari.png

これをUnityで書くと、こんなコードになるよ
画像を見ながら書いてみよう
hidari.png

コードが書けたら保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

プレイヤーが動くか確認してみよう
Unityにもどって、実行ボタン▶をおしてね
左やじるしキーで、左をむくようになったかな?

⑤ジャンプできるようにする

スペースキーをおしたら、ジャンプできるようにしよう
Scratchのブロックだと、こんな組み合わせになるコードをUnityで書いていくよ
スクリーンショット 2019-02-28 13.39.43.png

ちなみにUnityでは、こんなコードになるよ
画像を見ながら書いてみよう
jump.png

コードが書けたら保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

プレイヤーが動くかカクニン

さいごにUnityにもどって、実行ボタン▶をおしてね
プレイヤーが行きたい方向に動けるようになったかな?
また、ジャンプできるようになったかな?
カクニンしてみよう

宝箱をゲットできるようにしよう

タグを作ろう

Unityさんは、宝箱が宝だと分かっていないから
Unityさんに「これは宝だよ!」と教えてあげよう

そのために「タグ」という機能を使うよ
まず宝のタグを作ろう

Hierarchyの、宝箱(Treasure1)をクリック
treasure_click.png

いまはタグ(Tag)が「Untagged」になっているね
(Untaggedは、タグなしという意味だよ)
untagged.png

Untaggedをクリックして、Add Tag...をクリックしよう
Add Tag...は、タグをふやすという意味だよ
addtag1.png

プラスボタン(+)をクリックして、新しいタグを作ろう
plus_button.png

名前は「Treasure」がおすすめだよ
(Treasureは、英語で宝という意味だよ)
※日本語は使えないよ
treasure_input.png

名前を打ったら、「Save」(セーブ)をクリック
tag_save.png

いま打った名前が出てきたかな?
treasure_dekita.png

タグができたら、またHierarchyから宝箱(Treasure1)をクリックしてね
treasure_click.png

いま作ったタグをえらぼう
tag_click.png

宝をゲットできるようになったかカクニンするよ
実行ボタン▶をクリックして、プレイヤーを動かし宝箱に体当たりしてみよう

宝箱が消えたらOKだよ

ゲームを保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

宝箱をふやそう

宝箱のかずを5こにふやすよ
Hierarchyの宝箱(Tresure1)を右クリックして
「Duplicate」をクリック
Duplicateは、「複製(ふくせい)」という意味だよ
duplicate.png

3つのやじるしを使って、宝箱を好きなばしょに動かそう
treasure2_idou.png

おなじやりかたで、宝箱をぜんぶで5こにしよう
treasure5.png

5こにふやせたら、実行ボタンをおしてゲームで遊んでみよう
ぜんぶゲットできるかな?

ゲームを保存(ほぞん)しよう
⌘Commandをおしながら、Sキーをおすとセーブできるよ

ゲームをパワーアップさせよう

ステージをかえよう

ステージを作りこんで、見た目も本格的なゲームにしちゃおう
スクリーンショット 2019-02-15 14.30.00.png

作りかたはこちら

BGMをつけよう

好きな音楽をながして、もっとカッコいいゲームにしよう
作りかたはこちら

ゲームが完成したら…

自分のゲームで遊んでみよう

さいごにゲームを保存(ほぞん)してね
⌘Commandをおしながら、Sキーをおすとセーブできるよ

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

C#のNullable型で三項演算子を使うときの注意

はじめに

C#のNullable型で三項演算子を使おうと思ったらコンパイルエラーになったので、備忘録としてメモを残しておく。
ちなみに三項演算子を使いたかった理由は、三項演算子の方が可読性が高まるケースがあっためです。
(本記事は三項演算子の良し悪しについて議論したいわけではありません)

エラー内容

以下のコードはコンパイルエラーになります。

int? num = true ? 1 : null;

error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'int' and '<null>'

エラーメッセージを意訳すると、

三項演算子の第二オペランドの型と第三オペランドの型が異なるうえに、nullはintに暗黙的な型変換ができないよ

とのこと。

そもそも三項演算子は第二オペランドと第三オペランドを同じ型にする必要があります。
そのうえで、さらにnullはintに暗黙的な型変換ができないので、上記のように怒られているようですね。

解決策1

nullからNullable<int>へ明示的に型変換すれば、Nullable<int>からintへは暗黙的に型変換してくれるので実行可能になります。

int? num = true ? 1 : (int?)null;

解決策2

そもそも三項演算子にこだわらずifで書けば、もちろん問題ないですね。

int? num = null;
if (true) {
    num = 1;
}

参考リンク

https://blog.xin9le.net/entry/2013/02/11/035809

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

.NET FrameworkアプリでID/Password認証ありのproxyを突破する

やりたかったコト

  • BoxのSDKを使って、Box APIに接続しているが、そのコネクションを、認証ありのプロキシ経由にしたかった
  • BoxのSDKは、.NET Core で使用していた

できなかったコト

やったコト

  • .NET Coreじゃなきゃダメ、ってことがなかったので、.NET Frameworkで動くようにし、App.configでproxyの設定ができるようにした

App.configでのproxy設定方法

proxy設定なしの場合

defaultProxy項目自体なくてもよい

  <system.net>
    <defaultProxy enabled="false" useDefaultCredentials="false">
    </defaultProxy>
  </system.net>

proxy設定あり(認証なし)の場合

参考: https://docs.microsoft.com/ja-jp/dotnet/framework/configure-apps/file-schema/network/proxy-element-network-settings

  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="true">
        <proxy usesystemdefault="true"/>
    </defaultProxy>
  </system.net>

(本命)proxy設定あり(認証あり)の場合

参考: https://docs.microsoft.com/ja-jp/dotnet/framework/configure-apps/file-schema/network/module-element-network-settings

  <appSettings>
    <add key="http_proxy_url" value="http://[IP]:[Port]"/>
    <add key="proxy_user" value="hoge"/>
    <add key="proxy_pass" value="fuga"/>
  </appSettings>
  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="false">
      <module type="Sample.MyProxyModule, Sample"/>
    </defaultProxy>
  </system.net>

moduleの実装(Sample.MyProxyModule)

  • Sample/MyProxyModule.cs
    • 後述のApp.configから設定値を取得しています
using System;
using System.Net;
using System.Configuration;

namespace Sample
{
    public class MyProxyModule : IWebProxy
    {
        /// <summary>
        /// 認証情報
        /// </summary>
        public ICredentials Credentials { get; set; }

        /// <summary>
        /// ProxyServer名を返却
        /// </summary>
        /// <param name="destination"></param>
        /// <returns></returns>
        public Uri GetProxy(Uri destination)
        {
            return new Uri(ConfigurationManager.AppSettings["http_proxy_url"]);
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public AuthProxyModule()
        {
            try
            {
                Credentials = new NetworkCredential(ConfigurationManager.AppSettings["proxy_user"], ConfigurationManager.AppSettings["proxy_pass"]);
            }
            catch (Exception ex)
            {
                // 適宜
                throw;
            }
        }

        /// <summary>
        /// host でプロキシサーバーを使用しない場合は true。それ以外の場合は false。
        /// </summary>
        public bool IsBypassed(Uri host)
        {
            return false;
        }
    }
}
  • Sample/App.config
    • 認証情報をとりあえず、ここで設定。これは色々と方法あると思うので適宜。
  <appSettings>
    <add key="http_proxy_url" value="http://[IP]:[Port]"/>
    <add key="proxy_user" value="hoge"/>
    <add key="proxy_pass" value="fuga"/>
  </appSettings>

参考にさせていただきました。ありがとうございます:pray_tone2:
nap3/relayCredentials: 認証のプロキシの情報を中継するモジュール
c# - Is it possible to specify proxy credentials in your web.config? - Stack Overflow

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

C#でIMEの入力を受けるユーザーコントロールの作成

時々作りたくなるのですが、毎回忘れて調べるのに苦労する、C#でIMEの入力を受けるコントロールの作り方メモです。

 class SpTextEditorComponent : System.Windows.Forms.UserControl
    {

        #region IME関係

        private const int WM_IME_COMPOSITION = 0x010F;
        private const int GCS_RESULTREADSTR = 0x0200;
        private const int WM_IME_STARTCOMPOSITION = 0x10D; // IME変換開始
        private const int WM_IME_ENDCOMPOSITION = 0x10E;   // IME変換終了
        private const int WM_IME_NOTIFY = 0x0282;
        private const int WM_IME_SETCONTEXT = 0x0281;

        public enum ImmAssociateContextExFlags : uint
        {
            IACE_CHILDREN = 0x0001,
            IACE_DEFAULT = 0x0010,
            IACE_IGNORENOCONTEXT = 0x0020
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct C_RECT
        {
            public int _Left;
            public int _Top;
            public int _Right;
            public int _Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct C_POINT
        {
            public int x;
            public int y;
        }

        const uint CFS_POINT = 0x0002;

        public struct COMPOSITIONFORM
        {
            public uint dwStyle;
            public C_POINT ptCurrentPos;
            public C_RECT rcArea;
        }

        [DllImport("Imm32.dll")]
        private static extern IntPtr ImmGetContext(IntPtr hWnd);
        [DllImport("Imm32.dll")]
        private static extern int ImmGetCompositionString(IntPtr hIMC, int dwIndex, StringBuilder lpBuf, int dwBufLen);
        [DllImport("Imm32.dll")]
        private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
        [DllImport("imm32.dll")]
        private static extern IntPtr ImmCreateContext();
        [DllImport("imm32.dll")]
        private static extern bool ImmAssociateContextEx(IntPtr hWnd, IntPtr hIMC, ImmAssociateContextExFlags dwFlags);
        [DllImport("imm32.dll")]
        public static extern int ImmSetCompositionWindow(IntPtr hIMC, ref COMPOSITIONFORM lpCompositionForm);

        IntPtr himc = IntPtr.Zero;


        private void InitializeComponent()
        {
            this.SuspendLayout();
        }

        protected override void Dispose(bool disposing)
        {
            if (himc != IntPtr.Zero)
            {
                ImmReleaseContext(this.Handle, himc);
                himc = IntPtr.Zero;
            }
            base.Dispose(disposing);
        }

        ~SpTextEditorComponent()
        {
            if (himc != IntPtr.Zero)
            {
                ImmReleaseContext(this.Handle, himc);
                himc = IntPtr.Zero;
            }
        }


        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_IME_SETCONTEXT:
                    {
                        //Imeを関連付ける
                        IntPtr himc = ImmCreateContext();
                        ImmAssociateContextEx(this.Handle, himc, ImmAssociateContextExFlags.IACE_DEFAULT);
                        base.WndProc(ref m);
                        break;
                    }
                case WM_IME_STARTCOMPOSITION:
                    {
                        //入力コンテキストにアクセスするためのお約束
                        IntPtr hImc = ImmGetContext(this.Handle);

                        //コンポジションウィンドウの位置を設定
                        COMPOSITIONFORM info = new COMPOSITIONFORM();
                        info.dwStyle = CFS_POINT;
                        info.ptCurrentPos.x = 10;
                        info.ptCurrentPos.y = 10;
                        ImmSetCompositionWindow(hImc, ref info);

                        //コンポジションウィンドウのフォントを設定
                        //ImmSetCompositionFont(hImc, m_Focus->GetFont()->GetInfoLog());

                        //入力コンテキストへのアクセスが終了したらロックを解除する
                        ImmReleaseContext(Handle, hImc);


                        base.WndProc(ref m);
                        break;
                    }
                default:
                    //IME以外のメッセージは元のプロシージャで処理
                    base.WndProc(ref m);
                    break;
            }
        }

        #endregion


        public SpTextEditorComponent()
        {
            InitializeComponent();
        }
}

一部余分なコードや余分なインポートがありますが、ご勘弁を。
以下のことをしておけば最低限動くようです。

  • WndProcをオーバーライド
    • WM_IME_SETCONTEXT メッセージで
      • ImmCreateContext を呼んでコンテキストを作り、ImmAssociateContextEx でハンドルと結びつける
    • WM_IME_STARTCOMPOSITION メッセージで
      • ImmSetCompositionWindow を使い候補ウィンドウの位置を設定する
    • 解放のタイミング(Dispose?)で
      • ImmReleaseContext を呼んで解放

入力文字は、KeyPressイベントで一文字ずつ入ってきます。

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