private void onActionSelected(object value) { var actions = (AIActions)target; Undo.RecordObject(actions, "Edit actions"); if (actions.Actions == null) { actions.Actions = new AIAction[1]; } else { var new_ = new AIAction[actions.Actions.Length + 1]; for (int i = 0; i < new_.Length - 1; i++) { new_[i] = actions.Actions[i]; } actions.Actions = new_; } actions.Actions[actions.Actions.Length - 1] = (AIAction)CreateInstance(((Type)value).FullName); EditorUtility.SetDirty(actions); EditorSceneManager.MarkSceneDirty(UnityEngine.SceneManagement.SceneManager.GetActiveScene()); }
/// <summary> /// Executes the given action targeted at an actor. Does not necessarily have to belong to the Actions list. /// </summary> public void Execute(AIAction action, Actor target) { if (_active != null || action.Wait > float.Epsilon) { return; } if (action.Execute(_actor, target)) { begin(action); } }
/// <summary> /// Executes the given action targeted at a position. Does not necessarily have to belong to the Actions list. /// </summary> public void Execute(AIAction action, Vector3 position) { if (_active != null || action.Wait > float.Epsilon) { return; } if (action.Execute(_actor, position)) { begin(action); } }
/// <summary> /// UI will ask the player to assign the target for the given action. /// </summary> public void GiveCommand(AIAction action) { _forcedAction = action; }
private void Update() { if ((Disabler != null && Disabler.activeSelf) || EventSystem.current.IsPointerOverGameObject()) { hideMarker(); hideOutline(ref _targetOutline); hideSphere(); if (Target == null) { hideOutline(ref _performerOutline); } else { showOutline(ref _performerOutline, Target, SelectColor); } return; } var camera = _camera; if (camera == null) { camera = Camera.main; } if (camera == null) { return; } var mouse = Input.mousePosition; mouse.z = camera.nearClipPlane; var near = camera.ScreenToWorldPoint(mouse); mouse.z = camera.farClipPlane; var far = camera.ScreenToWorldPoint(mouse); var hit = Util.GetClosestNonActorHit(near, far, 1); var targetActor = AIUtil.FindClosestActorIncludingDead(hit, 0.7f); var isMouseDown = Input.GetMouseButtonDown(0); if (Target == null) { if (targetActor != null && targetActor.Side == Side && targetActor.IsAlive) { showOutline(ref _performerOutline, targetActor, PickColor); if (isMouseDown) { Target = targetActor; isMouseDown = false; } } else { hideOutline(ref _performerOutline); } } else if (Target != null) { showOutline(ref _performerOutline, Target, SelectColor); } else { hideOutline(ref _performerOutline); } AIActions targetActions = null; if (Target != null) { targetActions = Target.GetComponent <AIActions>(); } if (targetActions) { var target = hit; AIUtil.GetClosestStandablePosition(ref target); var isActor = targetActor != null; var isSelf = isActor && targetActor == Target; var isAlly = isActor && targetActor.Side == Target.Side; var isEnemy = isActor && targetActor.Side != Target.Side; var isDead = isActor && !targetActor.IsAlive; var isLocation = Vector3.Distance(target, hit) < 0.5f; AIAction action = null; var isTargetingActor = false; if (_forcedAction != null) { if (_forcedAction.CanTargetGround && isLocation) { action = _forcedAction; } else if ((!isDead || !_forcedAction.ShouldIgnoreDead) && ((isSelf && _forcedAction.CanTargetSelf) || (isAlly && _forcedAction.CanTargetAlly) || (isEnemy && _forcedAction.CanTargetEnemy))) { action = _forcedAction; isTargetingActor = true; } } else { for (int i = 0; i < targetActions.Actions.Length; i++) { var a = targetActions.Actions[i]; if (a.CanTargetGround && isLocation) { action = a; break; } else if ((!isDead || !a.ShouldIgnoreDead) && ((isSelf && a.CanTargetSelf) || (isAlly && a.CanTargetAlly) || (isEnemy && a.CanTargetEnemy))) { action = a; isTargetingActor = true; break; } } } if (action != null) { if (isTargetingActor) { if (isSelf) { hideOutline(ref _performerOutline); } showOutline(ref _targetOutline, targetActor, action.UIColor); hideMarker(); hideSphere(); } else { if (action.UIRadius > 0.001f) { showSphere(target, action.UIColor, action.UIRadius); hideOutline(ref _targetOutline); hideMarker(); } else { showMarker(target, action.UIColor); hideOutline(ref _targetOutline); hideSphere(); } } } if (isMouseDown) { isMouseDown = false; if (action != null) { if (action.CanTargetGround) { targetActions.Execute(action, target); } else { targetActions.Execute(action, targetActor); } if (_forcedAction != null) { _forcedAction = null; } } Target = null; } else if (Input.GetMouseButtonDown(1)) { Target = null; } } else { hideOutline(ref _targetOutline); hideMarker(); hideSphere(); } }
private void Update() { if (_autoWait > float.Epsilon) { _autoWait -= Time.deltaTime; } if (_checkWait > float.Epsilon) { _checkWait -= Time.deltaTime; } if (_coverTimer > float.Epsilon) { _coverTimer -= Time.deltaTime; } if (_active != null && (!_active.Update() || (!_active.HasNoTimeout && (Time.timeSinceLevelLoad - _actionStart) > Timeout))) { end(); } if (_actor.Cover == null) { _isInCover = false; _coverTimer = 0; } else if (!_isInCover) { _coverTimer = CoverDelay; _isInCover = true; } if (_active == null && _autoWait <= float.Epsilon && _checkWait <= float.Epsilon && _brain.enabled && _brain.State != FighterState.process && _actor.IsAlive && _coverTimer <= float.Epsilon && (!WaitForCoverActions || !_isTakingCover)) { _checkWait = 0.5f; _nearbyActors.Clear(); { var count = AIUtil.FindActorsIncludingDead(transform.position, AutoDistance); for (int i = 0; i < count; i++) { _nearbyActors.Add(AIUtil.Actors[i]); } } var canUseAttackAction = !AutoAttackOnlyFromCover || _actor.Cover != null; AIAction bestSingleAction = null; Actor bestSingleActionTarget = null; /////////////////////////////////////////////////////// // // CONSIDER MULTIPLE TARGET ACTIONS // /////////////////////////////////////////////////////// AIAction bestMultipleAction = null; int bestMultipleActionTargetCount = 0; for (int i = 0; i < Actions.Length; i++) { var action = Actions[i]; if (action.Wait > float.Epsilon || !action.Auto || action.NeedsSingleTargetActor || action.NeedsTargetLocation || action.NeedsOnlySelf) { continue; } int count = 0; for (int j = 0; j < Actors.Count; j++) { var actor = Actors.Get(j); if (!actor.IsAlive && action.ShouldIgnoreDead) { continue; } if (actor.Side == _actor.Side) { if (((actor == _actor && action.CanTargetSelf) || action.CanTargetAlly) && action.IsNeededFor(actor)) { count++; } } else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor))) { count++; } } if (count > bestMultipleActionTargetCount) { bestMultipleAction = action; bestMultipleActionTargetCount = count; } } if (bestMultipleAction != null) { _autoWait = AutoCooldown; Execute(bestMultipleAction); return; } /////////////////////////////////////////////////////// // // CONSIDER SELF ACTIONS // /////////////////////////////////////////////////////// for (int i = 0; i < Actions.Length; i++) { var action = Actions[i]; if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsOnlySelf) { continue; } if (action.CanTargetSelf && action.IsNeededFor(_actor)) { if (_actor == Priority) { _autoWait = AutoCooldown; Execute(action, _actor); return; } bestSingleAction = action; bestSingleActionTarget = _actor; break; } } /////////////////////////////////////////////////////// // // CONSIDER SINGLE TARGET ACTIONS // /////////////////////////////////////////////////////// for (int i = 0; i < Actions.Length; i++) { var action = Actions[i]; if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsSingleTargetActor) { continue; } Actor best = null; var bestDistance = 0f; var isBestSelf = false; for (int j = 0; j < _nearbyActors.Count; j++) { var actor = _nearbyActors[j]; if (!actor.IsAlive && action.ShouldIgnoreDead) { continue; } if (actor == _actor) { if (action.CanTargetSelf && action.IsNeededFor(actor)) { if (actor == Priority) { _autoWait = AutoCooldown; Execute(action, actor); return; } if (best == null) { best = actor; bestDistance = 0; isBestSelf = true; } } } else if (actor.Side == _actor.Side) { if (action.CanTargetAlly && action.IsNeededFor(actor)) { if (actor == Priority) { _autoWait = AutoCooldown; Execute(action, actor); return; } var distance = Vector3.Distance(transform.position, actor.transform.position); if (best == null || isBestSelf || distance < bestDistance) { best = actor; bestDistance = distance; isBestSelf = false; } } } else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor))) { if (actor == Priority) { _autoWait = AutoCooldown; Execute(action, actor); return; } var distance = Vector3.Distance(transform.position, actor.transform.position); if (best == null || isBestSelf || distance < bestDistance) { best = actor; bestDistance = distance; isBestSelf = false; } } } if (best != null) { bestSingleAction = action; bestSingleActionTarget = best; break; } } /////////////////////////////////////////////////////// // // CONSIDER AREA ACTIONS // /////////////////////////////////////////////////////// for (int i = 0; i < Actions.Length; i++) { var action = Actions[i]; if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsTargetLocation) { continue; } _possibleActionTargets.Clear(); for (int j = 0; j < _nearbyActors.Count; j++) { var actor = _nearbyActors[j]; if (!actor.IsAlive && action.ShouldIgnoreDead) { continue; } if (actor == _actor) { if (action.CanTargetSelf && action.IsNeededFor(actor)) { _possibleActionTargets.Add(actor); } } else if (actor.Side == _actor.Side) { if (action.CanTargetAlly && action.IsNeededFor(actor)) { _possibleActionTargets.Add(actor); } } else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor)) { _possibleActionTargets.Add(actor); } } if (_possibleActionTargets.Count == 0 || (_possibleActionTargets.Count == 1 && bestSingleAction != null)) { continue; } if (action.UIRadius > float.Epsilon) { var radius = action.UIRadius; var steps = (int)(2 * AutoDistance / radius); var hasBest = false; var bestPosition = Vector3.zero; var bestDistance = 0f; var bestActorCount = 0; var bestHasPriority = false; for (int x = -steps / 2; x < steps / 2; x++) { for (int y = -steps / 2; y < steps / 2; y++) { var position = transform.position + new Vector3(x * action.UIRadius, 0, y * radius); var distance = Vector3.Distance(position, transform.position); if (distance > AutoDistance) { continue; } if (AutoAttackOnlyFromCover && action.CanTargetEnemy && action.WillMoveForPosition(position)) { continue; } var actorCount = 0; var hasPriority = false; for (int j = 0; j < _possibleActionTargets.Count; j++) { var a = _possibleActionTargets[j]; if (Vector3.Distance(position, a.transform.position) < radius) { actorCount++; if (a == Priority) { hasPriority = true; } } } if (actorCount > 0) { var isBetter = false; if (!hasBest) { isBetter = true; } else if (hasPriority && !bestHasPriority) { isBetter = false; } else if (!bestHasPriority) { if (actorCount > bestActorCount) { isBetter = true; } else if (actorCount == bestActorCount) { isBetter = distance < bestDistance; } } if (isBetter) { hasBest = true; bestPosition = position; bestDistance = distance; bestHasPriority = hasPriority; bestActorCount = actorCount; } } } } if (hasBest && (bestSingleAction == null || bestActorCount > 1)) { _autoWait = AutoCooldown; Execute(action, bestPosition); return; } } } /////////////////////////////////////////////////////// // // EXECUTE BEST SINGLE IF NO AREA POSSIBLE // /////////////////////////////////////////////////////// if (bestSingleAction != null) { _autoWait = AutoCooldown; Execute(bestSingleAction, bestSingleActionTarget); } /////////////////////////////////////////////////////// // // CONSIDER NON-TARGET ACTIONS // /////////////////////////////////////////////////////// for (int i = 0; i < Actions.Length; i++) { var action = Actions[i]; if (action.Wait > float.Epsilon || !action.Auto || action.CanTargetAny || action.CanTargetGround || action.UIRadius > float.Epsilon || action.CanTargetMultiple || action.NeedsOnlySelf) { continue; } _autoWait = AutoCooldown; Execute(action); return; } } }
private void end() { Message("ToExitProcessAndMaintainPosition"); _active.Stop(); _active = null; }
private void begin(AIAction command) { _actionStart = Time.timeSinceLevelLoad; _active = command; Message("ToEnterProcess", false); }