「技術メモ」カテゴリーアーカイブ

プレイブラスト

プレイブラスト

プレイブラストは,ビューを録画してファイルに保存すること.

通常のレンダリングと違い,簡易的な方法でありプレビズ(プリビズ)などで利用される.

本格的なレンダリングに入る前にプレイブラストで動きを確認する習慣をつけましょう.プレイブラストの方法については以下のとおり.なおWindows7での方法については別途指示します.

プレイブラストの方法

  1. タイムラインで右クリックし,プレイブラストを選択する
  2. プレイブラストオプションウィンドウが開くので,各設定を行,プレイブラストをクリック(※Windowsの設定)
  3. 設定によってはプレイヤーが立ち上がり,動画が再生される.うまく再生されない場合はエンコーディングの設定を確認する.

 

参考WEBページ

https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2016/JPN/Maya/files/GUID-2D865271-2873-4EDB-82C4-7FB9D7B311E7-htm.html

アニメーションキーの削除

アニメーションしたキーの削除

1つのキーだけを削除する場合

  1. 再生バーを移動させ,右クリックし,削除を選択する
  2. キーフレームが削除される

全てのキーを削除する場合

  1. ツールセットがアニメーションになっているか確認する
  2. キー>削除の□を選択する
  3. 全てを削除したり,フレーム間を決めて削除などできる

Swift2

HTMLのあれをとってくる

https://qiita.com/_tid_/items/8705275813e740d693ef

webView.evaluateJavaScript("document.documentElement.innerHTML") { value, error in
    print(value as? String as Any)
}

これはHTML全文になるので

 

webView.evaluateJavaScript("document.getElementById('tes').innerHTML") { value, error in
    print(value as? String as Any)
}

で,HTML内に

<p id="tes">2019</p>

いれておくと,

optinal(“2019”)と表示される.

 


IDをWKWebkitからとれなかったので,cookieから取る

まずPHPでcookieにuseridを設定

//cookie設定(Swift用)
$userid = $_SESSION["id"];
setcookie('userid', $userid,time()+60*60*24*7);
echo $_COOKIE[‘userid’];

 

Swiftでcookieを取得・ただしこれはiOS11用

        //セッション取得
        let cookieStore = webView.configuration.websiteDataStore.httpCookieStore

//        webView.configuration.websiteDataStore.httpCookieStore.getAllCookies {
//            print($0)//全部取る
//        }

                cookieStore.getAllCookies() { (cookies) in
            for cookie in cookies {
                if cookie.domain == "hoge.com" &&
                    cookie.name == "userid" {
                    // UserDefaultsに保存
                    let cookieData = NSKeyedArchiver.archivedData(withRootObject: cookie)
                    UserDefaults.standard.set(cookieData, forKey: "Cookie")
                    UserDefaults.standard.synchronize()
                    print(cookie.value)//これでuseridだけとれる
                }
            }
        }
        //

XCODEのコンソールに表示される

参考

https://qiita.com/haru15komekome/items/fdbdea6d755545468ac8


特定のURLで実行させたい(途中)

 

extension ViewController: WKNavigationDelegate {//の中に書く

// 読み込み開始後に実行
 func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
     //URLチェック
     //0.5秒後に実行する
     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
         // 0.5秒後に実行したい処理
         
     }
 }

参考
https://swift.tecc0.com/?p=669

https://qiita.com/s_emoto/items/dc3d61626155f5cf83e7

これのまとめ

extension ViewController: WKNavigationDelegate {

の中にかきます

// 読み込み開始後に実行
   func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
       //URLチェック
       let currentUrl:URL? = webView.url
       let url = currentUrl?.absoluteString
       
       // 特定のURLで分岐処理
       if url!.contains("https://hoge.com") { //動的URLなのでcontain使用url!<-は
           
           //print("URLが含まれる")
           // 0.5秒後に実行したい処理
           DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
               
               //セッション取得
               let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
               //        webView.configuration.websiteDataStore.httpCookieStore.getAllCookies {
               //            print($0)
               //        }
               cookieStore.getAllCookies() { (cookies) in
                   for cookie in cookies {
                       if cookie.domain == "life-log.org" &&
                           cookie.name == "userid" {
                           // UserDefaultsに保存
                           let cookieData = NSKeyedArchiver.archivedData(withRootObject: cookie)
                           UserDefaults.standard.set(cookieData, forKey: "Cookie")
                           UserDefaults.standard.synchronize()
                           print(cookie.value)//cookieのuseridをsessionに表示
                       }
                   }
               }
               ////セッションここまで
               
           }
       }
       
   }

 

