kazumalab tech log

流行りとリラックマと嵐が大好きです。技術的ログ。

RailsのプロジェクトにRSpecを導入したお話

かずまです。

前回の記事で徳島を紹介するサイトを作ったお話をしました。
今回はそのRailsプロジェクトにテストコードを書いていこうということでRSpecを導入しました。

RSpec

github.com

Ruby用のGemもありますが、今回はRailsのプロジェクトということrails_rspecをインストールします。
Gemfileの中に書いてbundle installです。

忘れないうちにrspecの初期化をやっておきます。

$ rails g rspec:install

ちなみにテスト用のデータベースを用意する必要があるので、MySQLを使っている方などはRakeでRAILS_ENV=testを指定して作って上げる必要があります。

qiita.com
そこら辺はここを参考にするといいかも。

あとはGoogleで"rails mysql env"とかで検索すると情報が出てきますね。

テスト用のテストコードを書く

RSpecをインストールされるとspecディレクトリが出来ています。
ここにディレクトリを作成してRSpecのコードをカタカタ打っていきます。

ひとまずサンプルコードを書きたいと思います。
まずは言語のはじめに必ず書くとされる"Hello world!!"を出力してみます。

require 'rails_helper'

RSpec.describe ApplicationHelper, :type => 'helper' do
  describe "sample spec" do
    it "should print" do
      p "Hello World!!"
    end
  end
end 

いいですね。これで後は

rspec spec/sample/sample_spec.rb

ここで僕の場合、以下の様なwarningが...

DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /Users/kazuma/Documents/github/Prefecture/config/environment.rb:5)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /Users/kazuma/Documents/github/Prefecture/config/environment.rb:5)

これはググったところ、Rails5がサポートしていないGemがあるそうで、その警告でした。
まぁ警告してくれるのはありがたいですが毎回出るのは面倒なので切っておきます。

書くのはconfig/application.rb

ActiveSupport::Deprecation.silenced = true

これで消えました...!
あとは色々書いていくんですね。

Controllerのテストを書いてみる

今回はPictureという名前のモデルを使います。
そのPicturesControllerをテストします。

まずはRSpecのコード。

require 'rails_helper'
RSpec.describe PicturesController, :type => :controller do
  describe "GET #index" do
    it "respons success with an http 200 status code" do
      get :index
      expect(response).to be_success
    end

    it "renders the index template" do
      get :index
      expect(response).to render_template("index")
    end
  end
end

itの後ろは目的を書くらしいです。
何をするためのテストか?みたいな。

後は動作した結果、こうなってほしいというのを書くだけですね。
今回だとindexのレスポンスのステータスが200だと嬉しいよねってことでhave_http_status(200)です。

やる動作とそれに対応する返ってきてほしいものをit ... endの間に書くんでしょうね。

これはサンプルとか結構出回ってるので書いたという問題ではないけど....。
ちなみにここらへんを見るといっぱい書いてます。

File: README — Documentation for rspec-rails (3.6.0)

そんでRspecで叩く!

$ rspec spec/controllers/pictures_controller_spec.rb

Failures:

  1) PicturesController GET #index renders the index template
     Failure/Error: expect(response).to render_template("index")
     
     NoMethodError:
       assert_template has been extracted to a gem. To continue using it,
               add `gem 'rails-controller-testing'` to your Gemfile.
     # ./spec/controllers/pictures_controller_spec.rb:12:in `block (3 levels) in <top (required)>'

