UnityでジョイスティックのようなUIを作成したい!
Unityでモックを作成するときに仮想コントローラを作る機会がありました。仮想コントローラで少し大変なジョイスティックを実装した時にどのような感じで実装するかUIのみになりますが簡単に記述します。間違っている、もっといい方法があるかもしれないということを念頭に置いて参考にしてください( ´Ꙩωꙩ` )
以下画像のようにCanvas内でゲームオブジェクトを作成します。CanvasのImageのJostickFrameとButtonのJoystickButtonを追加します。

JoystickButtonゲームオブジェクトにJoystick.csスクリプトとEvent Triggerを追加します。Joystick.csの内容については以下に記述します。以下記述するスクリプトの今回の内容は、ゲームコントローラにあるようなジョイスティックのような挙動になるような制御になります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine;
public class Joystick : MonoBehaviour, IPointerUpHandler, IdragHandler {
private GameObject joystickButtonObject;
private Vector2 initialJoystickButtonPosition;
void Start()
{
joystickButtonObject = this.gameObject;
initialJoystickButtonPotision = joystickButtonObject.transform.position;
}
void Update()
{
}
// ボタンをリリース
public void OnPointerUp(PointerEventData ped)
{
joystickButtonObject.transform.position = initialJoystickButtonPosition;
}
// OnPointerDown実行後に移動した時
public void OnDrag(PointerEventData ped)
{
// JoystickButtonが移動する前にtransformを取得
Vector2 beforeMovePosition = joystickButtonObject.transform.position;
// JoystickButtonゲームオブジェクトの移動
joystickButtonObject.transform.position = new Vector2(
joystickButtonObject.transform.position.x + ped.delta.x,
joystickButtonObject.transform.position.y + ped.delta.y
);
// 初期位置からの移動距離を算出
float moveX = joystickButtonObject.transform.position.x - initialJoystickButtonPosition.x;
float moveY = joystickButtonObject.transform.position.y - initialJoystickButtonPosition.y;
// 三平方の定理(a^2+b^2=c^2)で移動距離を算出
float moveDistance = Mathf.Sqrt(Mathf.Pow(moveX, 2) + Mathf.Pow(moveY, 2));
// 移動距離を超えている場合は移動前に戻す
if (moveDistance >= MaxEnableDistance) {
joystickButtonObject.transform.position = beforeMovePosition;
}
}
}
ゲームのジョイスティックはJoystickButtonの移動反映は円形になります。そこで、中心点から反映内の直線距離を算出するために、三平方の定理を使うことにします。
これを使用するとうまいことジョイスティックみたいになります( ´Ꙩωꙩ` )b
Jenkinsから対話式のシェルを実行
Jenkinsからあるサーバに置いてあるシェルスクリプトを実行しなくてはいけないことになりました。
実行するだけならジョブのシェル実行にssh $HOSTNAME $SHELL_PATHを記述すれば良いですが、
実行しなくてはいけないシェルは対話式になっていました(◞‸◟)
ということで、対話式のシェルを実行するためのシェルを作成してJenkinsからでも実行できるようにしました。
#!/bin/bash
SHELL_PATH="/usr/local/bin/deploy.sh"
TARGET_ENV="develop"
TARGET_BRANCH="master"
expect -c "
set timeout -1
spawn $SHELL_PATH
expect -re \"Select Environment?.*\"
send \"${TARGET_ENV}\n\"
expect -re \"Select Branch?.*\"
send \"${TARGET_BRANCH}\n\"
expect eof
exit
"
対話式に対応させるためにexpectコマンドを使用して実現させました。細かく説明しますと、
expect -c "[コマンド群]":スクリプトを実行する前に、実行するコマンドを指示する。コマンドはシェルに壊されないようにクオートで囲むべきとされている。
set timeout -1:タイムアウトにする時間を設定できる。無制限にしたい場合は-1を設定する
spawn [実行コマンド]:ここで実行するシェルを指定する。
expect -re "[対話の対象となる文字文字列]":対話の対象になる文字列を指定する。
send "[対象の応答]":対話に対する応答の文字列を指定する。
expect eof,exit:cronやjenkinsから実行する場合はexpect eofとexitとする必要がある。
このシェルを使用すると対話式のシェルでもJenkinsから実行できるようになります。うむ、超絶便利!
Ruby on RailsにてRedisにマスタデータのModelをキャッシュ
とあるシュミレータをruby on rails上で作成することになり、ある処理を何万回、
何百万回と動作させなければいけなくなった。例えば以下の処理が本番環境で動作している。
def cards
(1..1000).each do |index|
index.to_s + ": " + Card.all[Random.rand(Card.all.size)].name
end
end
1000回ほど、カードというマスタデータのnameカラムをランダムに1件ずつ取得している処理だが、
Completed 200 OK in 17243ms (Views: 29.3ms | ActiveRecord: 2451.8ms)
ぐらいの処理時間になってしまう。特にActiveRecord: 2451.8msは1回の処理でmysqlに
アクセスしてしまうためにモデルデータをなんとかキャッシュできないかと考えなければいけない....!
というわけでruby on railsにredisを導入し、モデルデータをキャッシュしてしまおうと対応にでた。
def cards
(1..1000).each do |index|
cache = Rails.cache.fetch("card_data", expires_in: 1.hour) do
Card.all.to_a
end
index.to_s + ": " + cache[Random.rand(cache.size)].name
end
end
card_dataというkeyのvalueにCardモデルの内容を全てキャッシュするように記述してみました。
(expires_inに関してはTTL時間で1時間だけキャッシングするという記述)
これで処理してみると
Completed 200 OK in 16713ms (Views: 94.6ms | ActiveRecord: 0.4ms)
という結果を得ることができました。なんとActiveRecord: 0.4msという速度になり、logを確認すると
mysqlログもなくなりキャッシュからデータを取得できていることも確認できました。
(Views: 94.6msになってるのはなぜ・・)
ちなみに実際、どのようにデータがキャッシュされているかは以下コマンドで確認することができます。
$ redis-cli // redisコンソールの起動 127.0.0.1:6379> keys * // キャッシュされているkey一覧 1) "card_data" 127.0.0.1:6379> get card_data // valueの取得
コマンドは大変!クライアントソフトないの!?っという人もいると思います。(自分のことです...)
そういう方はRedis Desktop Managerを使用してみてはいかがでしょうか。
以下のような感じでredisを確認することができます。これは便利!