containsの参考

https://qiita.com/osamu1203/items/3ee63291c37d91428b55

 


 

こんな夜更けにSwiftかよ

急ぎの開発案件ですがAndroidは作成中っぽいのでSwiftコードで

Simple Web Viewのチュートリアル実行
https://qiita.com/fromage-blanc/items/079bc8d6da34ac90fecf

こSimulatorで制作中のサイトチェック,JS系動作OK
動画が見づらいと言うのでこのサイトを見るも普通に動画再生確認.問題が起きたときに再確認.

iPhoneXに対応?
https://jidouka.work/?p=248

XR等にお対応をどうするのか,,

Push通知実装

参考

https://qiita.com/toshi586014/items/5dea32faab94828fae75

can’t find gem cocoapods 出たので,
sudo gem install cocoapods

pod init できた

pod isntallする.参考WEBにそって,公式より1つ多くSDKインスト

  pod 'Firebase/Core'
  pod 'Firebase/Messaging'

XCODEでエラーでた

Could not build Objective-C module ‘Firebase’

手順,

https://dev.classmethod.jp/smartphone/iphone/remove-xcode-derived-data/

1.Xcodeを終了
2.該当プロジェクトの「DerivedData」ファイルを削除

(消し方がわからない方は関連リンクをご覧ください。)
3.ProjectName.xcworkspaceを削除

(ProjectNameはプロジェクト名が入ります。)
4.「Podfile.lock」ファイルと「Pods」フォルダを削除
5.「pod install」で再度ポッドを追加
6.新しく生成された「ProjectName.xcworkspace」ファイルを開きビルド

特に1と6が重要
これで,Firebaseとの通信できた.

Firebaseから通知送るときは,
(1)実機であること

(2)通知送る画面の最下部にあるサウンドバッジを有効にする.

 

ここから,個別端末に通知の内容

このあたりを参考にした
https://qiita.com/miyae/items/623c7869714b894a1b83

これも参考に
https://cpoint-lab.co.jp/article/201811/%E3%80%90%E5%82%99%E5%BF%98%E9%8C%B2%E3%80%91firebase-cloud-messaging%E3%81%A7%E3%81%AE%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E9%80%9A%E7%9F%A5%E3%81%AE%E9%80%81%E4%BF%A1%E3%81%AB%E3%81%A4%E3%81%84/


まず,個別端末通知の方法

AppDelegate.swiftに

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenStr: String = deviceToken.reduce("", { $0 + String(format: "%02X", $1) })
    print("APNsトークン: \(deviceTokenStr)")

    // APNsトークンを、FCM登録トークンにマッピング


    if let fcmToken = InstanceID.instanceID().token() {
        print("FCMトークン: \(fcmToken)")
    }
}

を追加.これのFCMトークンがデバイスID.XCODEのコンソールで見ることができる

 

この情報元に,PHPでメッセージを送る

&lt;?php
class Notification {
  private static $apiKey = "ここにサーバーキー";  // Firebase console:Overview &gt; プロジェクトの設定 &gt; クラウドメッセージング &gt; サーバーキー
  private static $url = "https://fcm.googleapis.com/fcm/send";

  static public function send($pushTokens,$title,$message) {
    $headers = [
      "Authorization: key=".self::$apiKey,
      "Content-Type: application/json"
    ];

    $fields = [
      "registration_ids" =&gt; is_array($pushTokens) ? $pushTokens : [$pushTokens],
      "priority" =&gt; "high",
      "notification" =&gt; [
        "title" =&gt; $title,
        "text" =&gt; $message
      ]
    ];

    $handle = curl_init();
    curl_setopt($handle, CURLOPT_URL, self::$url);
    curl_setopt($handle, CURLOPT_POST, true);
    curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($fields));
    $result = curl_exec($handle);
    curl_close($handle);
    return $result;
}
}
?&gt;

これを送信するPHP

<?php

//クラス読み込み
require_once './messageClass.php';
//クラス生成
//$message = new Notification();

$pushTokens='';//ここにデバイスID
$title="はろー";
$message="ぼくどらやき";

Notification::send($pushTokens, $title, $message);

?>

サンタゲーム用スクリプト

サンタゲームのメインスクリプト.単眼VRで照準に入ったら色を変えたり,スコアを表示したり,残時間を表示するなど.

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


public class scope: MonoBehaviour {

