-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Spotlight Turret. * Used new turret sprite, credit: @Lobstrex (Lob)#5692 * Moved AimShootLifeProcessor.cs to content. * Update Submodule Try 2.
- Loading branch information
Showing
9 changed files
with
255 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using SS14.Server.AI; | ||
using SS14.Server.GameObjects; | ||
using SS14.Server.Interfaces.GameObjects; | ||
using SS14.Shared.Interfaces.GameObjects; | ||
using SS14.Shared.Interfaces.GameObjects.Components; | ||
using SS14.Shared.Interfaces.Physics; | ||
using SS14.Shared.Interfaces.Timing; | ||
using SS14.Shared.IoC; | ||
using SS14.Shared.Maths; | ||
|
||
namespace Content.Server.AI | ||
{ | ||
/// <summary> | ||
/// The object stays stationary. The object will periodically scan for *any* life forms in its radius, and engage them. | ||
/// The object will rotate itself to point at the locked entity, and if it has a weapon will shoot at the entity. | ||
/// </summary> | ||
[AiLogicProcessor("AimShootLife")] | ||
class AimShootLifeProcessor : AiLogicProcessor | ||
{ | ||
private readonly ICollisionManager _physMan; | ||
private readonly IServerEntityManager _entMan; | ||
private readonly IGameTiming _timeMan; | ||
|
||
private readonly List<IEntity> _workList = new List<IEntity>(); | ||
|
||
private const float MaxAngSpeed = (float) (Math.PI / 2); // how fast our turret can rotate | ||
private const float ScanPeriod = 1.0f; // tweak this for performance and gameplay experience | ||
private float _lastScan; | ||
|
||
private IEntity _curTarget; | ||
|
||
/// <summary> | ||
/// Creates an instance of this LogicProcessor. | ||
/// </summary> | ||
public AimShootLifeProcessor() | ||
{ | ||
_physMan = IoCManager.Resolve<ICollisionManager>(); | ||
_entMan = IoCManager.Resolve<IServerEntityManager>(); | ||
_timeMan = IoCManager.Resolve<IGameTiming>(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override void Update(float frameTime) | ||
{ | ||
if (SelfEntity == null) | ||
return; | ||
|
||
DoScanning(); | ||
DoTracking(frameTime); | ||
} | ||
|
||
private void DoScanning() | ||
{ | ||
var curTime = _timeMan.CurTime.TotalSeconds; | ||
if (curTime - _lastScan > ScanPeriod) | ||
{ | ||
_lastScan = (float) curTime; | ||
_curTarget = FindBestTarget(); | ||
} | ||
} | ||
|
||
private void DoTracking(float frameTime) | ||
{ | ||
// not valid entity to target. | ||
if (_curTarget == null || !_curTarget.IsValid()) | ||
{ | ||
_curTarget = null; | ||
return; | ||
} | ||
|
||
// point me at the target | ||
var tarPos = _curTarget.GetComponent<ITransformComponent>().WorldPosition; | ||
var myPos = SelfEntity.GetComponent<ITransformComponent>().WorldPosition; | ||
|
||
var curDir = SelfEntity.GetComponent<IServerTransformComponent>().LocalRotation.ToVec(); | ||
var tarDir = (tarPos - myPos).Normalized; | ||
|
||
var fwdAng = Vector2.Dot(curDir, tarDir); | ||
|
||
Vector2 newDir; | ||
if (fwdAng < 0) // target behind turret, just rotate in a direction to get target in front | ||
{ | ||
var curRight = new Vector2(-curDir.Y, curDir.X); // right handed coord system | ||
var rightAngle = Vector2.Dot(curDir, new Vector2(-tarDir.Y, tarDir.X)); // right handed coord system | ||
var rotateSign = -Math.Sign(rightAngle); | ||
newDir = curDir + curRight * rotateSign * MaxAngSpeed * frameTime; | ||
} | ||
else // target in front, adjust to aim at him | ||
{ | ||
newDir = MoveTowards(curDir, tarDir, MaxAngSpeed, frameTime); | ||
} | ||
|
||
SelfEntity.GetComponent<IServerTransformComponent>().LocalRotation = new Angle(newDir); | ||
|
||
if (fwdAng > -0.9999) | ||
{ | ||
// TODO: shoot gun, prob need aimbot because entity rotation lags behind moving target | ||
} | ||
} | ||
|
||
private IEntity FindBestTarget() | ||
{ | ||
// "best" target is the closest one with LOS | ||
|
||
var ents = _entMan.GetEntitiesInRange(SelfEntity, VisionRadius); | ||
var myTransform = SelfEntity.GetComponent<IServerTransformComponent>(); | ||
var maxRayLen = VisionRadius * 2.5f; // circle inscribed in square, square diagonal = 2*r*sqrt(2) | ||
|
||
_workList.Clear(); | ||
foreach (var entity in ents) | ||
{ | ||
// filter to "people" entities (entities with controllers) | ||
if (!entity.HasComponent<IMoverComponent>()) | ||
continue; | ||
|
||
// build the ray | ||
var dir = entity.GetComponent<TransformComponent>().WorldPosition - myTransform.WorldPosition; | ||
var ray = new Ray(myTransform.WorldPosition, dir.Normalized); | ||
|
||
// cast the ray | ||
var result = _physMan.IntersectRay(ray, maxRayLen); | ||
|
||
// add to visible list | ||
if (result.HitEntity == entity) | ||
_workList.Add(entity); | ||
} | ||
|
||
// get closest entity in list | ||
var closestEnt = GetClosest(myTransform.WorldPosition, _workList); | ||
|
||
// return closest | ||
return closestEnt; | ||
} | ||
|
||
private static IEntity GetClosest(Vector2 origin, IEnumerable<IEntity> list) | ||
{ | ||
IEntity closest = null; | ||
var minDistSqrd = float.PositiveInfinity; | ||
|
||
foreach (var ent in list) | ||
{ | ||
var pos = ent.GetComponent<ITransformComponent>().WorldPosition; | ||
var distSqrd = (pos - origin).LengthSquared; | ||
|
||
if (distSqrd > minDistSqrd) | ||
continue; | ||
|
||
closest = ent; | ||
minDistSqrd = distSqrd; | ||
} | ||
|
||
return closest; | ||
} | ||
|
||
private static Vector2 MoveTowards(Vector2 current, Vector2 target, float speed, float delta) | ||
{ | ||
var maxDeltaDist = speed * delta; | ||
var a = target - current; | ||
var magnitude = a.Length; | ||
if (magnitude <= maxDeltaDist) | ||
{ | ||
return target; | ||
} | ||
|
||
return current + a / magnitude * maxDeltaDist; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using SS14.Server.Interfaces.GameObjects; | ||
using SS14.Shared.Interfaces.Map; | ||
using SS14.Shared.IoC; | ||
using SS14.Shared.Map; | ||
using SS14.Shared.Maths; | ||
|
||
namespace Content.Server.Placement | ||
{ | ||
/// <summary> | ||
/// Helper function for spawning more complex multi-entity structures | ||
/// </summary> | ||
public static class SpawnHelpers | ||
{ | ||
/// <summary> | ||
/// Spawns a spotlight ground turret that will track any living entities in range. | ||
/// </summary> | ||
/// <param name="grid"></param> | ||
/// <param name="localPosition"></param> | ||
public static void SpawnLightTurret(IMapGrid grid, Vector2 localPosition) | ||
{ | ||
var entMan = IoCManager.Resolve<IServerEntityManager>(); | ||
var tBase = entMan.SpawnEntity("TurretBase"); | ||
tBase.GetComponent<IServerTransformComponent>().LocalPosition = new LocalCoordinates(localPosition, grid); | ||
|
||
var tTop = entMan.SpawnEntity("TurretTopLight"); | ||
tTop.GetComponent<IServerTransformComponent>().LocalPosition = new LocalCoordinates(localPosition, grid); | ||
tTop.GetComponent<IServerTransformComponent>().AttachParent(tBase); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
- type: entity | ||
id: TurretBase | ||
name: Turret Base | ||
components: | ||
- type: Transform | ||
- type: Clickable | ||
- type: BoundingBox | ||
- type: Sprite | ||
drawdepth: FloorPlaceable | ||
sprites: | ||
- TurrBase | ||
|
||
- type: entity | ||
id: TurretTopGun | ||
name: Turret (Gun) | ||
components: | ||
- type: Transform | ||
- type: Clickable | ||
- type: BoundingBox | ||
- type: Sprite | ||
drawdepth: WallMountedItems | ||
sprites: | ||
- TurrTop | ||
- type: AiController | ||
logic: AimShootLife | ||
vision: 6.0 | ||
|
||
- type: entity | ||
id: TurretTopLight | ||
name: Turret (Light) | ||
components: | ||
- type: Transform | ||
- type: Clickable | ||
- type: BoundingBox | ||
- type: Sprite | ||
drawdepth: WallMountedItems | ||
sprites: | ||
- TurrLamp | ||
- type: AiController | ||
logic: AimShootLife | ||
vision: 6.0 | ||
- type: PointLight | ||
radius: 512 | ||
mask: flashlight_mask | ||
autoRot: true | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Submodule engine
updated
from fc3618 to 93c7aa