public override void OnShapeParentChanged(Microbe newShapeParent, Vector3 offset) { // Check if the pilus exists if (NeedsUpdateAnyway()) { // Send the organelle positions to the membrane then update the pilus currentShapesParent.SendOrganellePositionsToMembrane(); Update(0); } else { // Firstly the rotation relative to the master. var position = organelle.RotatedPositionInsideColony(lastCalculatedPosition); // Then the position position += offset; Vector3 middle = offset; Vector3 membranePointDirection = (position - middle).Normalized(); position += membranePointDirection * Constants.DEFAULT_HEX_SIZE * 2; // Pilus rotation var angle = GetAngle(middle - position); var rotation = MathUtils.CreateRotationForPhysicsOrganelle(angle); var transform = new Transform(rotation, position); // New ownerId var ownerId = currentShapesParent.CreateNewOwnerId(newShapeParent, transform, addedChildShapes[0]); newShapeParent.AddPilus(ownerId); // Destroy the old shape owner DestroyShape(); addedChildShapes.Add(ownerId); } currentShapesParent = newShapeParent; }
/// <summary> /// Add a pull from the given source with the given strength. /// </summary> /// <param name="source">The source of the pull to added.</param> /// <param name="strength">The strength of the added pull.</param> public void AddPull(Microbe source, float strength) { pull[source] = strength; }
public void Think(float delta, Random random, MicrobeAICommonData data) { _ = delta; // SetRandomTargetAndSpeed(random); // Clear the lists predatoryMicrobes.Clear(); preyMicrobes.Clear(); chunkList.Clear(); prey = null; // 30 seconds about if (boredom == (int)random.Next(SpeciesFocus * 2, 1000.0f + SpeciesFocus * 2)) { // Occasionally you need to reevaluate things boredom = 0; if (RollCheck(SpeciesActivity, 400, random)) { lifeState = LifeState.PLANTLIKE_STATE; } else { lifeState = LifeState.NEUTRAL_STATE; } } else { boredom++; } switch (lifeState) { case LifeState.PLANTLIKE_STATE: // This ai would ideally just sit there, until it sees a nice opportunity pop-up unlike neutral, // which wanders randomly (has a gather chance) until something interesting pops up break; case LifeState.NEUTRAL_STATE: { // Before these would run every time, now they just run for the states that need them. boredom = 0; preyPegged = false; prey = null; if (predator == null) { GetNearestPredatorItem(data.AllMicrobes); } // Peg your prey if (!preyPegged) { prey = null; prey = GetNearestPreyItem(data.AllMicrobes); if (prey != null) { preyPegged = true; } } if (targetChunk == null) { targetChunk = GetNearestChunkItem(data.AllChunks); } EvaluateEnvironment(random); break; } case LifeState.GATHERING_STATE: { // In this state you gather compounds if (RollCheck(SpeciesOpportunism, 400.0f, random)) { lifeState = LifeState.SCAVENGING_STATE; boredom = 0; } else { DoRunAndTumble(random); } break; } case LifeState.FLEEING_STATE: { if (predator == null) { GetNearestPredatorItem(data.AllMicrobes); } // In this state you run from predatory microbes if (predator != null) { DealWithPredators(random); } else { if (RollCheck(SpeciesActivity, 400, random)) { lifeState = LifeState.PLANTLIKE_STATE; boredom = 0; } else { lifeState = LifeState.NEUTRAL_STATE; } } break; } case LifeState.PREDATING_STATE: { // Peg your prey if (!preyPegged) { prey = null; prey = GetNearestPreyItem(data.AllMicrobes); if (prey != null) { preyPegged = true; } } if (preyPegged && prey != null) { DealWithPrey(data.AllMicrobes, random); } else { if (RollCheck(SpeciesActivity, 400, random)) { lifeState = LifeState.PLANTLIKE_STATE; boredom = 0; } else { lifeState = LifeState.NEUTRAL_STATE; } } break; } case LifeState.SCAVENGING_STATE: { if (targetChunk == null) { targetChunk = GetNearestChunkItem(data.AllChunks); } if (targetChunk != null) { DealWithChunks(targetChunk, data.AllChunks); } else { if (!RollCheck(SpeciesOpportunism, 400, random)) { lifeState = LifeState.NEUTRAL_STATE; boredom = 0; } else { lifeState = LifeState.SCAVENGING_STATE; } } break; } } // Run reflexes DoReflexes(); // Clear the absorbed compounds for run and rumble microbe.TotalAbsorbedCompounds.Clear(); }
/// <summary> /// For chasing down and killing prey in various ways /// </summary> private void DealWithPrey(List <Microbe> allMicrobes, Random random) { // Tick the engulf tick ticksSinceLastToggle += 1; bool lostPrey = false; try { targetPosition = prey.Translation; } catch (ObjectDisposedException) { lostPrey = true; } if (lostPrey) { preyPegged = false; prey = null; return; } // Chase your prey if you dont like acting like a plant // Allows for emergence of Predatory Plants (Like a single cleed version of a venus fly trap) // Creatures with lethargicness of 400 will not actually chase prey, just lie in wait microbe.LookAtPoint = targetPosition; hasTargetPosition = true; // Always set target Position, for use later in AI if (moveThisHunt) { if (moveFocused) { microbe.MovementDirection = new Vector3(0.0f, 0.0f, -Constants.AI_FOCUSED_MOVEMENT); } else { microbe.MovementDirection = new Vector3(0.0f, 0.0f, -Constants.AI_BASE_MOVEMENT); } } else { microbe.MovementDirection = new Vector3(0, 0, 0); } // Turn off engulf if prey is Dead // This is probabbly not working. This is almost certainly not working in the Godot version if (prey.Dead) { hasTargetPosition = false; prey = GetNearestPreyItem(allMicrobes); if (prey != null) { preyPegged = true; } microbe.EngulfMode = false; // You got a kill, good job if (!microbe.IsPlayerMicrobe && !microbe.Species.PlayerSpecies) { microbe.SuccessfulKill(); } if (RollCheck(SpeciesOpportunism, 400.0f, random)) { lifeState = LifeState.SCAVENGING_STATE; boredom = 0; } } else { // Turn on engulfmode if close if ((microbe.Translation - targetPosition).LengthSquared() <= 300 + microbe.EngulfSize * 3.0f && microbe.Compounds.GetCompoundAmount(atp) >= 1.0f && !microbe.EngulfMode && microbe.EngulfSize > Constants.ENGULF_SIZE_RATIO_REQ * prey.EngulfSize) { microbe.EngulfMode = true; ticksSinceLastToggle = 0; } else if ((microbe.Translation - targetPosition).LengthSquared() >= 500 + microbe.EngulfSize * 3.0f && microbe.EngulfMode && ticksSinceLastToggle >= Constants.AI_ENGULF_INTERVAL) { microbe.EngulfMode = false; ticksSinceLastToggle = 0; } } // Shoot toxins if able There should be AI that prefers shooting over engulfing, etc, not sure how to model that // without a million and one variables perhaps its a mix? Maybe a creature with a focus less then a certain // amount simply never attacks that way? Maybe a creature with a specific focus, only ever shoots and never // engulfs? Maybe their lethargicness impacts that? I just dont want each enemy to feel the same you know. For // now creatures with a focus under 100 will never shoot. if (SpeciesFocus >= 100.0f) { if (microbe.Hitpoints > 0 && microbe.AgentVacuoleCount > 0 && (microbe.Translation - targetPosition).LengthSquared() <= SpeciesFocus * 10.0f) { if (microbe.Compounds.GetCompoundAmount(oxytoxy) >= Constants.MINIMUM_AGENT_EMISSION_AMOUNT) { microbe.EmitToxin(oxytoxy); } } } }
/// <summary> /// Kill the microbe. /// </summary> /// <param name="microbe">The microbe to kill.</param> private static void Kill(Microbe microbe) { microbe.Die(); }
public void TriggerOnMicrobeDied(Microbe microbe, bool isPlayer) { OnMicrobeDied?.Invoke(microbe, isPlayer); }
public void TriggerOnMicrobeSpawned(Microbe microbe) { OnMicrobeSpawned?.Invoke(microbe); }
protected override void CustomAttach() { currentShapesParent = organelle.ParentMicrobe; }
public void OnShapeParentChanged(Microbe newShapeParent, Vector3 offset) { }
/// <summary> /// Called by a microbe when this organelle has been added to it /// </summary> public void OnAddedToMicrobe(Microbe microbe) { if (Definition == null) { throw new Exception("PlacedOrganelle has no definition set"); } if (ParentMicrobe != null) { throw new InvalidOperationException("PlacedOrganelle is already in a microbe"); } // Store parameters ParentMicrobe = microbe; // Grab the species colour for us Colour = microbe.Species.Colour; ParentMicrobe.OrganelleParent.AddChild(this); // Graphical display if (Definition.LoadedScene != null) { SetupOrganelleGraphics(); } float hexSize = Constants.DEFAULT_HEX_SIZE; // Scale the physics hex size down for bacteria if (microbe.Species.IsBacteria) { hexSize *= 0.5f; } // Physics ParentMicrobe.Mass += Definition.Mass; // Add hex collision shapes foreach (Hex hex in Definition.GetRotatedHexes(Orientation)) { var shape = new SphereShape(); shape.Radius = hexSize * 2.0f; var ownerId = ParentMicrobe.CreateShapeOwner(shape); // This is needed to actually add the shape ParentMicrobe.ShapeOwnerAddShape(ownerId, shape); // The shape is in our parent so the final position is our // offset plus the hex offset Vector3 shapePosition = Hex.AxialToCartesian(hex) + Translation; // Scale for bacteria physics. if (microbe.Species.IsBacteria) { shapePosition *= 0.5f; } var transform = new Transform(Quat.Identity, shapePosition); ParentMicrobe.ShapeOwnerSetTransform(ownerId, transform); shapes.Add(ownerId); } // Components Components = new List <IOrganelleComponent>(); foreach (var factory in Definition.ComponentFactories) { var component = factory.Create(); if (component == null) { throw new Exception("PlacedOrganelle component factory returned null"); } component.OnAttachToCell(this); Components.Add(component); } ResetGrowth(); }
private void OnPlayerUnbound(Microbe player) { TutorialState.SendEvent(TutorialEventType.MicrobePlayerUnbound, EventArgs.Empty, this); }
/// <summary> /// Called by a microbe when this organelle has been added to it /// </summary> public void OnAddedToMicrobe(Microbe microbe) { if (Definition == null) { throw new Exception("PlacedOrganelle has no definition set"); } if (ParentMicrobe != null) { throw new InvalidOperationException("PlacedOrganelle is already in a microbe"); } // Store parameters ParentMicrobe = microbe; // Grab the species colour for us Colour = microbe.Species.Colour; ParentMicrobe.OrganelleParent.AddChild(this); // Graphical display if (Definition.LoadedScene != null) { // There is an intermediate node so that the organelle scene root rotation and scale work OrganelleGraphics = new Spatial(); var organelleSceneInstance = (Spatial)Definition.LoadedScene.Instance(); AddChild(OrganelleGraphics); OrganelleGraphics.Scale = new Vector3(Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE); var transform = new Transform(MathUtils.CreateRotationForOrganelle(Orientation), Definition.CalculateModelOffset()); OrganelleGraphics.Transform = transform; // Store the material of the organelle to be updated GeometryInstance geometry; // Fetch the actual model from the scene to get at the material we set the tint on if (string.IsNullOrEmpty(Definition.DisplaySceneModelPath)) { geometry = (GeometryInstance)organelleSceneInstance; } else { geometry = organelleSceneInstance.GetNode <GeometryInstance>(Definition.DisplaySceneModelPath); } // Store animation player for later use if (!string.IsNullOrEmpty(Definition.DisplaySceneAnimation)) { OrganelleAnimation = organelleSceneInstance.GetNode <AnimationPlayer>(Definition.DisplaySceneAnimation); } organelleMaterial = (ShaderMaterial)geometry.MaterialOverride; OrganelleGraphics.AddChild(organelleSceneInstance); } // Position relative to origin of cell RotateY(Orientation * 60); Translation = Hex.AxialToCartesian(Position); float hexSize = Constants.DEFAULT_HEX_SIZE; // Scale the physics hex size down for bacteria if (microbe.Species.IsBacteria) { hexSize *= 0.5f; } // Physics ParentMicrobe.Mass += Definition.Mass; // Add hex collision shapes foreach (Hex hex in Definition.GetRotatedHexes(Orientation)) { var shape = new SphereShape(); shape.Radius = hexSize * 2.0f; var ownerId = ParentMicrobe.CreateShapeOwner(shape); // This is needed to actually add the shape ParentMicrobe.ShapeOwnerAddShape(ownerId, shape); // The shape is in our parent so the final position is our // offset plus the hex offset Vector3 shapePosition = Hex.AxialToCartesian(hex) + Translation; // Scale for bacteria physics. if (microbe.Species.IsBacteria) { shapePosition *= 0.5f; } var transform = new Transform(Quat.Identity, shapePosition); ParentMicrobe.ShapeOwnerSetTransform(ownerId, transform); shapes.Add(ownerId); } // Components Components = new List <IOrganelleComponent>(); foreach (var factory in Definition.ComponentFactories) { var component = factory.Create(); if (component == null) { throw new Exception("PlacedOrganelle component factory returned null"); } component.OnAttachToCell(this); Components.Add(component); } ResetGrowth(); }
public void Awake() { microbe = gameObject.GetComponent <Microbe>(); }
private void RemoveCellFromColony(Microbe target) { target.Colony.RemoveFromColony(target); }
/// <summary> /// Remove the pull of the given source. /// </summary> /// <param name="source">The source of the pull to remove.</param> public void RemovePull(Microbe source) { pull.Remove(source); }
public MicrobeEventArgs(Microbe microbe) { Microbe = microbe; }
public void TriggerOnPlayerMicrobeSpawned(Microbe player) { OnPlayerMicrobeSpawned?.Invoke(player); }