    [Header("クロスヘア(照準)の画像をつけたUIを入れる")]
    public Image aimPointImage;
    [Header("スライダー(補足時間目安)のUIを入れる")]
    public Slider myslider;//UIのスライダー
    float slideValue = 0f;//スライダーの値用の変数
    bool soundBool = false;//音を連続再生されるのを防止するBool
    [Header("何点ゲットしたかを表示する画像用のUI")]
    public Image pointImage;//何点ゲットしたかを表示する画像用のUI
    [Header("上のImageが入っているGameObject")]
    public GameObject imageObj;//上のImageが入っているGameObject

    [Header("10点用画像")]
    public Sprite point10;//Imageに割り当てる画像(スプライト10点用以下同じ)
    [Header("20点用画像")]
    public Sprite point20;
    [Header("50点用画像")]
    public Sprite point50;

    [Header("クロスヘアにロックした時の音")]
    public AudioClip scopesound;//クロスヘアにロックした時の音
    [Header("プレゼントをゲットした音")]
    public AudioClip getsound;//プレゼントをゲットした音
    AudioSource audio;//オーディオソース用
    AudioSource audio2;

    [Header("ポイント表示用UI")]
    public Text pointTxt;//文字変数ポイント用
    [Header("時間表示用UI")]
    public Text timeText;//時間表示用文字
    int mypoint;//ポイント用Int
    [Header("初期残時間")]
    public int mytime;//時間用


    private void Start()
    {
        AudioSource[] audioSources = gameObject.GetComponents<AudioSource>();//Maincameraにアサインされている複数のAudioSourceを取得し配列に入れる

        audio = audioSources[0];//一つ目のオーディオソースの名前をaudioに
        audio2 = audioSources[1];
        imageObj.SetActive(false);//ポイント取得画像パネルを隠す

        mypoint = 0;
        pointTxt.text = mypoint.ToString();//UIの文字を初期化する
        timeText.text = mytime.ToString();//上と同じ
        Invoke("startTimer", 3f);//3秒後にタイマースタート
    }


    void FixedUpdate()
    {

        // Rayを飛ばす
        Ray ray = new Ray(transform.position, transform.forward);

        // outパラメータ用に、Rayのヒット情報を取得するための変数を用意
        RaycastHit hit;


        // Rayのhit情報を取得する

        if (Physics.SphereCast(ray, 0.5f, out hit, 80.0f)){//Rayで球を飛ばす

            // Rayがhitしたオブジェクトのタグ名を取得
            string hitTag = hit.collider.tag;

            // タグの名前がpresentだったら、照準の色が変わる
            if ((hitTag.Equals("present"))){
                //照準を赤に変える
                aimPointImage.color = new Color(1.0f, 0.0f, 0.0f, 1.0f);

                slideValue += 1.5f;//スライドバー用の値をアップさせる
                myslider.value = slideValue;//スライドバーの値をセットする

                if(!soundBool){//連打再生されないようにBoolで飛ばす
                    soundBool = true;
                    audio.PlayOneShot(scopesound, 0.2f);//スコープ用の音を再生する
                }


                //99越えたら消す
                if(slideValue > 99){
                    pointget(hit.collider.gameObject);
                    Destroy(hit.collider.gameObject);
                    soundBool = false;//再び再生できるようにする


                }

            }else{
                // present以外では水色に
                aimPointImage.color = new Color(0.0f, 1.0f, 1.0f, 1.0f);
                slideValue = 0f;//スライド値を0にする
                myslider.value = slideValue;//その値をスライドにセットする
                audio.Stop();//音再生停止
                soundBool = false;
            }

        }else{
            // Rayがヒットしていない場合は水色に
            aimPointImage.color = new Color(0.0f, 1.0f, 1.0f, 1.0f);
            slideValue = 0f;
            myslider.value = slideValue;
            audio.Stop();
            soundBool = false;
        }
    }


    void pointget(GameObject go){
        //音再生
        audio2.PlayOneShot(getsound);
        //ポイント表示
        //InstatiateしたPrefab名で足す点数を変えている
        //と同時にポイント用画像を選定してセットする
  
        if (go.name.Contains("PresentYel"))
        {
            pointImage.sprite = point10;
            mypoint += 10;
        }
        else if (go.name.Contains("PresentBlue"))
        {
            pointImage.sprite = point20;
            mypoint += 20;
        }
        else if (go.name.Contains("PresentRed"))
        {
            pointImage.sprite = point50;
            mypoint += 50;
        }

        PlayerPrefs.SetInt("score", mypoint);//End画面用にPlayerPrefsに得点をセットする
        imageObj.SetActive(true);//得点画面を出す
        Invoke("hidePoint", 1f);//1秒後にポイント画面を隠す
        pointTxt.text = mypoint.ToString();//ポイントを文字列に変更して表示
    }

