protected override Vector3 CalcAdjDirection(ITargetable targ) { Unit unit = targ as Unit; // Only lead target against units // How far to aim ahead given how long it would take to reach current position // current target position + target velocity * time for projectile to reach current target position Vector3 offsetTarget = targ.GetPosition(); if (unit) { offsetTarget += unit.GetVelocity() * ((targ.GetPosition() - transform.position).magnitude / projTemplate.GetSpeed()); } // How far to aim ahead given how long it would take to reach predicted position // current target position + target velocity * time for projectile to reach predicted target position Vector3 offsetTargetAdj = targ.GetPosition(); if (unit) { offsetTargetAdj += unit.GetVelocity() * ((offsetTarget - transform.position).magnitude / projTemplate.GetSpeed()); } Vector3 difference = offsetTargetAdj - transform.position; // Visuals if (parentUnit.printInfo) { Debug.DrawLine(targ.GetPosition(), transform.position, Color.red); Debug.DrawLine(offsetTarget, transform.position, Color.green); Debug.DrawLine(offsetTargetAdj, transform.position, Color.blue); } return(difference.normalized); }
public override void Update(float dt) { if (currentEnemy == null) { List <ITargetable> targets = map.GetTargetsInRange(position, info.range); for (int x = 0; x < targets.Count; x++) { if (targets[x] == this) { continue; } if (targets[x].GetTeam() != GetTeam()) { currentEnemy = targets[x]; } } } else { if (CanAttack(currentEnemy)) { atkCooldown = 1.0f / info.attackSpeed; map.Attacks.Add(new Attack(map, DamageType.Physical, info.attack, info.armorPen, position, this, currentEnemy, 60)); } if (currentEnemy.IsDead() || (currentEnemy.GetPosition() - GetPosition()).LengthSquared() < info.range * info.range) { currentEnemy = null; } } atkCooldown -= dt; base.Update(dt); }
float ComparisonWeight(ITargetable x) { float distanceWeight = Vector3.Distance(transform.position, x.GetPosition()) / range; // distanceWeight is always 0 to 1 int typeWeight = x.GetTargetType() == preferredTargetType ? 0 : 1; // Move weight out of 0 to 1 range if it is not our preferred type return(distanceWeight + typeWeight); // Always targets the closest preferred target. Only targets a non-preferred target if a preferred target is not present. }
public void AddToPartitioning(ITargetable target) { Vector3 position = target.GetPosition(); int x = (int)(position.X / PartitioningDensity); int y = (int)(position.Z / PartitioningDensity); TargetPartitioning[x, y].Add(target); }
public void RemoveFromPartitioning(ITargetable target) { Vector3 position = target.GetPosition(); int x = (int)(position.X / PartitioningDensity); int y = (int)(position.Z / PartitioningDensity); TargetPartitioning[x, y].Remove(target); }
public void AttackUpdate(float dt) { targetPos = currentEnemy.GetPosition(); Vector3 diff = currentEnemy.GetPosition() - champion.GetPosition(); float length = diff.Length(); diff /= length; if (champion.InRange(currentEnemy)) { champion.Attack(currentEnemy); targetPos = champion.GetPosition(); } if (currentEnemy.IsDead()) { currentEnemy = null; state = TestControllerState.Laning; } }
bool IsValid(ITargetable potentialTarget) { // Valid distance float sqrDistance = !IsNull(potentialTarget) ? (potentialTarget.GetPosition() - parentUnit.transform.position).sqrMagnitude : 0; // Check distance between us and the target // TODO: Maybe check from the parent unit's position? // Valid direction Vector3 dir = !IsNull(potentialTarget) ? CalcAdjDirection(potentialTarget) : transform.forward; // direction used elsewhere to check if aimed at target or not bool valid = false; // Have target, its in range, the look rotation is within limits, it is visible to our team if (!IsNull(potentialTarget) && sqrDistance <= range * range && ValidRotationHorizontal(CalcLookRotation(dir)) && potentialTarget.GetVisibleTo(parentUnit.GetTeam())) { valid = true; } else { valid = false; } return(valid); }
public void Update(float dt) { if (target != null) { targetPosition = target.GetPosition(); } Vector3 diff = targetPosition - position; float length = diff.Length(); diff /= length; position += diff * dt * Speed; if (target != null && target.IsDead()) { map.Attacks.Remove(this); return; } if (target != null && length < 1) { map.Attacks.Remove(this); switch (type) { case DamageType.Physical: target.TakePhysDmg(damage, pen); break; case DamageType.Magical: target.TakeMagDmg(damage, pen); break; } if (target.IsDead()) { if (attacker != null) { attacker.ReceiveGold(target.GoldValue); attacker.ReceiveXP(target.ExpValue); } } } }
public void SpawnHitscan(Hitscan temp, Vector3 position, Vector3 direction, Unit from, Status onHit, ITargetable goal) { Hitscan scan = new Hitscan(temp); scan.startPosition = position; scan.direction = direction; scan.SetFrom(from); scan.SetStatus(onHit); //hitscans.Add(scan); int index = IndexFromHitscanType(temp.GetHitscanType()); bool noGoal = IsNull(goal); // Raycast or do damage immediately. Use actual distance / hit information to inform visuals Vector3 dif = noGoal ? Vector3.zero : (position - goal.GetPosition()); float length = noGoal ? Raycast(scan) : dif.magnitude; if (!noGoal) // Has goal, do damage manually { goal.Damage(scan.GetDamage(), length, scan.GetDamageType()); vfx.SpawnEffect(VFXType.Hit_Near, position + direction * length, direction, scan.GetFrom().GetTeam()); } Vector3 size = new Vector3(pS[index].main.startSizeX.constant, length, 1); EmitParams param = new EmitParams() { position = position, velocity = direction * directionMult, startSize3D = size, //startColor = Random.value * Color.red + Random.value * Color.green + Random.value * Color.blue, startLifetime = scan.GetLifetime() // 2x just in case. Particles dying prematurely is the worst thing that could happen to this system }; pS[index].Emit(param, 1); }
bool CheckFriendlyFire() { if (IsNull(target)) { return(false); } // We know how many potential collisions we can have with the parent unit's colliders, so we will cast multiple rays in succession to skip past the collisions that we want to ignore // RaycastAll will not work in this case because it will pass through everything, rather than only passing through the parent unit's colliders and stopping on the first collision after them Collider[] cols = parentUnit.GetComponentsInChildren <Collider>(); // First, try to raycast and hope we don't hit ourselves Vector3 forward = GetForward(); RaycastHit hit; // If we are targeting a fighter and willing to aim at an ally unit hoping to hit an enemy fighter, we will check for FF in a shorter distance float checkDistance = (riskFFAgainstFighters && !target.HasCollision()) ? Vector3.Distance(firePos.position, target.GetPosition()) : range * gameRules.PRJ_friendlyFireCheckRangeMult; float offset = 0.02f; // How much we move in towards our first raycast hit location to make sure the next raycast is technically inside the collider we hit the first time around if (Physics.Raycast(firePos.position, forward, out hit, checkDistance, gameRules.collisionLayerMask)) { if (parentUnit.printInfo) { Debug.DrawLine(firePos.position, firePos.position + forward * checkDistance, Color.magenta, 2); } // Is it a unit? This could be either self-detection or hitting a different unit. Transform parent = hit.collider.transform.parent; Unit unit = parent ? parent.GetComponent <Unit>() : null; if (unit) { if (unit.Team == parentUnit.GetTeam()) { // If we hit a non-parent teammate, immediately return false. if (unit != parentUnit) { return(false); } else { // Here's the fun part. We have to try to brute-force through the parent unit's colliders for (int i = 0; i < cols.Length; i++) { // Start where the last raycast left off, plus moved in a little bit to make sure we dont hit the same collider again if (Physics.Raycast(hit.point + forward * offset, forward, out hit, checkDistance, gameRules.collisionLayerMask)) { if (parentUnit.printInfo) { Debug.DrawLine(firePos.position, firePos.position + forward * checkDistance, Color.magenta, 2); } parent = hit.collider.transform.parent; unit = parent ? parent.GetComponent <Unit>() : null; if (unit) { if (unit.Team == parentUnit.GetTeam()) { // If we hit a non-parent teammate, immediately return false. if (unit != parentUnit) { return(false); } // If we hit the parent unit, the hit.point from this raycast will be used by the next raycast as a starting point } // teammate 2 else // enemy { // Hit an enemy before an ally unit, no reason to continue checking return(true); } } // unit 2 else { return(false); } } // second raycast } } // parent } // teammate else // enemy { // Hit an enemy before an ally unit, no reason to continue checking return(true); } } // unit else { return(false); } } // first raycast return(true); }
public override void Update(float dt) { List <ITargetable> targets = map.GetTargetsInRange(GetPosition(), info.viewRadius); for (int x = 0; x < targets.Count; x++) { if (targets[x] == this) { continue; } if (currentEnemy == null && targets[x].GetTeam() != GetTeam() && targets[x].IsTargetable(GetTeam())) { currentEnemy = targets[x]; } Vector3 diff = targets[x].GetPosition() - GetPosition(); float length = diff.Length(); diff /= length; if (length < 10 && length != 0) { Move(-diff * dt); } } if (currentEnemy == null) { targetPos = nextTarget; Vector3 diff = nextTarget - GetPosition(); float length = diff.Length(); diff /= length; if (length < 5) { targetID++; if (targetID >= lane.Waypoints.Length) { targetID = lane.Waypoints.Length - 1; } nextTarget = lane.Waypoints[targetID]; } } else { targetPos = currentEnemy.GetPosition(); Vector3 diff = currentEnemy.GetPosition() - GetPosition(); float length = diff.Length(); diff /= length; if (length < info.range) { Attack(currentEnemy); targetPos = GetPosition(); } else { ITargetable test = GetClosestEnemy(); if (test != null) { currentEnemy = test; } } if (currentEnemy.IsDead() || length > info.viewRadius) { currentEnemy = null; } } Vector3 tp; if (evade) { tp = evasionTarget; } else { tp = targetPos; } Vector3 tdiff = tp - GetPosition(); float tlength = tdiff.Length(); tdiff /= tlength; if (tlength > 0) { Vector3 predictedPosition = GetPosition() + tdiff * info.movespeed * 0.5f; if (map.InCollision(predictedPosition)) { evade = true; ICollidable collider = map.GetCollider(predictedPosition); if (collider != null) { Vector3 vertex = collider.Bounds.GetEdgeToCircumvent(GetPosition(), tp); Vector3 dir = vertex - collider.Bounds.Center; dir /= dir.Length(); evasionTarget = vertex + dir * Size; } } Move(tdiff * info.movespeed * dt); } if (evade && tlength < 1) { evade = false; } base.Update(dt); }
public bool CanAttack(ITargetable target) { Vector3 diff = target.GetPosition() - GetPosition(); return atkCooldown < 0 && diff.LengthSquared() < info.range*info.range; }
public bool CanAttack(ITargetable target) { Vector3 diff = target.GetPosition() - GetPosition(); return(atkCooldown < 0 && diff.LengthSquared() < info.range * info.range); }
/// <summary> /// Takes into account how this turret type deals damage to optimize aiming. /// </summary> /// <returns></returns> protected virtual Vector3 CalcAdjDirection(ITargetable targ) { return((targ.GetPosition() - transform.position).normalized); }
public bool InRange(ITargetable target) { return (this.position - target.GetPosition()).Length() < info.range + this.GetSize()/2 + target.GetSize()/2; }
public bool InRange(ITargetable target) { return((this.position - target.GetPosition()).Length() < info.range + this.GetSize() / 2 + target.GetSize() / 2); }