public override void DeployCommand(DVector3 position) { if (!buildInProgress) { return; } if (currentMode != BuildMode.BUILD_THEN_PLACE) { return; } if (remainingTime > 0) { return; } position = new DVector3(position.x, World.current.map.Height(position), position.z); if (!CheckBuildPlacement(buildingWhat, position)) { return; } World.current.Instantiate(buildables[buildingWhat], entity.team, position); buildInProgress = false; }
public bool CheckBuildPlacement(int id, DVector3 position) { // Eugh. Poke around in the prototype for the collider (if any). var radius = (DReal)0; var proto = World.current.entityPrototypes[buildables[id]]; foreach (var cproto in proto.components) { if (cproto.kind == "Collider") { radius = DReal.Parse(cproto.data["radius"]); } } if (World.current.FindEntitiesWithinRadius(position, radius * 2).Any()) { return(false); } // Must be within a build radius. foreach (var ent in World.current.entities.Where(e => e.team == entity.team)) { var br = ent.GetComponent <BuildRadius>(); if (br != null && br.Contains(position, radius)) { return(true); } } return(false); }
// c (+0,+1) d (+1,+1) // +--x-------+ // | | icd | Interpolate between a and b, producing iab. // | x | Interpolate between c and d, producing icd. // | | i | Interpolate between iab and icd, producing the interpolated result. // | | | // | | iab | // +--x-------+ // a (+0,+0) b (+1,+0) public static DVector3 BilinearLerp(DVector3 a, DVector3 b, DVector3 c, DVector3 d, DReal x, DReal y) { var iab = Lerp(a, b, x); var icd = Lerp(c, d, x); return(Lerp(iab, icd, y)); }
public override void DeployCommand(DVector3 position) { World.current.Instantiate(deployPrototype, entity.team, entity.position); entity.Destroy(); }
public void BuildCommand(int id, DVector3 position) { position = World.current.map.WrapPosition(position); foreach (var c in components) { c.BuildCommand(id, position); } }
public void SendDeployCommand(int eid, Game.DVector3 point) { var message = new NetworkMessage(NetworkMessage.Type.CommandDeploy); message.entityId = eid; message.position = point; SendMessageToServer(message); }
public void DeployCommand(DVector3 position) { position = World.current.map.WrapPosition(position); foreach (var c in components) { c.DeployCommand(position); } }
public void SendBuildCommand(int eid, int buildId, Game.DVector3 point) { var message = new NetworkMessage(NetworkMessage.Type.CommandBuild); message.entityId = eid; message.buildId = buildId; message.position = point; SendMessageToServer(message); }
public override void MoveCommand(DVector3 position) { if (motor != null) { motor.MoveTo(position); } attackTarget = null; passiveAttackTarget = null; }
public Entity(int team, DVector3 position, EntityPrototype prototype) { this.eid = World.current.RegisterEntity(this); this.team = team; this.position = position; this.isAlive = true; this.prototype = prototype; this.modelName = prototype.name; }
public Entity(int team, DVector3 position, string modelName) { this.eid = World.current.RegisterEntity(this); this.team = team; this.position = position; this.modelName = modelName; this.isAlive = true; this.prototype = null; }
// Cast a line from A to B, checking for collisions with other entities. public IEnumerable <LineCastResult> LineCastAll(DVector3 start, DVector3 end, int ignoreTeam = -1) { var start2d = new DVector2(start.x, start.z); var end2d = new DVector2(end.x, end.z); foreach (Collider c in colliders) { if (c.entity.team == ignoreTeam) { continue; } var position2d = new DVector2(c.entity.position.x, c.entity.position.z); DVector2 result; // FIXME: Need to adjust positions to correct for wrap. // FIXME: Some cases still not handled properly. // // _______________ // | / | // ---X----------- // / // / // O // / // / // Circle intersects at O, which is a miss, but a real intersect happens at X. if (Utility.IntersectLineCircle(position2d, c.radius, start2d, end2d, out result)) { // Possible hit, work out the correct 3D position at the intersect. var result3d = new DVector3(result.x, start.y, result.y); var a = result3d - start; var bhat = (end - start).normalized; var ab = DVector3.Dot(a, bhat); var intersectPoint = start + bhat * ab; var height = intersectPoint.y; var bottom = c.entity.position.y; var top = bottom + c.height; Logger.Log("result3d: {0} a: {1} bhat: {2} ab: {3} height: {4} bottom: {5} top:{6}", result3d, a, bhat, ab, height, bottom, top); DebugExtension.DebugPoint((UnityEngine.Vector3)intersectPoint, UnityEngine.Color.blue, 10, 10); UnityEngine.Debug.DrawLine((UnityEngine.Vector3)start, (UnityEngine.Vector3)end, UnityEngine.Color.green, 10); UnityEngine.Debug.DrawLine((UnityEngine.Vector3)start, (UnityEngine.Vector3)result3d, UnityEngine.Color.green, 10); if (bottom <= height && height <= top) { var r = new LineCastResult(); r.entity = c.entity; r.position = intersectPoint; yield return(r); } } } }
public ProjectileWeapon(Entity entity, ComponentPrototype proto) : base(entity) { projectile = proto.data["projectile"]; range = DReal.Parse(proto.data["range"]); fireRate = DReal.Parse(proto.data["fireRate"]); randomOffset = new DVector3(DReal.Parse(proto.data["randomOffsetX"]), DReal.Parse(proto.data["randomOffsetY"]), DReal.Parse(proto.data["randomOffsetZ"])); fireTime = 0; }
public void FireAt(Entity target) { if (fireTime > 0) { return; } var dist = entity.Range(target); if (dist > range) { return; } var target_position = target.position; // Aim for the middle. var target_collider = target.GetComponent <Collider>(); if (target_collider != null) { target_position += new DVector3(0, target_collider.height / 2, 0); } var projectile_spawn = entity.position; if (collider != null) { // Spawn from front middle of the collider. projectile_spawn += new DVector3(0, collider.height / 2, 0); projectile_spawn += entity.faceDirection * collider.radius; } // Offset the origin slightly to make it less repetative. projectile_spawn += new DVector3(randomOffset.x * World.current.RandomRange(-1, 1), randomOffset.y * World.current.RandomRange(-1, 1), randomOffset.z * World.current.RandomRange(-1, 1)); var dir = World.current.map.Direction(projectile_spawn, target_position); fireTime = fireRate; var ent = World.current.Instantiate(projectile, entity.team, projectile_spawn); var proj = ent.GetComponent <Projectile>(); if (proj != null) { proj.spawner = entity; proj.target = target_position; } World.current.eventListener.Animate(entity, "Fire"); }
public Entity LineCast(DVector3 start, DVector3 end, out DVector3 hitPosition, int ignoreTeam = -1) { var result = LineCastAll(start, end, ignoreTeam) .OrderBy(r => map.Distance(start, r.position)) .FirstOrDefault(); if (result == null) { hitPosition = new DVector3(0, 0, 0); return(null); } hitPosition = result.position; return(result.entity); }
public override bool Equals(System.Object obj) { // If parameter is null return false. if (obj == null) { return(false); } // If parameter cannot be cast to Point return false. DVector3 p = (DVector3)obj; // Return true if the fields match: return(this == p); }
public IEnumerable <Entity> FindEntitiesWithinRadius(DVector3 position, DReal radius, int ignoreTeam = -1) { foreach (Collider c in colliders) { if (c.entity.team == ignoreTeam) { continue; } var dist = map.Distance(c.entity.position, position); if (dist < radius + c.radius) { yield return(c.entity); } } }
public DReal Height(DVector3 position) { var ix = (int)position.x; var iz = (int)position.z; // Corner heights. var ha = RawHeight(ix, iz); var hb = RawHeight(ix + 1, iz); var hc = RawHeight(ix, iz + 1); var hd = RawHeight(ix + 1, iz + 1); // Interpolation offsets. var tx = position.x - ix; var tz = position.z - iz; return(DReal.BilinearLerp(ha, hb, hc, hd, tx, tz)); }
public DVector3 Normal(DVector3 position) { var ix = (int)position.x; var iz = (int)position.z; // Corner normals. var ha = RawNormal(ix, iz); var hb = RawNormal(ix + 1, iz); var hc = RawNormal(ix, iz + 1); var hd = RawNormal(ix + 1, iz + 1); // Interpolation offsets. var tx = position.x - ix; var tz = position.z - iz; return(DVector3.BilinearLerp(ha, hb, hc, hd, tx, tz).normalized); }
public DVector3 RandomSpawnPosition(DReal min, DReal max) { for (var attempt = 0; attempt < 100; attempt += 1) { var angle = World.current.RandomValue() * 360; var radius = World.current.RandomRange(min, max); var x = this.position.x + DReal.Cos(angle) * radius; var z = this.position.z + DReal.Sin(angle) * radius; var height = World.current.map.Height(new DVector3(x, 0, z)); var p = new DVector3(x, height, z); if (World.current.navigation.Reachability(this.position) == World.current.navigation.Reachability(p)) { return(p); } } UnityEngine.Debug.Log("Failed to generate random position."); return(this.position); }
IEnumerable <DVector3> neighbors(DVector3 point) { yield return(map.WrapPosition(point + new DVector3(0, 0, +1) * granularity)); yield return(map.WrapPosition(point + new DVector3(0, 0, -1) * granularity)); yield return(map.WrapPosition(point + new DVector3(+1, 0, 0) * granularity)); yield return(map.WrapPosition(point + new DVector3(-1, 0, 0) * granularity)); yield return(map.WrapPosition(point + new DVector3(+1, 0, +1) * granularity)); yield return(map.WrapPosition(point + new DVector3(+1, 0, -1) * granularity)); yield return(map.WrapPosition(point + new DVector3(-1, 0, +1) * granularity)); yield return(map.WrapPosition(point + new DVector3(-1, 0, -1) * granularity)); }
public override void DeployCommand(DVector3 position) { if (tower != null && tower.isAlive) { return; } if (towerBuildCooldownRemaining > 0) { return; } if (!CheckBuildPlacement(position)) { return; } // TODO: Respect the tower's build mode. tower = World.current.Instantiate(towerPrototype, entity.team, position); towerBuildCooldownRemaining = towerBuildCooldown; }
public bool MoveTo(DVector3 position) { if (currentPath != null && currentPath.Count != 0) { // Try to avoid recomputing path. var dist = World.current.map.Distance(position, currentPath[currentPath.Count - 1]); if (dist < 1) { return(true); } } var newPath = World.current.navigation.BuildPath(entity.position, position); if (newPath == null) { return(false); } currentPath = newPath; return(true); }
// Range to target, adjusted by collider size. public DReal Range(Entity target) { var ent2d = new DVector3(position.x, 0, position.z); var targ2d = new DVector3(target.position.x, 0, target.position.z); var dist = World.current.map.Distance(ent2d, targ2d); var local_collider = GetComponent <Collider>(); if (local_collider != null) { dist -= local_collider.radius; } var target_collider = target.GetComponent <Collider>(); if (target_collider != null) { dist -= target_collider.radius; } return(DReal.Max(0, dist)); }
public override void OnTick() { var p2d = new DVector3(entity.position.x, 0, entity.position.z); var targ = new Game.DVector3(target.x, 0, target.z); var dist = World.current.map.Distance(p2d, targ); var dir = World.current.map.Direction(p2d, targ); if (dist < moveSpeed * World.deltaTime) { entity.position = new DVector3(target.x, entity.position.y, target.z); } else { var d = p2d + dir * moveSpeed * World.deltaTime; entity.position = new DVector3(d.x, entity.position.y, d.z); entity.faceDirection = dir; } var terrainHeight = DReal.Max(0, World.current.map.Height(entity.position)); var wobble = DReal.Sin((World.current.time + wobbleOffset) * wobbleFrequency) * wobbleAmplitude; var targetHeight = terrainHeight + floatOffset + wobble; var height_diff = DReal.Abs(targetHeight - entity.position.y); var newHeight = (DReal)0; if (targetHeight > entity.position.y) { newHeight = entity.position.y + DReal.Min(height_diff, verticalSpeed * World.deltaTime); } else { newHeight = entity.position.y - DReal.Min(height_diff, verticalSpeed * World.deltaTime); } entity.position = new DVector3(entity.position.x, DReal.Max(terrainHeight, newHeight), entity.position.z); }
// Directly examine the map to determine if a tile is passible. bool MapPassable(int x, int z) { for (int xoff = 0; xoff < granularity; xoff += 1) { for (int zoff = 0; zoff < granularity; zoff += 1) { var pos = new DVector3(x + xoff + DReal.Half, 0, z + zoff + DReal.Half); var normal = map.Normal(pos); var up = new DVector3(0, 1, 0); var slope = DVector3.Dot(normal, up); if (slope < slopeLimit) { // Too sloped. return(false); } if (map.Height(pos) < 0) { // Underwater. return(false); } } } return(true); }
public DVector3 WrappedVectorSub(DVector3 lhs, DVector3 rhs) { var dx = lhs.x - rhs.x; var dy = lhs.y - rhs.y; var dz = lhs.z - rhs.z; if (dx > width / 2) { dx = dx - width; } else if (dx < -width / 2) { dx = dx + width; } if (dz > depth / 2) { dz = dz - depth; } else if (dz < -depth / 2) { dz = dz + depth; } return(new DVector3(dx, dy, dz)); }
public override void MoveCommand(DVector3 position) { is_idle = true; motor.MoveTo(position); }
public bool Contains(DVector3 point, DReal thing_radius) { var dist = World.current.map.Distance(point, entity.position); return(dist < radius + thing_radius); }
void DoFire(Game.DVector3 targetPoint, Game.DVector3 origin) { Debug.Log("Firing at " + targetPoint + " from " + origin); var dist = navMesh.map.Distance(new Game.DVector3((Game.DReal)origin.x, 0, (Game.DReal)origin.z), new Game.DVector3((Game.DReal)targetPoint.x, 0, (Game.DReal)targetPoint.z)); var dir = navMesh.map.Direction(new Game.DVector3((Game.DReal)origin.x, 0, (Game.DReal)origin.z), new Game.DVector3((Game.DReal)targetPoint.x, 0, (Game.DReal)targetPoint.z)); Debug.Log("Distance to target is " + dist); Debug.DrawRay((Vector3)origin, (Vector3)(dir * dist), Color.white, 10.0f); // Walk the line to check for collisions against the terrain. // ### Walking the projectile's whole path feels dubious for performance... // At least it only needs to be done once. Line/terrain intersect algorithms? // This computes X, the highest point of the arc (actually triangle) to clear the terrain. // X // / \ // / \ // / t\ // / tt \ // /t ttt \ // / t tttt t \ // / tttttttttt \ // Actual rendering uses an arc that passes through X to look nice, and the projectile travel // time is computed as though the line was flat. var position = origin; var midpoint = dist / 2; var angle = (Game.DReal) 0; var intesects_terrain = false; for (var offset = (Game.DReal) 0; offset < dist; offset += projSpeed * timeStep) { var old = position; var next_offset = offset + projSpeed * timeStep; if (next_offset >= dist) { break; } position += dir * projSpeed * timeStep; var terrain_height = navMesh.map.Height(position); if (terrain_height > position.y) { Debug.DrawLine((Vector3)old, (Vector3)position, Color.red, 10.0f, false); intesects_terrain = true; if (offset > midpoint) { angle = Game.DReal.Max(angle, Game.DReal.Atan2(terrain_height - position.y + 1, dist - offset)); } else { angle = Game.DReal.Max(angle, Game.DReal.Atan2(terrain_height - position.y + 1, offset)); } } } if (intesects_terrain) { Debug.Log("Intersect angle: " + Game.DReal.Degrees(angle) + " cos: " + Game.DReal.Cos(angle)); var foo = dir * midpoint; var leg = Game.DReal.Half * dist * ((Game.DReal) 1 / Game.DReal.Cos(angle)); var height = Game.DReal.Sqrt((4 * leg * leg - dist * dist) / 4); Debug.Log("Height: " + height); var middle = new Game.DVector3(foo.x, foo.y + height, foo.z); Debug.DrawLine((Vector3)origin, (Vector3)(origin + middle), Color.blue, 10.0f, false); Debug.DrawLine((Vector3)(origin + middle), (Vector3)targetPoint, Color.blue, 10.0f, false); } }