    void hidePoint(){
        imageObj.SetActive(false);//ポイント画面を隠す
    }


    void startTimer(){
        
        StartCoroutine ("myTimer"); //コルーチンをスタートする
    }


    IEnumerator myTimer()
    {
        while (true)
        {
            mytime--;//初期設定の120秒を減らす

            if(mytime < 10){//10秒未満になったら残り時間を変える
                timeText.color = new Color(1.0f, 0.0f, 0.0f, 1.0f);//文字を赤色に
            }else{
                timeText.color = new Color(1.0f, 1.0f, 1.0f, 1.0f);//文字を白色に
            }

            timeText.text = mytime.ToString();

            yield return new WaitForSeconds(1.0f);//1秒間待つ


            //終了処理
            if(mytime < 1){
                Invoke("showScore", 2f);
                yield break;
                //終了処理へ

            }


        }
    }

    //やめるボタン用
    public void goHomeBtn(){
        SceneManager.LoadScene("op");
    }

    //タイムアップ処理
    void showScore(){
        //スコア表示画面へ
        SceneManager.LoadScene("end");
    }
}

スクリプトの使い方です.説明文を入れていますので参考に.

スクリプトに説明文を入れています

単眼VR用スクリプト

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

public class gyroCam : MonoBehaviour {

	// Use this for initialization
	void Start () {
		Input.gyro.enabled = true;
	}
	
	// 横位置用
	void Update () {
		transform.rotation = Quaternion.AngleAxis(90.0f,Vector3.right)*Input.gyro.attitude*Quaternion.AngleAxis(180.0f,Vector3.forward);
	}
}

スマートホンのジャイロに応じてカメラが移動します.Androidはジャイロが搭載されていない機種も多いので使えないこともあります.

動作例

ゲームオブジェクトを巡回させる(AI無し)

スクリプトがアサインされたゲームオブジェクトを毎回決まったルートを巡回させます.

下のスクリプトをPatrol.csとして保存しUnityに読み込みます.

using UnityEngine;
using System.Collections;

public class Patrol : MonoBehaviour
{

    [SerializeField, TooltipAttribute("経由地点の数を入力し,シーン上に配置した空のオブジェクトをアサインします")]
    public Transform[] wayPoints;

    public Transform target;
    public float speed;

    public int currentRoot;


    void Update()
    {

        //配列に入れたTransformを順に巡る.AIを使っていればスムーズに曲がるがこれは鋭角に曲がる

        float step = speed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, wayPoints[currentRoot].position, step);


        Vector3 pos = wayPoints[currentRoot].position;

        float test = Vector3.Distance(target.position, pos);
        transform.LookAt(pos);
                    
        if(Vector3.Distance(transform.position, pos) < 0.5f)
        {
          currentRoot = (currentRoot < wayPoints.Length - 1) ? currentRoot + 1 : 0;
        }

    }
}

シーン内に巡回するGameObjectを配置します.

図ではCubeを選択しています

このGameObjectにPatrol.csをアサインします.

Sizeは巡回箇所の数で,ここに数字を入れると下に入力フィールドが現れます.Speedには適当な数字を入れておきます.

Elementには GameObject>CreateEmptyで作成した空のオブジェクト(位置情報のみ)を配置いれます.

これで再生すると,Patrol.csをアサインしたGameObjectがWayPointsを巡回するようになります.

キャラクタにモーションを追加する

コントロールオブジェクトを選択し、Sキーでキーフレームを設定し、アニメーションを作成する。

まずはアイドリングのアニメーションを作成する。およそ2〜3秒で1回のアニメーションとすること。

この他に「歩く」「走る」の基本モーションと、ゲームの内容に応じて、「驚く」「伏せる」「怒る」「襲う」などを作成すること。アニメーションについては、グラフエディタなどを使いループ時のつなぎ目が無いように設定すること。

増分保存することで、リセットできるようにしておくこと。

アニメーションが設定できたら、編集>キー>シミュレーションのベイク処理 を実施する。設定は以下画像を参考に。

その後、ファイル>すべて書き出し>□

プリセットを編集>アニメーションをベイク処理>アニメーションをベイク処理にチェック をして書き出す。

Unity上でアニメーションが再生されます。この後、プログラムを使い、状況に応じて再生するアニメーションを変えることで、自分が操作しているように見せることができます。

シーン遷移の基本

シーン遷移の基本を学びます.

ここでは,トップ画面>ゲーム画面>エンド画面の3つのシーンを移動しまたトップ画面へ戻ります.

 

