bool WarnCollision(NavMeshAgentWrapper navigator, RaycastHit hit){ // someone is coming //Debug.Log (name+" got warning from "+navigator.name); if (!isNavigating && !holdPosition && !lockPosition && GetComponent<TaskCharacter>().executingScript == null){// && priority > navigator.priority){ //if we are less important than the mover // don't let a character move out of the way if they are still animating // moved this inside so we only test if the other checks said it was okay. if ( GetComponent<AnimationManager>().CanWalk() == false ) //this only tests CharacterAnimState==Idle { UnityEngine.Debug.LogError ("NavMeshAgentWrapper.WarnCollision(" + this.name + ") : can't move out of the way, still animating!"); return false; } // what if we just move forward or back one radius ? Vector3 dir = hit.point - transform.position; dir.y=0; moveStartTime = Time.time; avoidCount = 0; FreeMe(); destPos = transform.position - dir.normalized*m_navMeshAgent.radius*1.5f; finalDestination = destPos; hasFinalRotation = false; // can we give a final rotation facing the patient ? hasFinalRotation = true; Vector3 rotationVector = GameObject.Find("lookPatient").transform.position-destPos; rotationVector.y = 0; finalRotation = Quaternion.LookRotation(rotationVector); GetComponent<AnimationManager>().Walk(0.25f); GetComponent<TaskCharacter>().IsInPosition(""); // clears atNode so we have to nav back m_navMeshAgent.SetDestination(destPos); makingWayFor = navigator; #if DEBUG_NAVIGATION Debug.Log (name+" Moving to avoid "+navigator.name+" hold="+holdPosition); #endif // blending forward/back with hit direction. // if (Vector3.Dot(dir,transform.forward) > 0) // m_navMeshAgent.SetDestination(transform.position - transform.forward*m_navMeshAgent.radius); // else // m_navMeshAgent.SetDestination(transform.position + transform.forward*m_navMeshAgent.radius); navRequested = true; isNavigating = false; return true; } else{ if (makingWayFor == navigator) return true; // i am already stepping out of your way. else{ //Debug.Log (name+" won't move to make way for "+navigator.name); return false; // cant help you, i am busy. } } }
void Update () { avoidTime -= Time.deltaTime; if (navRequested) { if (m_navMeshAgent == null){ Debug.LogWarning (name+" lost agent while navRequested."); m_navMeshAgent = RecreateAgent(); lastAvoidCheckTime = 0; // cause us to take the timeout exit path to our destination } if (m_navMeshAgent.hasPath) { navRequested = false; isNavigating = true; // if (!CheckForAvoidance()) // this will check every frame while needed lastAvoidCheckTime = Time.time; } else if (Time.time - lastAvoidCheckTime > avoidCheckInterval) { // failed to path in time, return failure //Debug.LogWarning(name+" NavMeshAgent failed to find initial path fast enough. Warping!"); SendMessageUpwards("OnNavigationRequestFailed",SendMessageOptions.DontRequireReceiver); navRequested = false; m_navMeshAgent.Stop(); // GetComponent<AnimationManager>().StopWalk(0.5f); m_navMeshAgent.updateRotation = false; // apparently this is needed to keep the positino and ritation from being updated // new code here: 4/2/13 PAA // this works well, but we have to be careful that the destination is a good one. // people were sinking down to avoid positions... // it didn't solve the very short distance navigation problem, though. isNavigating = true; failsafeSlider = 1.0f; // lerp to the failed point... moveStartTime = Time.time-moveTimeout-1.0f; // ensure that the lerp starts now. // somehow, final destination can end up below the floor, so we are correcting for that here. // finalDestination.y = transform.position.y; // don't lerp vertically } } if (isNavigating) { if (failsafeSlider <= 0 && Time.time - moveStartTime > moveTimeout) failsafeSlider = 1.0f; if (failsafeSlider > 0){ // we have run into trouble so just lerp to the final destination // Debug.LogWarning(name+" navigation failed to complete, Warping!"); isAvoiding = false; // we should turn off the collider at this point to avoid pushing anybody aside! if (collider != null) collider.isTrigger = true; // this didn't work, check on the nav mesh agent and capsule collider if (m_navMeshAgent != null){ //m_navMeshAgent.SetDestination(finalDestination); // let the final lerp do the node alignment // There is an unfortunate characteristic of the Unity NavMeshAgent, that when you take over // moving the object like this, the agent retains it's last position, and the next time // you let the agent drive, it snaps back to that spot. // The only way I found to get around this is to Destroy then Recreate the agent! m_navMeshAgent.Stop(true); m_navMeshAgent.ResetPath(); Object.Destroy(m_navMeshAgent); m_navMeshAgent = null; } // m_navMeshAgent.Stop(true); // let the final lerp do the node alignment // m_navMeshAgent.updateRotation = false; // m_navMeshAgent.updatePosition = false; transform.position = Vector3.Lerp(transform.position,finalDestination,1.0f-failsafeSlider); failsafeSlider -= Time.deltaTime/2.0f; // this gives us a 2 second lerp. if (failsafeSlider < 0.5f) GetComponent<AnimationManager>().StopWalk(0.25f); // start blending out the walk... if (failsafeSlider <= 0 && Time.time - moveStartTime > moveTimeout){ transform.position = finalDestination; if (m_navMeshAgent == null) RecreateAgent (); isNavigating = false; failsafeSlider = 0; if (collider != null) collider.isTrigger = false; LockMe (); makingWayFor = null; // if i was getting out of someone's way, i have done that now. SendMessageUpwards("OnNavigationRequestSucceeded",SendMessageOptions.DontRequireReceiver); // should really wait for alignment to complete for this GetComponent<TaskCharacter>().Arrive(); GetComponent<AnimationManager>().StopWalk(0.25f); // this would be better moved to TaskCharacter.Arrive() } return; } distance = m_navMeshAgent.remainingDistance; if (!isAvoiding){ // blend to normal speed if not avoiding /* if (m_navMeshAgent.speed < defaultSpeed) m_navMeshAgent.speed = m_navMeshAgent.speed*1.1f; else m_navMeshAgent.speed = defaultSpeed; */ // lets start the alignment a bit earlier if ( hasFinalRotation && distance < 3.0f*m_navMeshAgent.radius){ m_navMeshAgent.updateRotation = false; // if we were walking backwards, transfer the heading rotation up to the parent and let the lerp to // final rotation do the final alignment if (heading != 0 && headingTransform != null){ // fool the nav mesh agent into walking backwards by setting a rotation and counter rotation // on the two top hierarchy nodes foreach (GameObject go in reattachedObjects){ go.transform.parent = null; } transform.rotation *= Quaternion.AngleAxis(-heading,Vector3.up); headingTransform.localRotation = Quaternion.identity; heading = 0; foreach (GameObject go in reattachedObjects){ go.transform.parent = transform; } reattachedObjects.Clear(); } if (lerpFromRotation == Quaternion.identity) lerpFromRotation = transform.rotation; float denominator = 3.0f*m_navMeshAgent.radius; float numerator = denominator - distance; float lrp = 0.75f*numerator/denominator;// (3.0f*m_navMeshAgent.radius - distance) / 3.0f*m_navMeshAgent.radius; // technically, this kind of lerp should retain the starting value instead of // using the current value, as this leads to a non-linear interpolation, but this is easier to code Quaternion desiredRotation = Quaternion.Lerp(lerpFromRotation,finalRotation,lrp); // if the angle is too great, limit rotation and hold 'distance' above threshold until rotation can complete to avoid snapping on short trips float remainingAngle; Vector3 rotAxis; Quaternion delta = Quaternion.Inverse(transform.rotation) * desiredRotation; delta.ToAngleAxis(out remainingAngle,out rotAxis); float maxSlew = 3.0f*(Time.timeScale+.01f); if (remainingAngle > maxSlew){ delta = Quaternion.AngleAxis(maxSlew,rotAxis); transform.rotation = transform.rotation * delta; if (distance < 0.01f) distance = 0.011f; // so we don't trigger arrival yet... } else { transform.rotation = Quaternion.Lerp(lerpFromRotation,finalRotation,lrp); } } if (distance < 0.01f) // was 0.01f, but having occasional race conditions { transform.position = m_navMeshAgent.destination; // snap to final lerpFromRotation = Quaternion.identity; m_navMeshAgent.Stop(); // let the final lerp do the node alignment m_navMeshAgent.updateRotation = false; // apparently this is needed to keep the position and rotation from being updated. = false; isNavigating = false; makingWayFor = null; // if i was getting out of someone's way, i have done that now. if ((m_navMeshAgent.pathStatus != NavMeshPathStatus.PathComplete)) { SendMessageUpwards("OnNavigationRequestFailed",SendMessageOptions.DontRequireReceiver); // should really wait for slignment to complete for this } else { SendMessageUpwards("OnNavigationRequestSucceeded",SendMessageOptions.DontRequireReceiver); // should really wait for alignment to complete for this } LockMe (); // may destroy the agent #if DEBUG_NAVIGATION UnityEngine.Debug.Log ("NavMeshAgent "+name+" Arrived at "+TargetName); #endif GetComponent<TaskCharacter>().Arrive(); GetComponent<AnimationManager>().StopWalk(0.5f); // this would be better moved to TaskCharacter.Arrive() } // see if anyone is in our path if (Time.time - lastAvoidCheckTime > avoidCheckInterval) { if (!CheckForAvoidance()) // this will check every frame while needed lastAvoidCheckTime = Time.time; } } else { // is Avoiding, repath when one radius from goal to avoid slowdown ? if (distance < m_navMeshAgent.radius*1.0f) { m_navMeshAgent.SetDestination(finalDestination); isNavigating = false; isAvoiding = false; navRequested = true; return; } else { // see if anyone ELSE is in our path if (Time.time - lastAvoidCheckTime > avoidCheckInterval) { if (!CheckForAvoidance()) // lastAvoidCheckTime = Time.time; } } } } else { isAvoiding = false; } }
public void Execute(InteractionScript callingScript){ //Debug.Log ("XXX"+Time.time+" "+name+type); if ((breakpoint || callingScript.singleStepping) && callingScript.debug){ // place a breakpoint here and set breakpoint=true to trap on execute of a particular line of script Debug.Log ("Hit Execute Breakpoint for "+name+" of "+callingScript.name); InteractionScript.atBreakpoint = callingScript; callingScript.waitingForDebugger = true; Debug.Break (); WaitForDebugger (callingScript); Debug.Log ("Ran Right Past the Call"); } executedBy = callingScript; /* moved to Calling script to handle Role mapping * if (objectToAffect == null){ // default, or we could try looking up the name again... if (objectName != ""){ objectToAffect = GameObject.Find(executedBy.ResolveArgs(objectName).Replace ("\"","")); // we have a problem with two names here, one used by unity, one by the if (objectToAffect == null){ objectToAffect = ObjectManager.GetInstance().GetGameObject(objectName); } } else objectToAffect = executedBy.myObject; } */ if (executedBy != null) objectToAffect = executedBy.FindObjectToAffect(this); if (type != actionType.putMessage && objectToAffect != null) // don't need a taskCharacter to send a message... taskChar = objectToAffect.GetComponent<TaskCharacter>(); if (!forceExecute){ if (taskChar != null && taskChar.executingScript != null && taskChar.executingScript != this){ // this character is already busy, so wait until the current line completes StartCoroutine (ExecuteWhenIdle(callingScript)); return; } if (taskChar != null){ taskChar.executingScript = this; if (taskChar.actingInScript != null && taskChar.actingInScript != executedBy){// && CanCompleteImmediately()){ // don't add me, I'll be done before you know it... } else { taskChar.actingInScript = executedBy; // this could get cleared by this character doing an executeScript. // since we set it, be sure we're in the list of actor objects so we'll be released if (!executedBy.actorObjects.Contains(taskChar as ObjectInteraction)) executedBy.actorObjects.Add (taskChar as ObjectInteraction); } } } forceExecute = false; #if DEBUG_SCRIPTING Debug.Log ("ScriptedAction execute "+name); #endif if (breakpoint && callingScript.debug){ // place a breakpoint here and set breakpoint=true to trap on execute of a particular line of script Debug.Log ("Hit Execute Breakpoint for "+name+" of "+callingScript.name); } if (hasExecuted && executeOnlyOnce){ error = "already executed"; OnComplete(); } characterTaskPending = false; waitingForUpdate = false; // a single update call will complete us waitingForDialog = false; taskReady = false; waitingForNav = false; waitingForCondition = false; ignoreTimeout = false; waitingForAnim = false; runIndependentUpdates = false; trackCameraLookat = false; postureChangeStartTime = 0; executedBy = callingScript; error = ""; this.enabled = true; // need updates until we are through // Temporary hack to add any InteractMessage map to the character to avoid an error if (objectToAffect != null && type == actionType.putMessage && gameMsgForm.msgType == GameMsgForm.eMsgType.interactMsg){ // we are going to add this interaction to the objects AllMaps so it doesn't get an error ObjectInteraction OI = objectToAffect.GetComponent<ObjectInteraction>(); if (OI != null) OI.AddToAllMaps(gameMsgForm.map.GetMap()); } if (preAttributes != "") SetAttributes(objectToAffect,preAttributes); // can't do this here, need to do it when we use the values, and don't overwrite the original ones! // stringParam = SubstituteArgsAndAttributes(stringParam); // update parameter strings with current #args, $attrs // stringParam2 = SubstituteArgsAndAttributes(stringParam2); // stringParam3 = SubstituteArgsAndAttributes(stringParam3); // stringParam4 = SubstituteArgsAndAttributes(stringParam4); // attachmentOverride = SubstituteArgsAndAttributes(attachmentOverride); if (type == actionType.enableInteraction){ if (objectName == "Dispatcher"){ // this will cause all interaction tags except the space delimited list to be rejected // until an interaction on the list is hit, which then re-enables all interactions. // (needed so scripts can use tags to trigger things when running) // an empty list will allow all interactions again. Dispatcher td = FindObjectOfType<Dispatcher>(); if (td != null){ td.LimitInteractions( stringParam, negate, loop ); } OnComplete(); Cleanup (); } else { // look for an ObjectInteraction component on ObjectToAffect if (objectToAffect != null){ if (objectToAffect.GetComponent<ObjectInteraction>() != null){ ObjectInteraction OI = objectToAffect.GetComponent<ObjectInteraction>(); OI.Enabled = !negate; if (ease || texture2D!= null){ //hackfully abuse the 'ease' boolean to force clear the icon texture if (ease) OI.iconTexture = null; else if (texture2D!= null) OI.iconTexture = texture2D; } } else // adding handling of nav mesh obstacle here... if (objectToAffect.GetComponent<NavMeshObstacle>() != null){ NavMeshObstacle NMO = objectToAffect.GetComponent<NavMeshObstacle>(); NMO.enabled = !negate; } OnComplete(); Cleanup (); } else { error = "no objectInteraction to enable"; OnComplete(); Cleanup (); } } } if (type == actionType.playAnimation){ if (objectToAffect != null){ taskChar = objectToAffect.GetComponent<TaskCharacter>(); if (taskChar != null){ taskChar.Animate(stringParam); // figure out if we should wait... we could wait for the characterAnimState if (waitForCompletion){ waitingForAnim = true; animEndTime = -1; // failsafe for hung waiting for anim to end... AnimationState ast = taskChar.GetComponent<AnimationManager>().body.animation[stringParam]; if (ast != null && ast.clip != null) animEndTime = Time.time + ast.clip.length + 0.05f;; } else OnComplete (); } else { // handle ?speed= ?time= ?wieght= string[] p = stringParam.Split ('?'); string animationName = p[0]; float animSpeed = 1; // for overrideing defaults float animWeight = 1; float animTime = 0; int start=1; // process speed= weight= time= possibly mixing transform... while (start < p.Length){ if (p.Length > start && p[start].ToLower().Contains("speed=")){ string[] q = p[start].Split('='); float.TryParse(q[1],out animSpeed); } if (p.Length > start && p[start].ToLower().Contains("weight=")){ string[] q = p[start].Split('='); float.TryParse(q[1],out animWeight); } if (p.Length > start && p[start].ToLower().Contains("time=")){ string[] q = p[start].Split('='); float.TryParse(q[1],out animTime); } start++; } if (objectToAffect.animation != null){ if (animTime == 0) objectToAffect.animation.Rewind(animationName); if (animTime > 0) objectToAffect.animation[animationName].time = animTime; objectToAffect.animation[animationName].speed = animSpeed; objectToAffect.animation[animationName].weight = animWeight; objectToAffect.animation.clip = objectToAffect.animation[animationName].clip; objectToAffect.animation.Play(); if (waitForCompletion) waitingForAnim = true; else OnComplete (); } } } else { error = "no object to play animation on"; OnComplete(); Cleanup (); } } if (type == actionType.playAudio){ // object to affect should have an audio source AudioSource src = null; if (objectToAffect != null) src = objectToAffect.GetComponent<AudioSource>(); if (src == null) src = objectToAffect.AddComponent<AudioSource>() as AudioSource; if (src != null){ float timeToWait = fadeLength; if (audioClip == null){ // find the audio clip, looking thru the sound map for this character? if (stringParam != ""){ VoiceMap vm = VoiceMgr.GetInstance().Find(objectToAffect.name, stringParam); if (vm != null){ vm.Clip = SoundMgr.GetInstance().GetClip(vm.Audio); if (vm.Clip != null) timeToWait += vm.Clip.length; VoiceMgr.GetInstance().Play (objectToAffect.name, stringParam); if (stringParam2 != "" && taskChar != null && vm.Clip != null) taskChar.LookAt(stringParam2, Time.time + vm.Clip.length); } else{ audioClip = SoundMgr.GetInstance().Get(stringParam); } } } if (audioClip != null){ // will still be null if we sent this to the voice manager src.clip = audioClip; src.Play(); timeToWait += audioClip.length; if (stringParam2 != "" && taskChar != null) taskChar.LookAt(stringParam2, Time.time + audioClip.length); } if (waitForCompletion) StartCoroutine(CompleteAfterDelay (timeToWait)); else { OnComplete(); Cleanup (); } } else { error = "no audiosource for playAudio"; OnComplete(); } } if (type == actionType.putMessage){ // hack to avoid 'I'm too busy messages... if (taskChar != null) taskChar.executingScript = null; StartCoroutine(SendMessageAfterDelay(fadeLength)); } if (type == actionType.move){ // // lets handle the camera move first: if (moveTo == null){ // translate the name, if presesnt if (moveToName != "" && GameObject.Find(moveToName)!= null ){ moveTo = GameObject.Find(moveToName).transform; } } CameraLERP cameraLERP = objectToAffect.GetComponent<CameraLERP>(); if (cameraLERP != null){ // strangely in Unity, we're not allowed to create new Transforms, so we have to make a dummy if (moveTo != null){ if (offset == Vector3.zero){ // assume this is a return to the spline // reset the camera rail controller so we go to the starting position... // CameraRailCoordinator crc = FindObjectOfType<CameraRailCoordinator>(); // if (crc != null) // crc.Reset(); // cameraLERP.MoveTo(moveTo, fadeLength,true,false, 0); trackCameraLookat = true; if (!waitForCompletion) runIndependentUpdates = true; StartCoroutine( EndTrackCameraLookat(fadeLength)); if (!waitForCompletion) OnComplete (); return; } else { dummyGO = new GameObject("dummyGO"); dummyGO.transform.position = moveTo.position + offset.x*dummyGO.transform.forward + offset.y*dummyGO.transform.up + offset.z*dummyGO.transform.right; dummyGO.transform.LookAt(moveTo); cameraLERP.MoveTo(dummyGO.transform, fadeLength,true,true, 0); } } else { if (fadeLength <= 0) cameraLERP.Return(); // snap back else { GameObject dummyGO = new GameObject("dummyGO"); dummyGO.transform.position = cameraLERP.oldWorldPos; dummyGO.transform.rotation = cameraLERP.oldWorldRot; cameraLERP.MoveTo(dummyGO.transform, fadeLength,true,false, 0); } } //Destroy (dummyGO); destroy this later on Completed if (waitForCompletion && fadeLength > 0) StartCoroutine(CompleteAfterDelay (fadeLength)); else { OnComplete(); //Cleanup (); } } else { // if the moveTo NAME is a valid Node Name, we can use the TaskCharacter to move there taskChar = objectToAffect.GetComponent<TaskCharacter>(); if (taskChar != null){ // bool bResult = taskChar.IsInPosition (moveTo.name); // this should start off the nav // lets see if we have something with a NavMeshAgentWrapper... // navWrapper = objectToAffect.GetComponent<NavMeshAgentWrapper>(); // if (navWrapper != null){ // lets ignore the offset for now... // navWrapper.MoveToGameObject(moveTo.gameObject,2.0f); if (waitForCompletion){ navStartTime = Time.realtimeSinceStartup; // we may want to time out waitingForNav = true; return; } else{ runIndependentUpdates = true; pingTaskCharacter = true; OnComplete(); } // } } else { error = "move only implemented for camera, no cameraLERP found"; OnComplete(); } } } if (type == actionType.fade){ // if (objectToAffect == null){ Debug.LogWarning("Null object "+objectName+" for fade by "+name); OnComplete(); Cleanup(); return; } // if the thing is a the GUIManager then fade it GUIManager gm = objectToAffect.GetComponent<GUIManager>(); // test it if (gm != null) { gm.SetFadeCurtain(desiredColor.a, fadeLength); OnComplete(); Cleanup (); return; } // we need to have an object with a renderer. if (objectToAffect != null && objectToAffect.renderer != null){ // if string param has something, look for a resource by that name that is a mesh or material to swap in Material newMaterial = null; // Mesh newMesh = null; if (stringParam != ""){ newMaterial = Resources.Load(stringParam) as Material; // newMesh = Resources.Load(stringParam) as Mesh; } // fade can be an instant change, or take some time. // desired color should override desired alpha if (stringParam=="current"){ // should check new material and use it's color if provided desiredColor = objectToAffect.renderer.material.color; desiredColor.a = desiredAlpha; } desiredColor.a = desiredAlpha; if (fadeLength > 0){ // get components // if the thing has a color changer, lets make use of that. ColorChanger cc = objectToAffect.GetComponent<ColorChanger>(); if (cc != null){ cc.ChangeColor(desiredColor, fadeLength); } else { // fadeBeginTime = Time.time; // fadeBeginColor = objectToAffect.renderer.material.color; if (desiredAlpha > 0){ objectToAffect.renderer.enabled = true; // temporarily just jam the final result until the fade interpolate is in place objectToAffect.renderer.material.color = desiredColor; } // if the final alpha is zero, then set the alpha, and turn off the renderer else { objectToAffect.renderer.enabled = false; objectToAffect.renderer.material.color = desiredColor; } } } else { // instant fade if (newMaterial != null) renderer.material = newMaterial; // if final alpha is > 0, turn the renderer on and set the alpha if (desiredAlpha > 0){ objectToAffect.renderer.enabled = true; objectToAffect.renderer.material.color = desiredColor; } // if the final alpha is zero, then set the alpha, and turn off the renderer else { objectToAffect.renderer.enabled = false; objectToAffect.renderer.material.color = desiredColor; } } } else { // missing object or renderer error = "Fade has no object with renderer specified"; } OnComplete(); Cleanup (); } if (type == actionType.ifThenElse){ // BaseObject bob = null; if (objectToAffect != null && objectToAffect.GetComponent<BaseObject>() != null) bob = objectToAffect.GetComponent<BaseObject>(); if (bob != null){ // build a binaryExpressionNode out of the string for our testEntity and evaluate. // perform any arg substitutions string newString = executedBy.ResolveArgs(stringParam); BinaryExpressionNode condition = BinaryExpressionNode.BuildTree(newString); if (condition.Evaluate(bob)) executedBy.nextLineLabel = ""; // just go on to the next statement else executedBy.nextLineLabel = "else"; // this will find either the next 'else' block or the next 'endIfThenElse' block } else { error = "no baseObject for ifThenElse to test"; } // executedBy.nestingDepth += 1; OnComplete(); Cleanup (); } if (type == actionType.executeScript){ // our execution will be stacked and we will pend until this script completes if (scriptToExecute == null && stringParam2 != null && stringParam2 != ""){ // First, look for a script on the character running this interaction if (taskChar != null){ ScriptedObject tcso = taskChar.GetComponent<ScriptedObject>(); if (tcso!=null){ foreach (InteractionScript tcis in tcso.scripts){ if (tcis.name == stringParam2){ scriptToExecute = tcis; break; } } } } if (scriptToExecute == null){ // try finding the named game object and look for an interaction script there GameObject isGO = GameObject.Find(stringParam2); if (isGO != null) scriptToExecute = isGO.GetComponent<InteractionScript>(); } } if (scriptToExecute == null){ Debug.LogError("scriptedAction could not find script to execute at "+name+executedBy.name); OnComplete (); Cleanup (); } if (waitForCompletion){ // run this as a subroutine, continuing when it's done //build a string with our script's args and add to stringParam args... if (taskChar != null) taskChar.executingScript = null; // need to clear this for the next scrip executedBy.ExecuteScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease); // yield until we get an update. which will complete us. we HAVE to wait, no multi threading support yet. waitingForUpdate = true; } else { // don't wait for completion, so we will JUMP and not return to this line if (taskChar != null) taskChar.executingScript = null; // need to clear this for the next scrip executedBy.QueueScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease); // yield until we get an update. which will complete us. we HAVE to wait, no multi threading support yet. executedBy.nextLineLabel = "abort"; // terminate this script error="abort"; OnComplete(); Cleanup (); } } if (type == actionType.queueScript){ // no script and loop set means flush all scripts from the queue if (scriptToExecute == null && loop && (stringParam2 == null || stringParam2 == "")){ // remove all scripts that are not currently on the stack from the queue executedBy.caller.FlushScriptQueue(); OnComplete(); Cleanup (); return; } if (scriptToExecute == null && stringParam2 != null && stringParam2 != ""){ // try finding the named game object and look for an interaction script there GameObject isGO = GameObject.Find(stringParam2); if (isGO != null) scriptToExecute = isGO.GetComponent<InteractionScript>(); } if (scriptToExecute != null) executedBy.QueueScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease); else Debug.LogError("FAILED TO FIND script named \""+stringParam2+"\""); OnComplete(); Cleanup (); return; } if (type == actionType.wait){ // we ignore wait for completion on this one... // set the HoldPosition flag if requested if (loop){ NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>(); if (w != null) w.HoldPosition(true); // if there is no condition, holdPosition will stick till the next character task } // specifying wait 0 and delay = #delay lets you pass a delay into the script. if (fadeLength==0 && stringParam.ToLower().Contains("delay=")){ string delayString = SubstituteArgsAndAttributes(stringParam); if (!float.TryParse(delayString.Replace("delay=",""),out fadeLength)){ Debug.LogWarning("bad delay time in scripted action "+ name + stringParam); OnComplete(); Cleanup (); } else { StartCoroutine(CompleteAfterDelay (fadeLength)); return; } } // let's see about waiting for a TAG:NAME if (stringParam.Contains(":") && !stringParam.Contains ("=")){ // this could be better at excluding other things that contain ":" // assume this thing is a tag, and post a listener //GUIManager.GetInstance().AddInteractCallback(null,myInteractCallback); Brain.GetInstance().AddCallback(myInteractCallback); // fadelength should be a timeout here if > 0 if (fadeLength > 0) StartCoroutine(CompleteAfterDelay (fadeLength)); } else { if (stringParam == "" || stringParam == null){ StartCoroutine(CompleteAfterDelay (fadeLength)); } else { waitingForCondition = true; conditionNode = BinaryExpressionNode.BuildTree(stringParam); if (fadeLength > 0) StartCoroutine(CompleteAfterDelay (fadeLength)); // this starts a timeout } } } if (type == actionType.characterTask){ // taskChar = objectToAffect.GetComponent<TaskCharacter>(); nmaWrapper = objectToAffect.GetComponent<NavMeshAgentWrapper>(); if (taskChar != null){ taskChar.Init(); // clears flags taskChar.executingScript = this; // restore this flag // overload 'ease' for random pathnode/animation if (moveToName.ToLower()=="random"){ ease=true; moveToName = SceneNode.GetRandomUnlockedNode().name; // this could return a null, BOOM! } else { ease=false; } StartCoroutine(CharacterTaskAfterDelay(fadeLength)); if (!waitForCompletion){ runIndependentUpdates = true; OnComplete (); } } } if (type == actionType.attach){ // TaskCharacter tc = objectToAffect.GetComponent<TaskCharacter>(); if (negate){ // this is a detach, which leaves the object loose at the top level of the hierarchy. if (tc != null){ tc.Detach(SubstituteArgsAndAttributes(attachmentOverride)); } } else { // this is an attach, and it's usually better to attach to a new parent than to just detach. bool attachingToTcBone = true; if (tc != null){ // if there's an attachment override, and you can find the object and a bone, // then place the object at the bone plus offset location string substituted = attachmentOverride; if (attachmentOverride != "" && attachmentOverride.Contains(" ")){ string[]p = attachmentOverride.Split (' '); GameObject targetObject = GameObject.Find (SubstituteArgsAndAttributes(p[0]).Replace ("\"","")); Transform parentBone = tc.GetComponent<AnimationManager>().GetBone(p[1].Replace ("\"","")); attachingToTcBone = (parentBone != null); if (targetObject == null){ Debug.LogError(executedBy.name+": "+name+" Script Attachment found no target object in "+attachmentOverride); OnComplete(); Cleanup (); return; } if (!attachingToTcBone){ // name is not a bone, see if there's a game object by this name GameObject parentObject = GameObject.Find (SubstituteArgsAndAttributes(p[1]).Replace ("\"","")); if (parentObject != null) parentBone = parentObject.transform; tc.Detach(targetObject.name); // remove this from the attached Objects list... } substituted = targetObject.name+" "+p[1].Replace ("\"",""); if (offset != new Vector3(-1,-1,-1)){ if (targetObject != null && parentBone != null){ // if there's a delay, then we can do the lerp in a co-routine if (fadeLength > 0){ StartCoroutine (AttachAfterDelay(targetObject,parentBone,tc,substituted,attachingToTcBone)); return; // don't cleanup or complete until after delayed lerp } else { targetObject.transform.position = parentBone.TransformPoint(offset);//position+offset; targetObject.transform.rotation = parentBone.rotation*Quaternion.Euler(orientation); if (!attachingToTcBone) targetObject.transform.parent = parentBone; } } } else { // performing attach using current position if (!attachingToTcBone) targetObject.transform.parent = parentBone; } } if (attachingToTcBone) tc.Attach(substituted); } } OnComplete(); Cleanup (); } if (type == actionType.spawn){ GameObject newObject = Instantiate(Resources.Load(stringParam), objectToAffect.transform.position, objectToAffect.transform.rotation) as GameObject; newObject.name = SubstituteArgsAndAttributes(stringParam2); if (stringParam3 != ""){ GameObject newParent = GameObject.Find (stringParam3); if (newParent != null){ newObject.transform.parent = newParent.transform; newObject.transform.localPosition = offset; } } executedBy.args["spawnedname"]=newObject.name; OnComplete(); Cleanup (); } if (type == actionType.destroy){ Destroy(objectToAffect); OnComplete(); Cleanup (); } if (type == actionType.unityMessage){ // if (objectToAffect != null) objectToAffect.SendMessage(stringParam,stringParam2); OnComplete(); Cleanup (); } if (type == actionType.lockPosition){ if (negate){ NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>(); if (w != null) w.LockPosition(false); ScriptedObject so = objectToAffect.GetComponent<ScriptedObject>(); if (so != null) so.executePriorityLock = -1; } else { NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>(); if (w != null) w.LockPosition(true); if (stringParam != ""){ int lockPriority; if (int.TryParse(stringParam,out lockPriority)){ ScriptedObject so = objectToAffect.GetComponent<ScriptedObject>(); if (so != null) so.executePriorityLock = lockPriority; } } // test unlocking any nodes we have locked, so they are not blocking. // this is specifically for BVM, but might be good overall. SceneNode.UnlockLocation(objectToAffect.transform.position,0.5f); // radius is completely arbitrary 0.44f is probably a good value. } OnComplete(); Cleanup (); } if (type == actionType.goToLine){ // executedBy.nextLineLabel = stringParam; // untested, and very scary OnComplete(); Cleanup (); } if (type == actionType.setIKTarget){ // TaskCharacter tc = objectToAffect.GetComponent<TaskCharacter>(); if (tc != null){ IKArmController ctlr = tc.IKArmRight; if (stringParam.ToLower().Contains ("left")) ctlr = tc.IKArmLeft; if ((moveToName == null) || moveToName == ""){ // we are clearing the target ctlr.target = null; } else { GameObject targetGo = GameObject.Find(moveToName); if (targetGo != null){ ctlr.target = targetGo.transform; HandPoser poser = targetGo.GetComponent<HandPoser>(); if (poser != null) poser.Setup(ctlr.hand); } } ctlr.blendTime = fadeLength; ctlr.offset = offset; ctlr.orientation = Quaternion.Euler(orientation); if (stringParam2 == null || stringParam2 == "") stringParam2 = "0"; float releaseTime = 0; float.TryParse(stringParam2, out releaseTime); ctlr.releaseTime = releaseTime; } OnComplete(); // we'll worry about wait for completion later TODO Cleanup (); } }