【Unity】カウントダウンを実装する
レースゲームでお馴染みのカウントダウンを実装していきます。
必要なものは3つ
①カウントダウンのアニメーション
②カウントダウン終了後の処理
③カウントダウン終了時のトリガー
①カウントダウンのアニメーションを作成する
カウントダウンのアニメーションを作成します。今回は、カウントダウンを示す数字が
右から左へ流れるようなアニメーションを作成しました。
www.youtube.com
②イベントハンドラ用の関数を書く
カウントダウン終了後に行いたい処理
- 車を走らせる
- 各ボタンを有効にする 等…
を記述した関数を用意しておきます。
public class Hoge : MonoBehaviour { /// <summary> /// カウントダウン終了後に呼ばれる /// </summary> public void CompletedCountDown() { //カウントダウン終了後に行いたい処理 ・・・ } }
③カウントダウン終了時のトリガーをつくる
アニメーションイベントを利用します。先ほど用意したイベントハンドラ用の関数を持つスクリプトを、
①カウントダウンのアニメーションが登録されたAnimatorを持っているオブジェクトにアタッチします。
次に、カウントダウンアニメーションのタイムラインを開き、
カウントダウン終了時のタイミングにカーソルを合わせて右クリックし、「Add Animation Event」を選択します。
すると白いタグのようなものが表示されます。
こちらの白いタグをクリックしてInspectorを開き、
「Function」に②で作成した関数を選択します。
選択欄に表示されていない場合は、
- イベントハンドラ用の関数がprivateで宣言されている
- イベントハンドラ用の関数を持つクラスがMonoBehaviourを継承していない
- Animatorがアタッチされているオブジェクトにスクリプトをアタッチしていない
この辺をチェックしてみてください。
そんな訳でカウントダウン終了後に車を走らせてみました。
www.youtube.com
対象のオブジェクトを振動させるクラス作ったよー
コード
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 振動タイプ /// </summary> internal enum VibrateType { VERTICAL, HORIZONTAL } /// <summary> /// 対象オブジェクトの振動を管理するクラス /// </summary> public class VibrateController : MonoBehaviour { [SerializeField] private VibrateType vibrateType; //振動タイプ [Range(0, 1)] [SerializeField] private float vibrateRange; //振動幅 [SerializeField] private float vibrateSpeed; //振動速度 private float initPosition; //初期ポジション private float newPosition; //新規ポジション private float minPosition; //ポジションの下限 private float maxPosition; //ポジションの上限 private bool directionToggle; //振動方向の切り替え用トグル(オフ:値が小さくなる方向へ オン:値が大きくなる方向へ) // Use this for initialization void Start () { //初期ポジションの設定を振動タイプ毎に分ける switch (this.vibrateType) { case VibrateType.VERTICAL: this.initPosition = transform.localPosition.y; break; case VibrateType.HORIZONTAL: this.initPosition = transform.localPosition.x; break; } this.newPosition = this.initPosition; this.minPosition = this.initPosition - this.vibrateRange; this.maxPosition = this.initPosition + this.vibrateRange; this.directionToggle = false; } // Update is called once per frame void Update () { //毎フレーム振動を行う Vibrate (); } private void Vibrate() { //ポジションが振動幅の範囲を超えた場合、振動方向を切り替える if (this.newPosition <= this.minPosition || this.maxPosition <= this.newPosition) { this.directionToggle = !this.directionToggle; } //新規ポジションを設定 this.newPosition = this.directionToggle ? this.newPosition + (vibrateSpeed * Time.deltaTime) : this.newPosition - (vibrateSpeed * Time.deltaTime); this.newPosition = Mathf.Clamp (this.newPosition, this.minPosition, this.maxPosition); //新規ポジションを代入 switch (this.vibrateType) { case VibrateType.VERTICAL: this.transform.localPosition = new Vector3 (0, this.newPosition, 0); break; case VibrateType.HORIZONTAL: this.transform.localPosition = new Vector3 (this.newPosition, 0, 0); break; } } }
使い方
振動させたいオブジェクトに上記スクリプトをアタッチします。今回はレースゲームで出てくる車の車体にくっつけます。
次に各プロパティを設定します。
- Type...振動タイプ。VERTICALが縦振動で、HORIZONTALが横振動。
- Range...振動させる範囲。値が大きいほど揺れ幅がでかくなる。
- Speed...振動速度。値が大きいほど時間あたりの振動回数が増える。
実行した結果がこちら↓
とあるサイトの文字化けを修正した話
とあるサイトの予約ページで、入力した値が全て文字化けしているので修正してほしいとの依頼があった。
確認してみたところ、サイト内の文字は全てShift_JISで扱われているが
POSTされた値がUTF-8で飛んでくるため文字化けが発生している様子。
(PHP5.6から変わったっぽい?)
Shift_JISに変換するよう色々試してみたがうまくいかず。
表示する値とPOSTする値を変換したら行けた
mb_convert_encoding($value, 'Shift_JIS')
しかし、このやり方だと修正箇所が相当な数になってしまうため
どうしてようかと悩んでいたところ・・・
便利な関数がありました。
string mb_convert_variables ( string $to_encoding , mixed $from_encoding , &$vars )
$to_encoding :変換先の文字エンコード
$from_encoding:変換元の文字エンコード
$vars :変換したい文字列を含む配列
この関数は配列内の文字列を全て変換したい文字コードに変換してくれます。
(第3引数は参照渡しの為、代入する必要はない)
$data = $_POST['data']; //文字コード変換 mb_convert_variables('Shift_JIS', 'UTF-8', $data);
―終了!
【Unity】お気に入りリンク集
●Unity開発で気を付けておきたい7つの事
www.shibuya24.info●Unity AssetStoreまとめ
assetsale.hateblo.jpUnityまとめ
unity-matome.comアプリに含めるアセットを抑えて、アプリサイズを小さくする
tsubakit1.hateblo.jp【Swift】WKWebView まとめ
SwiftでのWKWebView実装方法について自分なりにまとめてみました。
①WKWebViewを作成する
import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { @IBOutlet weak var contentView: UIView! //WebViewの表示領域 private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() //WkWebView 生成 self.webView = WKWebView(frame: CGRect.zero) //デリケート設定 self.webView.navigationDelegate = self //フリップでの戻る・進むを有効にする self.webView.allowsBackForwardNavigationGestures = true self.contentView.addSubview(self.webView) //ページ読み込み let url = NSURL(string: "https://www.google.co.jp/") let urlRequest = URLRequest(url: url as! URL) self.webView.load(urlRequest) } override func viewDidLayoutSubviews() { //WKWebView リサイズ self.webView.frame = CGRect(origin: CGPoint.zero, size: self.contentView.frame.size) } }
注意点
(ここにチェックが入っていると、ナビゲーションバーの高さ分レイアウトがずれてしまう)
②各デリケートの処理
// MARK: - WKWebView Delegate func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { let requestURL: URL? = navigationAction.request.url; // 電話対応 if(requestURL?.scheme == "tel") { var telNumber = String(describing: requestURL!) telNumber = telNumber.substring(from: telNumber.index(telNumber.startIndex, offsetBy: 4)) //アラートを出す ・・・ decisionHandler(.cancel) return } // メール対応 if(String(describing: requestURL).contains("http://") == false && String(describing: requestURL).contains("https://") == false) { if UIApplication.shared.canOpenURL(requestURL!){ UIApplication.shared.openURL(requestURL!) } decisionHandler(.cancel) return } // target=blankも開く if (navigationAction.navigationType == WKNavigationType.linkActivated) { if (navigationAction.targetFrame == nil || navigationAction.targetFrame!.isMainFrame) { self.mainWebView.load(URLRequest(url: requestURL!)) decisionHandler(.cancel); return; } } decisionHandler(.allow) } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { // ネットワークインジケータを表示 UIApplication.shared.isNetworkActivityIndicatorVisible = true; } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // ネットワークインジケータを非表示 UIApplication.shared.isNetworkActivityIndicatorVisible = false; } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { //ユーザーキャンセルによるエラーは無視する if((error as NSError).code != NSURLErrorCancelled) { //インジケータ非表示 UIApplication.shared.isNetworkActivityIndicatorVisible = false; //エラー時の処理 ・・・ } }
ポイント
③iOS10に対応する
input type=“file” 等のリンクをタップした時に写真ライブラリやカメラにアクセスする場合がある。
iOS10では、info.plistに使用目的を記述しておかないとアプリがクラッシュするので注意。
参考:http://dev.classmethod.jp/smartphone/iphone/ios10-privacy-data-purpose-description/
TeamViewerを使ってPCからAndroid端末を遠隔操作する
PCからAndroid端末をリモートコントロールできないか、と依頼された事があったので。
①操作される側(Android端末)の準備
初めに、遠隔操作を行いたい端末に
「TeamViewer QuickSupport」をインストールします。
インストールが完了したら、TeamViewer QuickSupportを起動します。
起動時にアドオンのダウンロードを促すダイアログが表示される場合があります。
インストールしたアプリを実行すると、下のような画面が表示されます。
「ダウンロード」ボタンを押すとPlayストアに移動するので、必要なアドオンをインストールします。
TeamViewer QuickSupportを起動すると下のような画面が表示されます。
「使用中のID」欄に、IDが表示されていることを確認できたら
Android側の準備は終了です。
TeamViewer QuickSupportは立ち上げたままにしておきます。
②操作する側(PC)の準備
遠隔操作を行うパソコンに「TeamViewer」をインストールします。
(Windows版 / Mac版と別れているので、必要な方をインストール。)
TeamViewerを立ち上げると、このような画面が表示されます。
画像赤枠部分にTeamViewer QuickSupportで表示されていたIDを入力します。
「パートナーに接続」ボタンを押すと、Android端末にリモートコントロールの許可を求めるダイアログが表示されるので、「許可」を押してリモートコントロールを開始します。
③実行
表示されているシミュレーターはマウスで操作することが可能です。
シミュレーターを操作すると、実機でも操作が同期されていることが確認できるかと思います。