ワークフロー

  • シーンを作成
  • ボタンを作成
  • スクリプトを作成
  • ボタンにスクリプトをアサイン
  • ビルド設定をする
  • 実行する

 

トップシーンを作成する

  1. トップ画面用シーンを作成する
  2. トップ画面用シーンに適宜UI>Textを入れて遷移時にどの画面にいるか分かるようにする
  3. トップ画面にGameObject>UI>Buttonでボタンを作成する
  4. 位置調整をする(参考画像)

 

スクリプト作成

  1. scnChangeというファイル名でスクリプトを作成する(※ファイル名とclass名は同一にすること)
  2. 全て以下に入れ替え保存する(※このスクリプトは他でも使い回しできます)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.SceneManagement;//これを必ず追加しないと使えない


public class scnChange : MonoBehaviour {

    public string scnName;//変数scnNameをInspectorからセットできるようにする
	
	
    public void goScene(){
        SceneManager.LoadScene(scnName);//変数scnNameのシーンにシーン遷移する
    }

}

 

スクリプトをボタンにアサインする

  1. GameObject>CreateEmpty で空のオブジェクトに上で作成したスクリプトをコンポーネントに追加する
  2. Scn Nameの欄にジャンプ先のシーン名を入力する(※これがInspectorに表示されるのは10行目の変数宣言をpublicにしているから)
  3. ボタンを選択し,OnClickの+ボタンでリストを追加する
  4. 追加したリストに作成した空のオブジェクト(1でスクリプトがついているもの)をアサインする
  5. NoFunctionのプルダウンからscnChange>goSceneを選択する(13行目のpublic void goScene を実行するという意味,publicがついているとボタンから押せる)

ビルド設定をおこなう

  1. File>Build Settings…でビルド設定を開き,ドラッグ&ドロップで,ここで作成した最初のシーンと,これまで作成しらゲームのシーンを追加する
  2. 保存し,トップ画面用シーンを再生し,ボタンを押してシーン遷移するか確認する
  3. シーン遷移後,ゲーム画面の明るさが少し暗いようでしたら,そのシーンのWindow>Lightingを選び,AutoGenerateのチェックを外し,Generateを一度押しておきます

 

実習

  • エンドシーンを作成する
  • ゲームシーンからエンドシーンエンドシーンからトップシーンへとジャンプさせ3つのシーンを1周できるようにすること

Ultimate Joystick cam

ultimate joystick用スクリプト

// BEGIN MIT LICENSE BLOCK //
//
// Copyright (c) 2016 dskjal
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
//
// END MIT LICENSE BLOCK   //
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class followCam3 : MonoBehaviour
{
    public Transform Target;
    public float DistanceToPlayerM = 2f;    // カメラとプレイヤーとの距離[m]
    public float SlideDistanceM = 0f;       // カメラを横にスライドさせる;プラスの時右へ,マイナスの時左へ[m]
    public float HeightM = 1.2f;            // 注視点の高さ[m]
    public float RotationSensitivity = 100f;// 感度
    public float limitMax = 0.4f;
    public float limitMin = -0.4f;

    void Start()
    {
        if (Target == null)
        {
            Debug.LogError("ターゲットが設定されていない");
            Application.Quit();
        }
    }

    void FixedUpdate()
    {


       // var rotX = Input.GetAxis("Mouse X") * Time.deltaTime * RotationSensitivity;
       // var rotY = Input.GetAxis("Mouse Y") * Time.deltaTime * RotationSensitivity;

        float rotX = UltimateJoystick.GetHorizontalAxis("camStick")* Time.deltaTime * RotationSensitivity;
        float rotY = UltimateJoystick.GetVerticalAxis("camStick")* Time.deltaTime * RotationSensitivity;

        var lookAt = Target.position + Vector3.up * HeightM;

        // 回転
        transform.RotateAround(lookAt, Vector3.up, rotX);
        // カメラがプレイヤーの真上や真下にあるときにそれ以上回転させないようにする
        if (transform.forward.y > limitMax && rotY < 0)//default 0.9
        {
            rotY = 0;
        }
        if (transform.forward.y < limitMin && rotY > 0)
        {
            rotY = 0;
        }
        transform.RotateAround(lookAt, transform.right, rotY);

        // カメラとプレイヤーとの間の距離を調整
        transform.position = lookAt - transform.forward * DistanceToPlayerM;

        // 注視点の設定
        transform.LookAt(lookAt);

        // カメラを横にずらして中央を開ける
        transform.position = transform.position + transform.right * SlideDistanceM;
    }
}

 

参考サイト

https://dskjal.com/unity/tps-camera.html