private void PositionCameraAtNode(TrackNode node) { _cameraNode = node; _camera.Position = Engine.Instance.Random.Next() % 2 == 0 ? _cameraNode.GetLeftBoundary() : _cameraNode.GetRightBoundary(); _camera.Position = _camera.Position + new Vector3(0, Engine.Instance.Random.Next(15, 50), 0); }
public void PlaceOnTrack(Track t, TrackNode startNode) { Track = t; CurrentNode = startNode; Position = Vector3.Lerp(startNode.GetLeftVerge(), startNode.GetRightVerge2(), 0.5f); //center of node }
private void FollowTrackOrientation(TrackNode node, TrackNode nextNode) { var closestPoint1 = Utility.GetClosestPointOnLine(node.GetLeftBoundary(), node.GetRightBoundary(), Position); var closestPoint2 = Utility.GetClosestPointOnLine(nextNode.GetLeftBoundary(), nextNode.GetRightBoundary(), Position); var dist = Distance2d(closestPoint1, closestPoint2); var carDist = Distance2d(closestPoint1, Position); float ratio = Math.Min(carDist / dist, 1.0f); TrackPosition = CurrentNode.Number + ratio; // if the road is sloping downwards and we have enough speed, unstick from ground if (node.Slope - nextNode.Slope > 50 && Speed > 100 && _isOnGround) { _isOnGround = false; _upVelocity = -0.4f; } if (_isOnGround) { Up = Vector3.Lerp(node.Up, nextNode.Up, ratio); Up = Vector3.Normalize(Up); Direction = Vector3.Cross(Up, Right); Direction.Normalize(); } _currentHeightOfTrack = MathHelper.Lerp(closestPoint1.Y, closestPoint2.Y, ratio); if (_currentHeightOfTrack == -9999) { throw new Exception(); } if (_isOnGround) { var newPosition = Position; newPosition.Y = _currentHeightOfTrack; Position = newPosition; } //GameConsole.WriteLine("height: " + _position.Y, 0); //GameConsole.WriteLine("ratio: " + ratio, 1); }
void ParseTrackNodesBlock(BinaryReader reader) { reader.BaseStream.Position = 2444; //start of node list TrackNode prevNode = null; for (int i = 0; i < 2400; i++) { var node = new TrackNode(); node.Number = Nodes.Count; float vergeScale = 8000; node.DistanceToLeftVerge = reader.ReadByte(); node.DistanceToLeftVerge *= GameConfig.TerrainScale * vergeScale; node.DistanceToRightVerge = reader.ReadByte(); node.DistanceToRightVerge *= GameConfig.TerrainScale * vergeScale; node.DistanceToLeftBarrier = reader.ReadByte(); node.DistanceToLeftBarrier *= GameConfig.TerrainScale * vergeScale; node.DistanceToRightBarrier = reader.ReadByte(); node.DistanceToRightBarrier *= GameConfig.TerrainScale * vergeScale; node.Flag1 = reader.ReadByte(); node.Flag2 = reader.ReadByte(); node.Flag3 = reader.ReadByte(); node.NodeProperty = reader.ReadByte(); // unused trackNodes are filled with zeroes, so stop when we have a node with a zero position if (node.DistanceToLeftVerge == 0 && node.DistanceToRightVerge == 0 && node.DistanceToLeftBarrier == 0 && node.DistanceToRightBarrier == 0) { break; } //Debug.WriteLine("{0},{1},{2},{3}", node.b[0], node.b[1], node.b[2], node.b[3]); node.Position = new Vector3(reader.ReadInt32(), reader.ReadInt32(), -reader.ReadInt32()) * GameConfig.TerrainScale; // Slope is stored as a 2's complement value. Convert it back to signed value Int16 slope = reader.ReadInt16(); //bool msbSet = (slope & (0x1 << 13)) != 0; //if (msbSet) //{ // slope = (short)~slope; // slope++; // slope *= -1; //} if (slope > 0x2000) { slope -= 0x3FFF; } node.Slope = slope; node.Slant = reader.ReadInt16(); //weird slant-A float orientation = (float)reader.ReadInt16(); //convert to signed degrees //0 = forwards, 0x1000 = right, 0x2000 = back, 0x3000 = left, 0x3FFF back to forwards if (orientation > 0x2000) { orientation -= 0x3FFF; } node.Orientation = ((orientation / 0x3FFF) * -360); node.unk1 = reader.ReadBytes(2); node.ZOrientation = reader.ReadInt16(); node.Slant = reader.ReadInt16(); // slant-B node.XOrientation = reader.ReadInt16(); node.unk2 = reader.ReadBytes(2); if (prevNode != null) { prevNode.Next = node; node.Prev = prevNode; } prevNode = node; Nodes.Add(node); } // If this is a circuit track, hook the last node up to the first if (Vector3.Distance(Nodes[0].Position, Nodes[Nodes.Count - 1].Position) > 100) { IsOpenRoad = true; } else { prevNode.Next = Nodes[0]; Nodes[0].Prev = prevNode; } for (int i = 0; i < Nodes.Count - 1; i++) { var node = Nodes[i]; var normal = Vector3.Cross(node.GetRightBoundary() - node.GetLeftBoundary(), node.Next.Position - node.GetLeftBoundary()); node.Up = Vector3.Normalize(normal); } }
// add a driver to the race, placing him in a starting grid public void AddDriver(IDriver d, TrackNode startNode) { d.Vehicle.PlaceOnTrack(Track, startNode); if (d is TrafficDriver) { } else if (d is RacingAIDriver || d is PlayerDriver) { // place on starting grid int lane = (Drivers.Count % 2 == 0 ? AIDriver.MaxVirtualLanes - 1 : 1); if (d is RacingAIDriver) { ((RacingAIDriver)d).VirtualLane = lane; } Vector3 pos = d.Vehicle.CurrentNode.Position; pos.Z -= Drivers.Count * 30; pos.X = Vector3.Lerp(d.Vehicle.CurrentNode.GetLeftVerge2(), d.Vehicle.CurrentNode.GetRightVerge2(), (float)lane / (AIDriver.MaxVirtualLanes)).X; d.Vehicle.Position = pos; } Drivers.Add(d); }
public void Render(Vector3 cameraPosition, TrackNode currentNode) { _skybox.Render(); _effect.View = Engine.Instance.Camera.View; _effect.Projection = Engine.Instance.Camera.Projection; _effect.World = Matrix.Identity; int segmentIndex = currentNode.Number / 4; var startSegment = TerrainSegments[segmentIndex]; var renderedSegments = new List<TerrainSegment>(); Engine.Instance.Device.SetVertexBuffer(TerrainVertexBuffer); _effect.CurrentTechnique.Passes[0].Apply(); Engine.Instance.Device.RasterizerState = RasterizerState.CullNone; Engine.Instance.Device.SamplerStates[0] = GameConfig.WrapSampler; var frustum = new BoundingFrustum(Engine.Instance.Camera.View * Engine.Instance.Camera.Projection); // draw segments from the player vehicle forwards. Stop when a segment is out of view var segment = startSegment; for (int i = 0; i < GameConfig.MaxSegmentRenderCount; i++) { if (segment == null) break; if (frustum.Intersects(segment.BoundingBox)) { RenderSegment(segment); renderedSegments.Add(segment); } else { break; } segment = segment.Next; } // draw segments from the player vehicle backwards. Stop when a segment is out of view segment = startSegment.Prev; for (int i = 0; i < GameConfig.MaxSegmentRenderCount; i++) { if (segment == null) break; if (frustum.Intersects(segment.BoundingBox)) { RenderSegment(segment); renderedSegments.Add(segment); } segment = segment.Prev; } DrawScenery(renderedSegments); if (FenceVertexBuffer != null) { Engine.Instance.Device.SetVertexBuffer(FenceVertexBuffer); _effect.World = Matrix.Identity; _effect.CurrentTechnique.Passes[0].Apply(); Engine.Instance.Device.SamplerStates[0] = GameConfig.WrapSampler; foreach (var renderedSegment in renderedSegments) { DrawFenceStrips(renderedSegment); } } if (GameConfig.DrawDebugInfo) { var node = currentNode; for (int i = 0; i < GameConfig.MaxSegmentRenderCount; i++) { Engine.Instance.GraphicsUtils.AddCube(Matrix.CreateTranslation(node.GetLeftBoundary()), Color.Red); Engine.Instance.GraphicsUtils.AddCube(Matrix.CreateTranslation(node.GetRightBoundary()), Color.Red); Engine.Instance.GraphicsUtils.AddCube(Matrix.CreateTranslation(node.GetLeftVerge()), Color.Blue); Engine.Instance.GraphicsUtils.AddCube(Matrix.CreateTranslation(node.GetRightVerge()), Color.Blue); Engine.Instance.GraphicsUtils.AddCube(Matrix.CreateTranslation(node.Position), Color.Yellow); if (node.Number % TriFile.NbrRowsPerSegment == 0) { Engine.Instance.GraphicsUtils.AddLine(node.GetLeftBoundary(), node.GetRightBoundary(), Color.White); } node = node.Next; if (node == null) break; } GameConsole.WriteLine(String.Format("Position node: {0}, segment: {1}", currentNode.Number, (int)(currentNode.Number / TriFile.NbrRowsPerSegment))); GameConsole.WriteLine(String.Format("Node property: {0}, flags: {1}, {2}, {3}", currentNode.NodeProperty, currentNode.Flag1, currentNode.Flag2, currentNode.Flag3)); } }
public float GetHeightAtPoint(TrackNode node, Vector3 point) { Vector3 a = node.GetLeftBoundary(); Vector3 b = node.GetRightBoundary(); Vector3 c = node.Next.GetRightBoundary(); Vector3 d = node.Next.GetLeftBoundary(); Vector3 hitLoc; float t; Vector3 pos = point; pos.Y += 100; if (Utility.FindRayTriangleIntersection(ref pos, Vector3.Down, 1000f, ref a, ref b, ref c, out hitLoc, out t)) { return hitLoc.Y; } else if (Utility.FindRayTriangleIntersection(ref pos, Vector3.Down, 1000f, ref a, ref c, ref d, out hitLoc, out t)) { return hitLoc.Y; } else { return -9999; } }
public static Vector3 GetRoadOffsetPosition(TrackNode roadNode, float offset) { Vector3 position = roadNode.Position + Utility.RotatePoint(new Vector2(offset, 0), -roadNode.Orientation); return position; }