/* * ExternalReceiver * https://sabowl.sakura.ne.jp/gpsnmeajp/ * * MIT License * * Copyright (c) 2019 gpsnmeajp * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ using System.Collections; using System.Collections.Generic; using UnityEngine; namespace EVMC4U { [RequireComponent(typeof(ExternalReceiver))] public class HandCatch : MonoBehaviour { //表示オンオフ public bool ShowCollider = true; bool ShowColliderOld = true; public float NonHoldFilter = 0f; public float InHoldFilter = 0.90f; float offset = 0.06f; float size = 0.15f; public string CollisionTag = ""; public float SpeedMultiplier = 1.0f; public string LeftKey = "Z"; public string RightKey = "X"; public string ControllerButton = "ClickTrigger"; public bool signaling = true; public bool StickyMode = false; bool stickyLeft = false; bool stickyRight = false; ExternalReceiver exrcv; InputReceiver inputrcv; Transform leftHand; Transform rightHand; GameObject leftSphere; GameObject rightSphere; Rigidbody leftRigidBody; Rigidbody rightRigidBody; Vector3 leftLastPos; Vector3 rightLastPos; Vector3 leftLastSpeed; Vector3 rightLastSpeed; HandCatch_Helper leftHelper; HandCatch_Helper rightHelper; GameObject leftCatchedObject; GameObject rightCatchedObject; bool leftCatchedObjectIsKinematic; bool rightCatchedObjectIsKinematic; Transform leftCatchedObjectParent; Transform rightCatchedObjectParent; void Start() { //ExternalReceiverにキー操作を登録 exrcv = GetComponent(); inputrcv = GetComponentInChildren(); inputrcv.ControllerInputAction.AddListener(ControllerInputEvent); inputrcv.KeyInputAction.AddListener(KeyInputEvent); //ブレ防止用にフィルタを設定 exrcv.BonePositionFilterEnable = true; exrcv.BoneRotationFilterEnable = true; exrcv.BoneFilter = NonHoldFilter; //手のボーンを取得 var anim = exrcv.Model.GetComponent(); leftHand = anim.GetBoneTransform(HumanBodyBones.LeftHand); rightHand = anim.GetBoneTransform(HumanBodyBones.RightHand); //左手当たり判定スフィア生成 leftSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); leftSphere.transform.parent = leftHand; leftSphere.transform.localPosition = new Vector3(-offset, 0f, 0f); leftSphere.transform.localScale = new Vector3(size, size, size); //左手当たり判定スフィアコライダー設定 var leftCollider = leftSphere.GetComponent(); //コライダーは反応のみで衝突しない leftCollider.isTrigger = true; //左手当たり判定物理演算追加 leftRigidBody = leftSphere.AddComponent(); //物理は反応のみで演算しない leftRigidBody.isKinematic = true; //左手当たり判定ヘルパー追加 leftHelper = leftSphere.AddComponent(); //右手当たり判定スフィア生成 rightSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); rightSphere.transform.parent = rightHand; rightSphere.transform.localPosition = new Vector3(offset, 0f, 0f); rightSphere.transform.localScale = new Vector3(size, size, size); //右手当たり判定スフィアコライダー設定 var rightCollider = rightSphere.GetComponent(); //コライダーは反応のみで衝突しない rightCollider.isTrigger = true; //右手当たり判定物理演算追加 rightRigidBody = rightSphere.AddComponent(); //物理は反応のみで演算しない rightRigidBody.isKinematic = true; //右手当たり判定ヘルパー追加 rightHelper = rightSphere.AddComponent(); } //物理演算のためFixedUpdate void FixedUpdate() { //剥がれ防止で親を設定 leftSphere.transform.parent = leftHand; leftSphere.transform.localPosition = new Vector3(-offset, 0f, 0f); leftSphere.transform.localScale = new Vector3(size, size, size); rightSphere.transform.parent = rightHand; rightSphere.transform.localPosition = new Vector3(offset, 0f, 0f); rightSphere.transform.localScale = new Vector3(size, size, size); //表示非表示を反映 if (ShowColliderOld != ShowCollider) { leftSphere.GetComponent().enabled = ShowCollider; rightSphere.GetComponent().enabled = ShowCollider; ShowColliderOld = ShowCollider; } //投げるとき用にフレーム間速度を求める leftLastSpeed = SpeedMultiplier * (leftHand.transform.position - leftLastPos)/Time.fixedDeltaTime; leftLastPos = leftHand.transform.position; rightLastSpeed = SpeedMultiplier * (rightHand.transform.position - rightLastPos)/Time.fixedDeltaTime; rightLastPos = rightHand.transform.position; } //左手掴む処理 void CatchLeft(bool s) { if (s) { //つかみ処理 if (leftHelper.Trigger && leftHelper.other != null) { //コリジョンタグになにか文字が入っていて、対象と一致しない場合は処理しない if (CollisionTag != "" && CollisionTag != leftHelper.other.tag) { return; } //左手ですでに掴んでいるものは掴まない if (leftHelper.other.gameObject.transform.parent == leftSphere.transform) { return; } //右手ですでに掴んでいるものは掴まない if (leftHelper.other.gameObject.transform.parent == rightSphere.transform) { return; } //解除用に保持 leftCatchedObject = leftHelper.other.gameObject; //親を保存 leftCatchedObjectParent = leftCatchedObject.transform.parent; //手を親に上書き leftCatchedObject.transform.parent = leftSphere.transform; //掴むために物理演算を切る var rigid = leftCatchedObject.GetComponent(); if (rigid != null) { //IsKinematicを保存 leftCatchedObjectIsKinematic = rigid.isKinematic; //設定に関わらずtrueにする rigid.isKinematic = true; } //フィルタ強く exrcv.BoneFilter = InHoldFilter; //オブジェクトにメッセージを送る if (signaling) { leftCatchedObject.SendMessage("OnCatchedLeftHand"); } } } else { if (leftCatchedObject != null) { //解除して親に戻す leftCatchedObject.transform.parent = leftCatchedObjectParent; //掴むために物理演算を切る var rigid = leftCatchedObject.GetComponent(); if (rigid != null) { //IsKinematicを保存していた設定にする rigid.isKinematic = leftCatchedObjectIsKinematic; //投げるために速度を転送する rigid.linearVelocity = leftLastSpeed; } //フィルタ解除 exrcv.BoneFilter = NonHoldFilter; //オブジェクトにメッセージを送る if (signaling) { leftCatchedObject.SendMessage("OnReleasedLeftHand"); } } } } void CatchRight(bool s) { if (s) { if (rightHelper.Trigger && rightHelper.other != null) { //コリジョンタグになにか文字が入っていて、対象と一致しない場合は処理しない if (CollisionTag != "" && CollisionTag != rightHelper.other.tag) { return; } //左手ですでに掴んでいるものは掴まない if (rightHelper.other.gameObject.transform.parent == leftSphere.transform) { return; } //右手ですでに掴んでいるものは掴まない if (rightHelper.other.gameObject.transform.parent == rightSphere.transform) { return; } //解除用に保持 rightCatchedObject = rightHelper.other.gameObject; //親を保存 rightCatchedObjectParent = rightCatchedObject.transform.parent; //手を親に上書き rightCatchedObject.transform.parent = rightSphere.transform; //掴むために物理演算を切る var rigid = rightCatchedObject.GetComponent(); if (rigid != null) { //IsKinematicを保存 rightCatchedObjectIsKinematic = rigid.isKinematic; //設定に関わらずtrueにする rigid.isKinematic = true; } //フィルタ強く exrcv.BoneFilter = InHoldFilter; //オブジェクトにメッセージを送る if (signaling) { rightCatchedObject.SendMessage("OnCatchedRightHand"); } } } else { if (rightCatchedObject != null) { //解除して親に戻す rightCatchedObject.transform.parent = rightCatchedObjectParent; //掴むために物理演算を切る var rigid = rightCatchedObject.GetComponent(); if (rigid != null) { //IsKinematicを保存していた設定にする rigid.isKinematic = rightCatchedObjectIsKinematic; Debug.Log(rightRigidBody.linearVelocity); //投げるために速度を転送する rigid.linearVelocity = rightLastSpeed; } //フィルタ解除 exrcv.BoneFilter = NonHoldFilter; //オブジェクトにメッセージを送る if (signaling) { rightCatchedObject.SendMessage("OnReleasedRightHand"); } } } } public void KeyInputEvent(EVMC4U.KeyInput key) { if (!StickyMode) { //Zキーが押されたか if (key.name == LeftKey) { //つかみ・離し CatchLeft(key.active == 1); } //Xキー押されたか if (key.name == RightKey) { //つかみ・離し CatchRight(key.active == 1); } } else { if (key.active == 1) { //Zキーが押されたか if (key.name == LeftKey) { //つかみ・離し stickyLeft = !stickyLeft; CatchLeft(stickyLeft); } //Xキー押されたか if (key.name == RightKey) { //つかみ・離し stickyRight = !stickyRight; CatchRight(stickyRight); } } } } public void ControllerInputEvent(EVMC4U.ControllerInput con) { //トリガー引かれたか if (con.name == ControllerButton) { if (!StickyMode) { if (con.IsLeft == 1) { //つかみ・離し CatchLeft(con.active == 1); } else { //つかみ・離し CatchRight(con.active == 1); } } else { if (con.active == 1) { if (con.IsLeft == 1) { //つかみ・離し stickyLeft = !stickyLeft; CatchLeft(stickyLeft); } else { //つかみ・離し stickyRight = !stickyRight; CatchRight(stickyRight); } } } } } } }