11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License. See LICENSE in the project root for license information.
33
4+ using System ;
45using HoloToolkit . Unity . InputModule ;
56using UnityEngine ;
67
@@ -22,6 +23,18 @@ public class TapToPlace : MonoBehaviour, IInputClickHandler
2223 [ Tooltip ( "Supply a friendly name for the anchor as the key name for the WorldAnchorStore." ) ]
2324 public string SavedAnchorFriendlyName = "SavedAnchorFriendlyName" ;
2425
26+ [ Tooltip ( "Place parent on tap instead of current game object." ) ]
27+ public bool PlaceParentOnTap = false ;
28+
29+ [ Tooltip ( "Specify the parent game object to be moved on tap, if the immediate parent is not desired." ) ]
30+ public GameObject ParentGameObjectToPlace ;
31+
32+ /// <summary>
33+ /// Keeps track of if the user is moving the object or not.
34+ /// Setting this to true will enable the user to move and place the object in the scene.
35+ /// </summary>
36+ public bool IsBeingPlaced ;
37+
2538 /// <summary>
2639 /// Manages persisted anchors.
2740 /// </summary>
@@ -34,11 +47,12 @@ public class TapToPlace : MonoBehaviour, IInputClickHandler
3447 private SpatialMappingManager spatialMappingManager ;
3548
3649 /// <summary>
37- /// Keeps track of if the user is moving the object or not.
50+ /// Keeps track of the relative position between the parent object to be moved and
51+ /// the current gameobject this script is attached to.
3852 /// </summary>
39- private bool placing ;
53+ private Vector3 parentPositionRelativeToChild ;
4054
41- private void Start ( )
55+ public virtual void Start ( )
4256 {
4357 // Make sure we have all the components in the scene we need.
4458 anchorManager = WorldAnchorManager . Instance ;
@@ -62,46 +76,67 @@ private void Start()
6276 // If we don't have what we need to proceed, we may as well remove ourselves.
6377 Destroy ( this ) ;
6478 }
79+
80+ if ( PlaceParentOnTap )
81+ {
82+ if ( ParentGameObjectToPlace != null && ! gameObject . transform . IsChildOf ( ParentGameObjectToPlace . transform ) )
83+ {
84+ Debug . LogError ( "The specified parent object is not a parent of this object." ) ;
85+ }
86+
87+ DetermineParent ( ) ;
88+
89+ parentPositionRelativeToChild = gameObject . transform . position - ParentGameObjectToPlace . transform . position ;
90+ }
6591 }
6692
67- private void Update ( )
93+ public virtual void Update ( )
6894 {
6995 // If the user is in placing mode,
7096 // update the placement to match the user's gaze.
71- if ( placing )
97+ if ( IsBeingPlaced )
7298 {
99+ if ( gameObject . GetComponent < TapToPlace > ( ) . IsBeingPlaced ) { }
73100 // Do a raycast into the world that will only hit the Spatial Mapping mesh.
74- var headPosition = Camera . main . transform . position ;
75- var gazeDirection = Camera . main . transform . forward ;
101+ Vector3 headPosition = Camera . main . transform . position ;
102+ Vector3 gazeDirection = Camera . main . transform . forward ;
76103
77104 RaycastHit hitInfo ;
78- if ( Physics . Raycast ( headPosition , gazeDirection , out hitInfo ,
79- 30.0f , spatialMappingManager . LayerMask ) )
105+ if ( Physics . Raycast ( headPosition , gazeDirection , out hitInfo , 30.0f , spatialMappingManager . LayerMask ) )
80106 {
107+ // Rotate this object to face the user.
108+ Quaternion toQuat = Camera . main . transform . localRotation ;
109+ toQuat . x = 0 ;
110+ toQuat . z = 0 ;
111+
81112 // Move this object to where the raycast
82113 // hit the Spatial Mapping mesh.
83114 // Here is where you might consider adding intelligence
84115 // to how the object is placed. For example, consider
85116 // placing based on the bottom of the object's
86117 // collider so it sits properly on surfaces.
87- this . transform . position = hitInfo . point ;
88-
89- // Rotate this object to face the user.
90- Quaternion toQuat = Camera . main . transform . localRotation ;
91- toQuat . x = 0 ;
92- toQuat . z = 0 ;
93- this . transform . rotation = toQuat ;
118+ if ( PlaceParentOnTap )
119+ {
120+ // Place the parent object as well but keep the focus on the current game object
121+ ParentGameObjectToPlace . transform . position = hitInfo . point - parentPositionRelativeToChild ;
122+ ParentGameObjectToPlace . transform . rotation = toQuat ;
123+ }
124+ else
125+ {
126+ gameObject . transform . position = hitInfo . point ;
127+ gameObject . transform . rotation = toQuat ;
128+ }
94129 }
95130 }
96131 }
97132
98- public void OnInputClicked ( InputEventData eventData )
133+ public virtual void OnInputClicked ( InputEventData eventData )
99134 {
100135 // On each tap gesture, toggle whether the user is in placing mode.
101- placing = ! placing ;
136+ IsBeingPlaced = ! IsBeingPlaced ;
102137
103138 // If the user is in placing mode, display the spatial mapping mesh.
104- if ( placing )
139+ if ( IsBeingPlaced )
105140 {
106141 spatialMappingManager . DrawVisualMeshes = true ;
107142
@@ -117,5 +152,22 @@ public void OnInputClicked(InputEventData eventData)
117152 anchorManager . AttachAnchor ( gameObject , SavedAnchorFriendlyName ) ;
118153 }
119154 }
155+
156+ private void DetermineParent ( )
157+ {
158+ if ( ParentGameObjectToPlace == null )
159+ {
160+ if ( gameObject . transform . parent == null )
161+ {
162+ Debug . LogError ( "The selected GameObject has no parent." ) ;
163+ PlaceParentOnTap = false ;
164+ }
165+ else
166+ {
167+ Debug . LogError ( "No parent specified. Using immediate parent instead: " + gameObject . transform . parent . gameObject . name ) ;
168+ ParentGameObjectToPlace = gameObject . transform . parent . gameObject ;
169+ }
170+ }
171+ }
120172 }
121173}
0 commit comments