// Start is called before the first frame update void Awake() { damage = enemyPreset.damage; moveTime = enemyPreset.moveTime; idleTimeMin = enemyPreset.idleTimeMin; idleTimeMax = enemyPreset.idleTimeMax; wanderRadius = enemyPreset.wanderRadius; home = transform.position; trigger = GetComponentInChildren <DetectPlayer>(); trigger.GetComponent <SphereCollider>().radius = enemyPreset.detectionRadius; navMeshAgent = GetComponent <NavMeshAgent>(); navMeshAgent.speed = enemyPreset.speed; fsm = new FSM("MeleeAI FSM"); WanderState = fsm.AddState("WanderState"); IdleState = fsm.AddState("IdleState"); AlertState = fsm.AddState("AlertState"); MeleeState = fsm.AddState("MeleeState"); WanderAction = new WanderAction(WanderState); IdleAction = new TextAction(IdleState); alertAction = new AlertAction(AlertState); meleeAction = new MeleeAction(MeleeState); WanderState.AddAction(WanderAction); IdleState.AddAction(IdleAction); AlertState.AddAction(alertAction); MeleeState.AddAction(meleeAction); WanderState.AddTransition("ToIdle", IdleState); WanderState.AddTransition("PlayerDetect", AlertState); IdleState.AddTransition("ToWander", WanderState); IdleState.AddTransition("PlayerDetect", AlertState); AlertState.AddTransition("ToIdle", IdleState); AlertState.AddTransition("ToMelee", MeleeState); MeleeState.AddTransition("ToAlert", AlertState); WanderAction.Init(this.transform, home, navMeshAgent, wanderRadius, moveTime, "ToIdle"); IdleAction.Init("Idling", Random.Range(idleTimeMin, idleTimeMax), "ToWander"); alertAction.Init(trigger, navMeshAgent, "ToIdle"); meleeAction.Init(this.transform, damage, trigger, FindObjectOfType <PlayerManager>(), "ToAlert"); fsm.Start("IdleState"); }
/// <summary> /// /// </summary> public static void createMeleeAction(Vector2 position, Vector2 heading, Transform transform, Entity owner) { Entity e = ecs_instance.create(); Sprite sprite = new Sprite("sword", "swordnormal", 32, 32, 0, 0); MeleeAction action = new MeleeAction(); action.Animation = new SpriteAnimation(9, 20); action.ArcDegrees = 180; action.Owner = owner; action.Lifetime = 250; action.Range = 32; ecs_instance.add_component(e, new Position(position, new Vector2(16))); ecs_instance.add_component(e, new Heading(heading)); ecs_instance.add_component(e, transform); ecs_instance.add_component(e, sprite); ecs_instance.add_component(e, action); ecs_instance.resolve(e); }
protected override void process(Entity entity) { MeleeAction action = (MeleeAction)m_MeleeActionMapper.get(entity); Position position = (Position)m_PositionMapper.get(entity); SpatialPartition spatial = (SpatialPartition)m_SpatialMapper.get(m_Spatial); action.ElapsedTime += ecs_instance.ElapsedTime; //is it time for the melee action to die? if (action.ElapsedTime >= action.Lifetime) { ecs_instance.delete_entity(entity); return; } //retrieve all local entities //List<Entity> locals = spatial.QuadTree.retrieveContentsAtLocation(position.Pos); List <Entity> locals = spatial.QuadTree.findAllWithinRange(position.Pos, action.Range); //is the location good? if (locals != null) { //is there anyone here? if (locals.Count > 0) { for (int i = 0; i < locals.Count; i++) { //dont attempt to melee owner if (locals[i] == action.Owner) { continue; } if (action.HitByAction.Contains(locals[i])) { continue; } Life life = (Life)m_LifeMapper.get(locals[i]); //if no life, dont bother if (life == null) { continue; } //if not alive, dont bother if (!life.IsAlive) { continue; } //interaction available? Interactable interactions = (Interactable)m_InteractionMapper.get(locals[i]); if (interactions != null) { Position lPosition = (Position)m_PositionMapper.get(locals[i]); Position oPosition = (Position)m_PositionMapper.get(action.Owner); Vector2 lToO = (oPosition.Pos + oPosition.Offset) - (lPosition.Pos + lPosition.Offset); //local to owner Heading head = (Heading)m_HeadingMapper.get(entity); //get the weapon heading bool facing = (Vector2.Dot(head.getHeading(), lToO) < 0); //is the weapon facing the local? //if you're facing, are you within range? if (facing && (Vector2.Distance(lPosition.Pos + lPosition.Offset, position.Pos + position.Offset) <= action.Range)) { //does it support this interaction? if (interactions.SupportedInteractions.MELEE_ACTIONABLE && interactions.SupportedInteractions.ATTACKABLE) { Factions lfactions = (Factions)m_FactionMapper.get(locals[i]); Factions pfactions = (Factions)m_FactionMapper.get(action.Owner); //dont attack allies if (lfactions.OwnerFaction.FactionType == pfactions.OwnerFaction.FactionType) { continue; } //add to hit-list so we dont attack it again on swing follow-through action.HitByAction.Add(locals[i]); //create melee attack UtilFactory.createAttack(action.Owner, locals[i], AttackType.Melee); //destroy melee action //ecs_instance.delete_entity(entity); //return; } } } } } } //get info for rotation update Heading heading = (Heading)m_HeadingMapper.get(entity); Transform transform = (Transform)m_TransformMapper.get(entity); //rotate melee by degrees over the melee arc float rot = (((float)action.Animation.updateFrame(ecs_instance.ElapsedTime) / (float)action.Animation.Frames) * action.ArcDegrees) - (action.ArcDegrees / 2f); transform.Rotation = rot * (((float)Math.PI) / 180f) - VectorHelper.getAngle(new Vector2(1, 0), heading.getHeading()); //adjust the arc based on current position (i.e., move with the player) Position ownerPos = (Position)m_PositionMapper.get(action.Owner); Vector2 pos = ownerPos.Pos + new Vector2(16, 0);// +ownerPos.getOffset(); Vector2 dir = heading.getHeading(); dir.Normalize(); position.Pos = pos + dir * 10; }
/// <summary> /// /// </summary> /// <param name="processingAction"></param> /// <param name="targets"></param> /// <param name="user"></param> private void processMeleeAction(MeleeAction processingAction, List <System.Object> targets, ParentPuppetScript user) { Debug.LogError("The Hunter " + user.getPuppetName() + " is using the action " + ((BattleAction)processingAction).name + " on the following targets:"); foreach (System.Object target in targets) { Debug.LogError(((MonsterBodyPart)target).name); } int strengthModifier = processingAction. getStrengthModifierValue(); int strength = modifyValue(user.getModifiedStrength(), strengthModifier, processingAction.getStrengthModifierType()); float chanceToHit = processingAction.getChanceToHit(); int piercing = processingAction.getPiercing(); int damage = processingAction.getDamagae(); int meleeHitCount = user.getModifiedMeleeAttackCount(); for (int i = 0; i < targets.Count; i++) { for (int hits = 0; hits < meleeHitCount; hits++) { switch (targets[i]) { case MonsterBodyPart monsterBodyPart: Debug.LogError("The target is a monster bodypart"); Debug.LogError("Chance to hit is " + chanceToHit); // If the chance to hit succes, proceed, otherwise end this if (Random.Range(0, 99) < chanceToHit) { Debug.LogError("HIT!"); // Remove some toughness from the monster through // the peircing value float monsterToughness = monsterBodyPart.toughness - piercing; // Clamp the monster toughness so that it is always // greater than 0 (such that we do not divide by zero) monsterToughness = Mathf.Clamp(monsterToughness, 1.0f, float.PositiveInfinity); // Get the chance to penetrate float chanceToPierce = user.getModifiedStrength() / (monsterToughness * 2); Debug.LogError("The chance to pierce is: " + user.getModifiedStrength() + " / ((" + monsterBodyPart.toughness + " - " + piercing + ") * 2) = " + chanceToPierce); // If it pens, then deal damag based on the given amount if (Random.Range(0, 99) < (float)(chanceToPierce * 100f)) { Debug.LogError("PIERCE!"); Debug.LogError("Bodypart HP is " + monsterBodyPart.hp + " and damage is " + damage); monsterBodyPart.damageBodyPart(damage); Debug.LogError("Bodypart HP after damage is " + monsterBodyPart.hp); } else { Debug.LogError("DEFLECTED!"); // Tell user the hit reflected } } else { Debug.LogError("MISS!"); // Tell user they missed } break; default: Debug.LogError("Error! unknown action target from the" + "current processing target: " + targets[i].ToString()); break; } } } }