Modelファイルにスキーマ情報を簡単記述「annotate」
業務でruby on railsに触れて半年目。いろいろな便利なgemに触れてきました。
ということで今回、あったら便利だなぁというgemを紹介いたします。
今回紹介するgemはannotateです。
導入の仕方はGemfileに以下1文を記述して$ bundle installいます。
gem "annotate"
annotateをインストールした後に以下コマンドを入力します。
$ bundle exec annotate
そうすると、Annotated (1): Playerみたいな文言がmodelの分出力され、
app/models/以下にあるmodelのファイルにスキーマ情報が以下のようにコメントとして追記されます。
# == Schema Information # # Table name: cards # # id :integer not null, primary key # character_id :integer not null # name :string(255) not null
いちいちテーブルの情報を見なくても、このmodelにはこういうカラムが存在しているんだなぁというのが 一目瞭然になります。非常に便利なgemですので是非入れてみてください。
crystal-langのファイルをAtomで開く準備
最近、crystal-langに触れています。rubyのように書けて実行速度が爆速なのはありがたいですね。
さて、crystal-langはAtomエディタで主にプログラミングしているのですが、カラーシンタックスがPlain Textを選ばれてわざわざrubyに変更するのが面倒くさいと思いました。crという拡張子をrubyのカラーシンタックスになるように以下パッケージを導入しました。
設定はメニューバーから[Atom]->[Open Your Config]を選択して以下のように追記をします。
"*":
"file-types":
cr: "source.ruby"
tx: "text.html.basic"
この設定により、crがrubyのカラーシンタックスになります。(ついでににtxをhtmlに設定しています。)
※Atomはバージョン1.5.3に書いた記事です。
Unity5.3にしたときのシーン切り替えで暗くなる
Unity5.3がリリースしてすんなり動くかと思った第2弾。今度はSceneManager.LoadSceneでシーン切り替えを実施した際に、急に画面が暗くなります。
それを解決するためには、以下手順を踏んで設定を変更する。
- メニューバーから
Window=>Lightingを選択し、Lightmapsを3つのタブから選択する。 Autoのチェックを外して、Buildをクリックする。
この手順を踏むとSceneManager.LoadSceneした際に画面が暗くなりません。情報を提供していただいたクライアントエンジニアさんに感謝。
Unity5.3にしたときのシーンの切り替えで警告文
12月上旬にUnity5.3がリリースされました。新しい2DツールやJSONの公式サポート、カスタムコルーチン等、魅力的な機能が
多く追加されたのですぐにアップデートしました。5.2から5.3のアップデートなのですんなり動くだろう(根拠なし)と思っていましたが、
以下エラーが発生しました。
"UnityEngine.Application.LoadLevel(int)' is obsolete: `Use SceneManager.LoadScene'".
シーンファイルの切り替えはApplication.LoadLevel([シーンナンバー])で実施していましたが、なんとこれはもう時代遅れだ!SceneManager.LoadSceneを使えや!というUnityの警告が出力されました。ということで以下のように書き換え。
using UnityEngine.SceneManager;
// Application.LoadLevel([シーンIDまたはシーン名]); SceneManager.LoadScene([シーンIDまたはシーン名]);
これでUnityに怒られなくなります。