int EntityHealthLimit = 100; // Health limits for each entity public Game(PictureBox field, Size entitySize, MindState mindState, int spawnLimit) { width = field.Width; height = field.Height; this.entitySize = entitySize; this.mindState = mindState; this.entityesLimits = spawnLimit; state = GameState.doesntInit; }
private void Sleep() { if (this.state == MindState.Asleep) return; if (this.state == MindState.FallingAsleep) return; this.state = MindState.FallingAsleep; this.eyeOpenTarget = 0.0f; this.eyeBlinking = false; this.eyeSpeed = Time.SPFMult / MathF.Rnd.NextFloat(1.5f, 3.5f); this.DeactivateSpikes(); }
private void StartMind(MindState state) { var ctx = state.Context; var go = state.Component.gameObject; ctx.Status = BehaviorContextStatus.None; ctx.SetItem("BehaviorFile", state.Component.BehaviorFile); ctx.SetItem("GameObjectName", go.name); ctx.SetItem("GameObjectId", go.GetInstanceID()); ctx.SetItem("gameObject", go); ctx.SetItem("signalContext", go); }
private void Sleep() { if (this.state == MindState.Asleep) { return; } if (this.state == MindState.FallingAsleep) { return; } this.state = MindState.FallingAsleep; this.eyeOpenTarget = 0.0f; this.eyeBlinking = false; this.eyeSpeed = Time.SecondsPerFrame / MathF.Rnd.NextFloat(1.5f, 3.5f); this.DeactivateSpikes(); }
private void Awake() { if (this.state == MindState.Idle) { return; } if (this.state == MindState.Awaking) { return; } this.state = MindState.Awaking; this.eyeOpenTarget = 1.0f; this.eyeBlinking = false; this.eyeSpeed = Time.SecondsPerFrame / MathF.Rnd.NextFloat(1.0f, 1.5f); this.RandomizeBlinkTimer(); }
public void Add(Mind mind) { Assert.IsFalse(minds.Any(x => x.Component == mind)); var state = new MindState(mind); state.Tree = this.behaviorTreeFactory.Create(mind.BehaviorFile); state.Context = new BehaviorContext( string.Format("{0}-{1}", mind.gameObject.name, mind.gameObject.GetInstanceID()), state.Tree.Root); minds.Add(state); StartMind(state); }
private void StopMind(MindState state, bool recycle) { // Mind could already have been stopped if MindCoordinator was destroyed first if (state.IsMindStarted) { state.Tree.Root.Stop(state.Tree.Root.GetNode(state.Context)); // remove any schedule that might have been added in this game loop this.scheduler.Unschedule(state.Context); if (recycle) { state.Context.Reset(); } else { state.Context.Dispose(); } } state.IsMindStarted = false; }
protected override void Update() { // Find Target if (!target) { FindTarget(); } switch (state) { case MindState.FLEEING: target = startingPoint; agent.SetDestination(target.position); // start the enemy moving toward its target animator.SetBool("moving", true); if (HasReachedTarget()) { if (target.CompareTag("SpawnPoint")) // If the enemy has returned to their spawn point { GameManager.NumOfChildren--; Destroy(gameObject); } } break; case MindState.CHASING: if (timeTilRefresh < 0) // A timer to keep this from getting calculated every frame { FindTarget(); timeTilRefresh = refreshTime; } else { timeTilRefresh -= Time.deltaTime; } agent.SetDestination(target.position); // start the enemy moving toward its target animator.SetBool("moving", true); // Check if target is child and enemy is close enough to pick it up if (target.CompareTag("Target") && HasReachedTarget()) { if (target.parent.gameObject.GetComponentInChildren <Interactable>().pickedUp || !target.gameObject.activeInHierarchy) { Debug.Log("My target is already taken"); FindTarget(); return; } state = MindState.FLEEING; PickUpObject(target.parent.gameObject.GetComponentInChildren <Interactable>()); } else if (HasReachedAttackTarget()) // If the enemy is close enough to attack { if (Time.time >= nextAttackTime) { // Make sure the enemy has a line of sight to the player // if (!Physics.Linecast(transform.position, target.position, attackLayers)) // if (!Physics.Linecast(transform.position, target.position)) { // Play attack animation animator.SetTrigger("attack"); animator.SetBool("moving", false); // Resest navmesh path agent.ResetPath(); // Change to attacking state // Stops enemy from moving while attacking nextAttackTime = Time.time + attackTime; // timer for returning to chase state state = MindState.ATTACKING; // Do the actual attacking StartCoroutine(Attack(attackDelay)); IEnumerator Attack(float delay) { yield return(new WaitForSeconds(delay)); currentWeapon.target = target.transform.position + Vector3.up * 2; currentWeapon.Attack(); } } } FaceTarget(); } break; case MindState.ATTACKING: // Make sure to properly face the target FaceTarget(); // Return to chasing state when appropriate if (Time.time >= nextAttackTime) { state = MindState.CHASING; // nextAttackTime = Time.time + 1f / attackRate; // reset time for next attack } break; } // end switch base.Update(); }
private void Awake() { if (this.state == MindState.Idle) return; if (this.state == MindState.Awaking) return; this.state = MindState.Awaking; this.eyeOpenTarget = 1.0f; this.eyeBlinking = false; this.eyeSpeed = Time.SPFMult / MathF.Rnd.NextFloat(1.0f, 1.5f); this.RandomizeBlinkTimer(); }
void ICmpUpdatable.OnUpdate() { EnemyBlueprint blueprint = this.blueprint.Res; Transform transform = this.GameObj.Transform; RigidBody body = this.GameObj.GetComponent<RigidBody>(); Ship ship = this.GameObj.GetComponent<Ship>(); // Calculate distress caused by going in a different direction than desired float moveDistress = 0.0f; if (body.LinearVelocity.Length > 1.0f) { Vector2 actualVelocityDir = body.LinearVelocity.Normalized; Vector2 desiredVelocityDir = ship.TargetThrust; float desiredDirectionFactor = Vector2.Dot(actualVelocityDir, desiredVelocityDir); moveDistress = MathF.Clamp(1.0f - desiredDirectionFactor, 0.0f, 1.0f) * MathF.Clamp(body.LinearVelocity.Length - 0.5f, 0.0f, 1.0f); } // Do AI state handling stuff float moveTowardsEnemyRatio = 0.0f; switch (this.state) { case MindState.Asleep: { // Wake up, if there is a player near float nearestDist; GameObject nearestObj = this.GetNearestPlayerObj(out nearestDist); if (nearestObj != null && nearestDist <= WakeupDist && this.HasLineOfSight(nearestObj, true)) { this.Awake(); } // Don't move actively ship.TargetThrust = Vector2.Zero; ship.TargetAngle = MathF.Rnd.NextFloat(-MathF.RadAngle30, MathF.RadAngle30); ship.TargetAngleRatio = 0.0f; break; } case MindState.FallingAsleep: { if (this.eyeOpenValue <= 0.0001f) this.state = MindState.Asleep; break; } case MindState.Awaking: { if (this.eyeOpenValue >= 0.9999f) this.state = MindState.Idle; break; } case MindState.Idle: { // Follow, if there is a player near float nearestDist; GameObject nearestObj = this.GetNearestPlayerObj(out nearestDist); if (nearestObj != null && this.HasLineOfSight(nearestObj, false)) { if (behavior.HasFlag(BehaviorFlags.Chase)) { Transform nearestObjTransform = nearestObj.Transform; Vector2 targetDiff = nearestObjTransform.Pos.Xy - transform.Pos.Xy; ship.TargetThrust = targetDiff / MathF.Max(targetDiff.Length, 25.0f); moveTowardsEnemyRatio = ship.TargetThrust.Length; } else { ship.TargetThrust = Vector2.Zero; } ship.TargetAngle += 0.001f * Time.TimeMult; ship.TargetAngleRatio = 0.1f; this.idleTimer = MathF.Rnd.NextFloat(0.0f, SleepTime * 0.25f); if (nearestDist <= SpikeAttackMoveDist) { moveDistress = 0.0f; if (!this.spikesActive) this.ActivateSpikes(); } else if (ship.TargetThrust.Length > 0.1f) { if (this.spikesActive) this.DeactivateSpikes(); } } // Try to stay in place otherwise else { ship.TargetThrust = -body.LinearVelocity / MathF.Max(body.LinearVelocity.Length, ship.Blueprint.Res.MaxSpeed); ship.TargetAngleRatio = 0.1f; this.idleTimer += Time.MsPFMult * Time.TimeMult; if (this.spikesActive) this.DeactivateSpikes(); } // Blink occasionally this.blinkTimer -= Time.MsPFMult * Time.TimeMult; if (this.blinkTimer <= 0.0f) { this.RandomizeBlinkTimer(); this.BlinkEye(); } // Go to sleep if nothing happens. if (this.idleTimer > SleepTime) { this.Sleep(); } break; } } // Udpate the eyes state and visual appearance { float actualTarget = MathF.Clamp(this.eyeOpenTarget - moveDistress * 0.35f, 0.0f, 1.0f); float eyeDiff = MathF.Abs(actualTarget - this.eyeOpenValue); float eyeChange = MathF.Sign(actualTarget - this.eyeOpenValue) * MathF.Min(this.eyeSpeed, eyeDiff); this.eyeOpenValue = MathF.Clamp(this.eyeOpenValue + eyeChange * Time.TimeMult, 0.0f, 1.0f); if (this.eyeBlinking && this.eyeOpenValue <= this.eyeOpenTarget + 0.0001f) this.eyeOpenTarget = 1.0f; if (this.eye != null) { this.eye.AnimTime = this.eyeOpenValue; } } // Update the spikes state and visual appearance for (int i = 0; i < this.spikeState.Length; i++) { float actualTarget = MathF.Clamp(this.spikeState[i].OpenTarget - moveDistress, 0.0f, 1.0f); if (actualTarget > this.spikeState[i].OpenValue) { Vector2 spikeDir; switch (i) { default: case 0: spikeDir = new Vector2(1, -1); break; case 1: spikeDir = new Vector2(1, 1); break; case 2: spikeDir = new Vector2(-1, 1); break; case 3: spikeDir = new Vector2(-1, -1); break; } Vector2 spikeBeginWorld = transform.GetWorldPoint(spikeDir * 4); Vector2 spikeEndWorld = transform.GetWorldPoint(spikeDir * 11); bool hitAnything = false; RigidBody.RayCast(spikeBeginWorld, spikeEndWorld, data => { if (data.Shape.IsSensor) return -1; if (data.Body == body) return -1; Ship otherShip = data.GameObj.GetComponent<Ship>(); if (otherShip != null && otherShip.Owner != null) return -1; hitAnything = true; return 0; }); if (hitAnything) { actualTarget = 0.0f; } } float spikeMoveDir = MathF.Sign(actualTarget - this.spikeState[i].OpenValue); this.spikeState[i].OpenValue = MathF.Clamp(this.spikeState[i].OpenValue + spikeMoveDir * this.spikeState[i].Speed * Time.TimeMult, 0.0f, 1.0f); if (this.spikeState[i].Blinking && this.spikeState[i].OpenValue <= this.spikeState[i].OpenTarget + 0.0001f) { this.spikeState[i].OpenTarget = 1.0f; this.spikeState[i].Speed = Time.SPFMult / MathF.Rnd.NextFloat(0.25f, 1.0f); } // If we're extending a spike where the sensor has already registered a contact, explode if (this.spikeState[i].OpenValue > 0.75f && this.spikeState[i].ContactCount > 0) this.FireExplosives(); } if (this.spikes != null) { for (int i = 0; i < this.spikes.Length; i++) { if (this.spikes[i] == null) continue; Rect spikeRect = this.spikes[i].Rect; spikeRect.Y = MathF.Lerp(3.5f, -4.5f, this.spikeState[i].OpenValue); this.spikes[i].Rect = spikeRect; } } // Make a sound while moving if (blueprint.MoveSound != null) { // Determine the target volume float targetVolume = MathF.Clamp(moveTowardsEnemyRatio, 0.0f, 1.0f); // Clean up disposed loop if (this.moveSoundLoop != null && this.moveSoundLoop.Disposed) this.moveSoundLoop = null; // Start the loop when requested if (targetVolume > 0.0f && this.moveSoundLoop == null) { this.moveSoundLoop = DualityApp.Sound.PlaySound3D(blueprint.MoveSound, this.GameObj); this.moveSoundLoop.Looped = true; } // Configure existing loop and dispose it when no longer needed if (this.moveSoundLoop != null) { this.moveSoundLoop.Volume += (targetVolume - this.moveSoundLoop.Volume) * 0.05f * Time.TimeMult; if (this.moveSoundLoop.Volume <= 0.05f) { this.moveSoundLoop.FadeOut(0.1f); this.moveSoundLoop = null; } } } // Make a danger sound while moving with spikes out if (blueprint.AttackSound != null) { // Determine the target volume float targetVolume = this.spikesActive ? MathF.Clamp(moveTowardsEnemyRatio, 0.25f, 1.0f) : 0.0f; // Clean up disposed loop if (this.dangerSoundLoop != null && this.dangerSoundLoop.Disposed) this.dangerSoundLoop = null; // Start the loop when requested if (targetVolume > 0.0f && this.dangerSoundLoop == null) { this.dangerSoundLoop = DualityApp.Sound.PlaySound3D(blueprint.AttackSound, this.GameObj); this.dangerSoundLoop.Looped = true; } // Configure existing loop and dispose it when no longer needed if (this.dangerSoundLoop != null) { this.dangerSoundLoop.Volume += (targetVolume - this.dangerSoundLoop.Volume) * 0.1f * Time.TimeMult; if (this.dangerSoundLoop.Volume <= 0.05f) { this.dangerSoundLoop.FadeOut(0.1f); this.dangerSoundLoop = null; } } } }
void ICmpUpdatable.OnUpdate() { EnemyBlueprint blueprint = this.blueprint.Res; Transform transform = this.GameObj.Transform; RigidBody body = this.GameObj.GetComponent <RigidBody>(); Ship ship = this.GameObj.GetComponent <Ship>(); // Calculate distress caused by going in a different direction than desired float moveDistress = 0.0f; if (body.LinearVelocity.Length > 1.0f) { Vector2 actualVelocityDir = body.LinearVelocity.Normalized; Vector2 desiredVelocityDir = ship.TargetThrust; float desiredDirectionFactor = Vector2.Dot(actualVelocityDir, desiredVelocityDir); moveDistress = MathF.Clamp(1.0f - desiredDirectionFactor, 0.0f, 1.0f) * MathF.Clamp(body.LinearVelocity.Length - 0.5f, 0.0f, 1.0f); } // Do AI state handling stuff float moveTowardsEnemyRatio = 0.0f; switch (this.state) { case MindState.Asleep: { // Wake up, if there is a player near float nearestDist; GameObject nearestObj = this.GetNearestPlayerObj(out nearestDist); if (nearestObj != null && nearestDist <= WakeupDist && this.HasLineOfSight(nearestObj, true)) { this.Awake(); } // Don't move actively ship.TargetThrust = Vector2.Zero; ship.TargetAngle = MathF.Rnd.NextFloat(-MathF.RadAngle30, MathF.RadAngle30); ship.TargetAngleRatio = 0.0f; break; } case MindState.FallingAsleep: { if (this.eyeOpenValue <= 0.0001f) { this.state = MindState.Asleep; } break; } case MindState.Awaking: { if (this.eyeOpenValue >= 0.9999f) { this.state = MindState.Idle; } break; } case MindState.Idle: { // Follow, if there is a player near float nearestDist; GameObject nearestObj = this.GetNearestPlayerObj(out nearestDist); if (nearestObj != null && this.HasLineOfSight(nearestObj, false)) { if (this.behavior.HasFlag(BehaviorFlags.Chase)) { Transform nearestObjTransform = nearestObj.Transform; Vector2 targetDiff = nearestObjTransform.Pos.Xy - transform.Pos.Xy; ship.TargetThrust = targetDiff / MathF.Max(targetDiff.Length, 25.0f); moveTowardsEnemyRatio = ship.TargetThrust.Length; } else { ship.TargetThrust = Vector2.Zero; } ship.TargetAngle += 0.001f * Time.TimeMult; ship.TargetAngleRatio = 0.1f; this.idleTimer = MathF.Rnd.NextFloat(0.0f, SleepTime * 0.25f); if (nearestDist <= SpikeAttackMoveDist) { moveDistress = 0.0f; if (!this.spikesActive) { this.ActivateSpikes(); } } else if (ship.TargetThrust.Length > 0.1f) { if (this.spikesActive) { this.DeactivateSpikes(); } } } // Try to stay in place otherwise else { ship.TargetThrust = -body.LinearVelocity / MathF.Max(body.LinearVelocity.Length, ship.Blueprint.Res.MaxSpeed); ship.TargetAngleRatio = 0.1f; this.idleTimer += Time.MillisecondsPerFrame * Time.TimeMult; if (this.spikesActive) { this.DeactivateSpikes(); } } // Blink occasionally this.blinkTimer -= Time.MillisecondsPerFrame * Time.TimeMult; if (this.blinkTimer <= 0.0f) { this.RandomizeBlinkTimer(); this.BlinkEye(); } // Go to sleep if nothing happens. if (this.idleTimer > SleepTime) { this.Sleep(); } break; } } // Udpate the eyes state and visual appearance { float actualTarget = MathF.Clamp(this.eyeOpenTarget - moveDistress * 0.35f, 0.0f, 1.0f); float eyeDiff = MathF.Abs(actualTarget - this.eyeOpenValue); float eyeChange = MathF.Sign(actualTarget - this.eyeOpenValue) * MathF.Min(this.eyeSpeed, eyeDiff); this.eyeOpenValue = MathF.Clamp(this.eyeOpenValue + eyeChange * Time.TimeMult, 0.0f, 1.0f); if (this.eyeBlinking && this.eyeOpenValue <= this.eyeOpenTarget + 0.0001f) { this.eyeOpenTarget = 1.0f; } if (this.eye != null) { this.eye.AnimTime = this.eyeOpenValue; } } // Update the spikes state and visual appearance for (int i = 0; i < this.spikeState.Length; i++) { float actualTarget = MathF.Clamp(this.spikeState[i].OpenTarget - moveDistress, 0.0f, 1.0f); if (actualTarget > this.spikeState[i].OpenValue) { Vector2 spikeDir; switch (i) { default: case 0: spikeDir = new Vector2(1, -1); break; case 1: spikeDir = new Vector2(1, 1); break; case 2: spikeDir = new Vector2(-1, 1); break; case 3: spikeDir = new Vector2(-1, -1); break; } Vector2 spikeBeginWorld = transform.GetWorldPoint(spikeDir * 4); Vector2 spikeEndWorld = transform.GetWorldPoint(spikeDir * 11); bool hitAnything = false; this.Scene.Physics.RayCast(spikeBeginWorld, spikeEndWorld, data => { if (data.Shape.IsSensor) { return(-1); } if (data.Body == body) { return(-1); } Ship otherShip = data.GameObj.GetComponent <Ship>(); if (otherShip != null && otherShip.Owner != null) { return(-1); } hitAnything = true; return(0); }); if (hitAnything) { actualTarget = 0.0f; } } float spikeMoveDir = MathF.Sign(actualTarget - this.spikeState[i].OpenValue); this.spikeState[i].OpenValue = MathF.Clamp(this.spikeState[i].OpenValue + spikeMoveDir * this.spikeState[i].Speed * Time.TimeMult, 0.0f, 1.0f); if (this.spikeState[i].Blinking && this.spikeState[i].OpenValue <= this.spikeState[i].OpenTarget + 0.0001f) { this.spikeState[i].OpenTarget = 1.0f; this.spikeState[i].Speed = Time.SecondsPerFrame / MathF.Rnd.NextFloat(0.25f, 1.0f); } // If we're extending a spike where the sensor has already registered a contact, explode if (this.spikeState[i].OpenValue > 0.75f && this.spikeState[i].ContactCount > 0) { this.FireExplosives(); } } if (this.spikes != null) { for (int i = 0; i < this.spikes.Length; i++) { if (this.spikes[i] == null) { continue; } Rect spikeRect = this.spikes[i].Rect; spikeRect.Y = MathF.Lerp(3.5f, -4.5f, this.spikeState[i].OpenValue); this.spikes[i].Rect = spikeRect; } } // Make a sound while moving if (blueprint.MoveSound != null) { // Determine the target volume float targetVolume = MathF.Clamp(moveTowardsEnemyRatio, 0.0f, 1.0f); // Clean up disposed loop if (this.moveSoundLoop != null && this.moveSoundLoop.Disposed) { this.moveSoundLoop = null; } // Start the loop when requested if (targetVolume > 0.0f && this.moveSoundLoop == null) { this.moveSoundLoop = DualityApp.Sound.PlaySound3D(blueprint.MoveSound, this.GameObj, true); this.moveSoundLoop.Looped = true; } // Configure existing loop and dispose it when no longer needed if (this.moveSoundLoop != null) { this.moveSoundLoop.Volume += (targetVolume - this.moveSoundLoop.Volume) * 0.05f * Time.TimeMult; if (this.moveSoundLoop.Volume <= 0.05f) { this.moveSoundLoop.FadeOut(0.1f); this.moveSoundLoop = null; } } } // Make a danger sound while moving with spikes out if (blueprint.AttackSound != null) { // Determine the target volume float targetVolume = this.spikesActive ? MathF.Clamp(moveTowardsEnemyRatio, 0.25f, 1.0f) : 0.0f; // Clean up disposed loop if (this.dangerSoundLoop != null && this.dangerSoundLoop.Disposed) { this.dangerSoundLoop = null; } // Start the loop when requested if (targetVolume > 0.0f && this.dangerSoundLoop == null) { this.dangerSoundLoop = DualityApp.Sound.PlaySound3D(blueprint.AttackSound, this.GameObj, true); this.dangerSoundLoop.Looped = true; } // Configure existing loop and dispose it when no longer needed if (this.dangerSoundLoop != null) { this.dangerSoundLoop.Volume += (targetVolume - this.dangerSoundLoop.Volume) * 0.1f * Time.TimeMult; if (this.dangerSoundLoop.Volume <= 0.05f) { this.dangerSoundLoop.FadeOut(0.1f); this.dangerSoundLoop = null; } } } }
/// <summary> /// Create new need with: /// </summary> /// <param name="mindState">Need type</param> /// <param name="increment">Need desire rate</param> public Need(MindState mindState, float increment) { this.Max = 5000000; this.Min = 0; this.increment = increment; this.satisfactionThreshold = DefaultThreshold; this.MindState = mindState; }
/// <summary> /// begins a new process flow, usually on the event of a current need change /// </summary> /// <param name="mindState">The new current need type</param> private void startNewProcess(MindState mindState) { switch (mindState) { case MindState.Thirsty: thoughtProcess = new BarProcess(boid, drinkNeed); break; case MindState.Dancey: thoughtProcess = new DanceProcess(boid, danceNeed); break; case MindState.Incontenent: thoughtProcess = new ToiletProcess(boid, toiletNeed); break; default: throw new ArgumentOutOfRangeException(); } }
public void setMind(MindState m) { this.mindState = m; }