Finished in 0.0513 seconds (files took 3.57 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/controllers/pictures_controller_spec.rb:10 # PicturesController GET #index renders the index template

エラった、なんかgem rails-controller-testingを入れろ見たいなことを書いてますね。
念のためググって見る。

github.com
Readmeに書いてある、更にこっちも

github.com
Issueでも解決してるっぽい。

これを使ってみる。
Gemfileにgem rails-controller-testingを入れてbundle!!
localにも入れてもいいかも...と思ったけどまぁ今回は止めておくことにします。

入れ終わったら、今度こそ!

..

Finished in 0.06619 seconds (files took 2.64 seconds to load)
2 examples, 0 failures

通ったぽい!
これでガリガリテストも書けますね!

まとめ

すごく簡単に単体のテストができました。
次の課題としては一連の流れのテストと自動化ですね。

サービスとしてはテストの通ったものだけを入れたいので、CircleCIを使って検証します。

ついでにコード規約用のRubocopも導入してみました。
参考にしたURLはこちら。
qiita.com

最後に徳島を紹介するサービスはこちら!

tokushima.sinariovr.com

オープンデータとかも使っています。

余談

機械学習を始めようと思ってpyenv入れたり、pipでTensorflowとか入れてみたけどいまいち方法がわからなくてあたふたしてます。
Unityでゼルダも途中で終わっちゃってるので遺伝的アルゴリズムとかで最強の敵を作ったりしてもいいかなーと思って試行錯誤してる最中です。

時間かかりそうです。

RubyでOpenGLを動かすところまでのお話

かずまです。

今日は入社式とか研修とかでした。
帰ってバタンキューだったのですがなんか妙な時間に目覚めてしまったのでRubyOpenGLAPI叩けないかなーってことで調べてたら
あった!


別にRubyでゲーム作りたいとか、ではないのですが、使えると便利かな、ぐらいです。

github.com

ちゃんとありました。
DirectXは基本WindowsAPIになっているのでMacLinuxユーザーとしてはOpenGLかなって感じですね。
まぁVM立ててWindows立ち上げるみたいなので力技はできますが。

Sampleを動かす

先程のgithubからCloneしてきてSampleを動かしてみることにします。

GemのOpenGLとかを入れるのですが、まぁプロジェクトごとに管理できるのが一番いいのでBundlerを入れてしまいます。
入ってる場合は飛ばします。

こことかを参考にして

blog.tokoyax.com

$ gem install bundler

Fetching: bundler-1.14.6.gem (100%)
Successfully installed bundler-1.14.6
Parsing documentation for bundler-1.14.6
Installing ri documentation for bundler-1.14.6
Done installing documentation for bundler after 4 seconds
1 gem installed

OK、これでExampleディレクトリに移動して、

$ bundle init
$ vim Gemfile

ここでGemfileの中身を書き加えます。

gem 'opengl'
gem 'glu'
gem 'glut'

これで後は

$ bundle install --path=vendor/bundle

これでここのディレクトリのみにGemがインストールされるはずです。
よしこれで動く環境は整いました、examples/Neheに移動してrubyで叩いてみます!

$ bundle exec ruby nehe_lesson02.rb 

f:id:kazumalab:20170404023612p:plain

おぉー表示されました。
いいですね。

頂点をきめたりするところ

glBegin GL_POLYGON do
    glVertex3f  0.0,  1.0, 0.0
    glVertex3f  1.0, -1.0, 0.0
    glVertex3f -1.0, -1.0, 0.0
end

ここで三角形の頂点を決めてますね。
GL_POLYGONの部分でどんな形をレンダリングするかです。

ちなみにGL_QUADSのところを

glBegin GL_POINTS do
    glVertex3f -1.0,  1.0, 0.0
    glVertex3f  1.0,  1.0, 0.0
    glVertex3f  1.0, -1.0, 0.0
    glVertex3f -1.0, -1.0, 0.0
  end

GL_POINTSに変更すると

f:id:kazumalab:20170404033516p:plain

見えにくいですが点がレンダリングされます。

使うとよさそうな一覧が乗ったページがありますのでこちらを参考にするといいかも。
glBegin

今日は時間も遅いのでここまで。
お疲れ様でした。

敵ロックオン機能をUnityで実装する <ゼルダの伝説シリーズ>

かずまです。

今回も引き続き、ゼル伝シリーズをやっていきます。


そういえば今回のゼルダの伝説は一応ストーリー全クリしました。
ただマップの開放とかいっぱいやることはありますね。

ネタバレっぽくなっちゃいますが、感動した!これだけ言っておきます!笑

気になる方はこちら!
ゼルダの伝説 ブレス オブ ザ ワイルド


テーマ

今回は画面内に入った敵を注目してLボタンでロックオンするところです。
ロックオンして、タイミングよくバク転か、サイドステップをするとラッシュ攻撃ができます。

これです。
ちなみに一定の範囲内に入った時に注目できるよって示すマークを出します。

考察

ロックオン(注目)で重要な点は

  • 注目できる敵の上になにか表示
  • 注目したらなにか表示(上とは違うものを)
  • 注目しているときは敵を見続ける
  • 画面外になったときは解除される

これぐらいです。

下準備

まずは重要な点でも言ったなにか表示の部分の準備です。
注目している場合の画像は、今回いいのがあったのでフリーを使います。

yajidesign.com
この末広がりのやじるしです。

[指し示すだけの三角]
f:id:kazumalab:20170402082026p:plain
白紙ですが、この上に有ります。

これをSpriteRendererで違和感のないサイズに変更し、名前を"Point"に変更し、Prefab化します。

f:id:kazumalab:20170402090702p:plain
サイズ的にはこんな感じ。

そのPrefabに次のスクリプトをアタッチします。


これでPrefabにくっつけます。
この時、InspectorからSpriteをセットし忘れないように...。

EnemyManagerを作る

今回Enemyが画面に入ったらリストに追加、削除していきます。
そこから最短のEnemyを取り出したりすることができます。

これを作りました。
MonoBehaviourは継承しません。継承しちゃうとインスタンス生成できなくなりますかね。

次にEnemyManagerをPlayer.cs内でインスタンス生成します。
前回のPlayer.csを使い、変数とStart関数、新規メソッドを追加します。
ついでにXbox One ControllerのLBをLTriggerとしてUnityにセットしておきます。

// 変数
public EnemyManager EnemyMGR;

// Start関数でインスタンス生成、コンストラクタとしてPlayerが必要なので自分をいれる
private void Start () {
		EnemyMGR = new EnemyManager (this);
		CharactorCTL = GetComponent<CharacterControl> ();
		CameraCTL = GameObject.Find ("Main Camera").GetComponent<CameraControl> ();
	}

// 新規メソッド追加
public void Locked () {
		if (Input.GetAxis ("LTrigger") > 0.9f) {
			Enemy enemy = EnemyMGR.getNearEnemy ();
			if (enemy != null) {
                                // あとでEnemyAttentionメソッドを記載します
				enemy.Attention ();
			}
		}
	}

Enemyスクリプトに追記

次にEnemyは画面に入った、出た場合のタスクとして、そのEnemyManagerに自身を突っ込んでもらいます。
画面外は自分をリストから削除します。

画面に入った入ってないは

qiita.com

このQiitaで完結に解説されています。

// 画面外にでた
private void OnBecameInvisible () {
	player.EnemyMGR.DeleteEnemy (this);
}

// 画面内に入った
private void OnBecameVisible () {
	player.EnemyMGR.AddEnemy (this);
}

private void OnWillRenderObject() {
  // あとで記載
}

EnemyはPlayerを常に見ている状態なのでPlayerのEnemyManagerにもアクセスできることになります。
これで画面に入ったりでたりというのが確認できます。

注目しているかしていないか、Player側に持っておくのではなくEnemy側で管理します。
Enemy.csに変数とメソッドをもう少し付け加えます。

private readonly float AttentionDistance = 4f;

public bool isDrawingAttention = false;

public void Attention () {
	player.transform.LookAt (transform.position);
	isDrawingAttention = true;
}

public void UnAttention () {
	isDrawingAttention = false;
}

private void OnWillRenderObject() {
   // あとで記載と書いていた場所
	if (getDistance () < AttentionDistance) {
		transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = true;
	} else {
		transform.FindChild ("Point").GetComponent<SpriteRenderer> ().enabled = false;
	}
}

あとはこれでEnemyの子どもとしてPointのPrefabをセットします。
isDrawAttentionがtrueのときは注目している画像になればOKです!

結果

f:id:kazumalab:20170402181518g:plain

もっと派手なエフェクトほしいけどまた今度!
なんか雑になってきたやばい...。

追記

  • クラス図とか書こうと思う
  • オブジェクト指向プログラミング意識しよう
  • ちゃんと寝よう

敵の目線の動きをUnityで実装する <ゼルダの伝説シリーズ>

かずまです。

前回まではPlayerの動きを実装していました。



blog.kazumalab.com

ちなみにSwitchのゼルダの伝説の動きが気になる方はこちら。

ゼルダの伝説 ブレス オブ ザ ワイルド

テーマ

今回のテーマは"敵の動き"です。
敵がいないと始まらないですからね。

考察


敵の動きを見てみます。

気づかれると注目して見られる

音に気づく

目線があうと気づかれる

隠れると見失う

ココらへんが結構重要だと思います。
この章では歩くことはあとで実装します。

Enemyを追加

EnemyをPlayerと同じものを作ります。
前回作ったCharactorControlをつけます。

今度はEnemy.csを作ります。


気づいたときのアクション

EnemyにつけるNoticeObjectを作ります。

気づいたときのびっくりマークとはてなマークをPhotoShopとかIllustratorで作ります。
[びっくり]
f:id:kazumalab:20170331001612p:plain
[はてな]
f:id:kazumalab:20170331001727p:plain

両方背景透明なので白く見えますがあります。

Notice.csを作成

先程用意した画像をSpriteにして、SpriteRendererで表示します。
その時につけるスクリプトです。

以下のように設定します。
f:id:kazumalab:20170331002330p:plain

WarningはHatenaのSpriteを入れて、
DiscoveryはBikkuriのSpriteを入れます。

これをPrefab化して、その後、NoticeObjectに入れます。

ここからは重要な部分だけを取り上げて解説していきたいと思います。

Playerとの距離

Unity C#では

Vector3.Distance (Vector3 a, Vector3 b)

で距離を求めますが、今回は簡単なので実装してみます。
PowはC++でもライブラリがあるみたいなので、ちょっと意識して...

// Enemy.cs
Vector3 dv = player.transform.position - transform.position;
return Mathf.Pow ((dv.x * dv.x + dv.y * dv.y + dv.z * dv.z), 0.5f);

unitylab.wiki.fc2.com
いや、ここのサイトのように正規化したほうが良さそう。

EnemyはPlayerを探す

EnemyにはSearchメソッドがあって、そこの中でPlayerを探しています。

検索方法としては、

目線

Enemy.cs内でenum設定している

  • Warning

これは気づくか気づかないかを表します。
はてなマークのアイコンを使います。

  • Discovery

これは気づいたときを表します。
ビックリマークのアイコンを使います。

距離

これは先程、使ったメソッドを使って距離を測っています。
次の足音が小さければ距離が近くても気づかれないです。

足音

今回のゼルダから導入されました、足音の機能です。
気づかれず、回り込めば不意打ちを噛ませます。

これを実装します。

入力の力に合わせて足音を実装する

今回はXbox Controllerのスティックを使っているためGetAxisを使うことができます。

float dx = Input.GetAxis ("Horizontal");
float dy = Input.GetAxis ("Vertical");

WalkVolume = (Vector3.right * dx + Vector3.up * dy).magnitude;
getWalkVolumeStatus ();


Player.cs内のこの部分でmagnitudeで入力の加減を取っています。
これを足音としています。
スティックを強く押し込むと足音が大きく、軽く押し込むと小さくなります。


VolumeのStatusでどの動きか、を取ることができます。

  1. Quiet
  2. Small
  3. Loud

f:id:kazumalab:20170331013058g:plain

こんな感じ。
これに音をつければそれっぽくなります。

後半へばってしまいましたが、今回はこんな感じです。

f:id:kazumalab:20170331013805g:plain
デザインとかも実装したいですがうーん笑


コードのデザインもうまくいかないのでそこまで手が回らなそう。
もっとこうしたらいいよ、みたいなのがありましたら言ってください...!

カメラワークとプレイヤーの動きをUnityで実装する Part2 <ゼルダの伝説シリーズ>

かずまです。
前回の記事はこちら。

blog.kazumalab.com

そう、ゼルダの伝説です。

テーマ

今回のテーマはゼルダの伝説のプレイヤーの動きとカメラの動きを再現します。
しかし、昨日試行錯誤したのですが、ちょっと違うっぽい動きになってしまいました。
そのうち改善します。

考察

リンクの動きはカメラの方向が正面になります。
なので、動いている時にカメラを回転させたらその方向に移動する感じですね。

Playerを実装

まずはPlayerを動かします。
今回は拡張性を踏まえてCharactorControllerを使わないで自分で実装します。

上記スクリプトを書きます。
CharactorControllerではisGroundがあったので、それも実装してしまいます。

  1. Raycastで距離を測る
  2. Colliderでのあたり判定

この2つによって実装されます。
Colliderだけだと天井などに当たったときに反応してしまうのでRaycastも使います。


つけるコンポーネントは以下の通りです。
RigidbodyをつけてFreeze Rotationをすべてチェックいれます。
これをしないと物に当たった時に制御できなくなります。

f:id:kazumalab:20170328195415p:plain

次にPlayer.csを実装します。

これをPlayerのオブジェクトにくっつけます。
前回のブログでもちょこっとかきましたが、それにすこし付け足します。

UnityでXboxOneコントローラを使う…前に | 蒼玉亭
ここを参考にして、Playerの動きはXbox Controllerの左スティック、カメラの動きは右スティックを使って制御します。

Edit -> Project Settings -> Input
からMouse XとMouse Yがあるとおもうので、以下のように変更してあげます。
これでInput.GetAxis("Mouse X")でOKになります。

f:id:kazumalab:20170328200927p:plain

MacXbox Controllerを使う

Driverが必要だそうです。
github.com

ここからdmgを落としてくるなりでOKです。
再起動されます。

結果

ホントはこれ、カメラ動かしてないときはPlayerも回転させてかったけど...だめだった。
そのうち他のところ実装しながら思いついたらやり直します。