예제 #1
0
        //helper function to determine all viable snap candidates given an actor and a starting position
        // will automatically reject candidates outside the configured min snap offset
        // will also automatically weight the previous frame's results higher to reduce jitter between two close snap points
        private void AddToCandidates(GameThing thing, Vector3 snapFromPosition, int sourceIndex, ref List <CandidateConnection> snapCandidates)
        {
            //loop over all game things looking for pipes
            for (int i = 0; i < InGame.inGame.gameThingList.Count; i++)
            {
                GameActor actor = InGame.inGame.gameThingList[i] as GameActor;

                if (actor != null && actor.Movement != null && actor != (thing as GameActor))
                {
                    if (actor.Chassis != null && actor.Chassis is PipeChassis)
                    {
                        //found a pipe that isn't ourself, look for candidates
                        PipeChassis targetPipe = actor.Chassis as PipeChassis;

                        List <PipeConnection> potentialSnapPoints = GenerateConnections(actor, actor.Movement.Position);

                        //weight each candidate based on how far away it is - if too far, reject it completely
                        foreach (PipeConnection nextSnapPoint in potentialSnapPoints)
                        {
                            Vector3 snapVector = nextSnapPoint.SourcePos - snapFromPosition;
                            snapVector.Z = 0.0f;

                            float distance = snapVector.Length();
                            //if distance is in max offset or, if it's exactly where we snapped to last time, allow for double the radius to consider it valid
                            if (distance <= kMaxSnapOffset * Parent.ReScale ||
                                (m_bIsSnapped && m_lastSnapSourceIndex == sourceIndex && distance < kMaxSnapOffset * Parent.ReScale * 2.0f))
                            {
                                float weight     = 1.0f - MathHelper.Clamp(distance / kMaxSnapOffset, 0.0f, 1.0f);
                                bool  retainSnap = false;

                                //special case: were we previously snapped to this exact target, from the same source?
                                // if so, add some weight - we'd prefer to stay in place
                                if (m_bIsSnapped && m_lastSnapSourceIndex == sourceIndex)
                                {
                                    float distanceToLastSnapped = (m_lastSnapTarget - nextSnapPoint.SourcePos).Length();
                                    if (distanceToLastSnapped < 0.001f)
                                    {
                                        weight    += 1.0f;
                                        retainSnap = true;
                                    }
                                }

                                //found a candidate, add it to the lsit
                                CandidateConnection newCandidate = new CandidateConnection {
                                    SourceConnectionIndex = sourceIndex,
                                    SnapToPosition        = nextSnapPoint.SourcePos,
                                    UpDir          = nextSnapPoint.SourceUpDir,
                                    CenterPosition = actor.Movement.Position,
                                    Weight         = weight,
                                    RetainSnap     = retainSnap
                                };
                                snapCandidates.Add(newCandidate);
                            }
                        }
                    }
                }
            }
        }
예제 #2
0
        //helper function that, given an actor and a starting position, will generate valid outgoing pipe connections
        private List <PipeConnection> GenerateConnections(GameActor actor, Vector3 fromPosition)
        {
            List <PipeConnection> connections = new List <PipeConnection>();

            PipeChassis chassis = actor.Chassis as PipeChassis;

            if (chassis == null)
            {
                return(connections);
            }

            //determine modified direction vectors based on rotation
            Matrix rotationMat = Matrix.CreateRotationY(chassis.m_terrainPitch) * //rotation due to pitch from terrain in X (rotated around Y)
                                 Matrix.CreateRotationX(-chassis.m_terrainRoll) * //rotation due to roll from terrain in Y (rotated around X)
                                 Matrix.CreateRotationZ(chassis.m_snappedYaw);    //normal rotation due to direction facing

            Vector3 facingDir = Vector3.TransformNormal(new Vector3(1.0f, 0.0f, 0.0f), rotationMat);

            facingDir.Normalize();
            Vector3 rightDir = Vector3.TransformNormal(new Vector3(0.0f, -1.0f, 0.0f), rotationMat);

            rightDir.Normalize();
            Vector3 upDir = Vector3.TransformNormal(new Vector3(0.0f, 0.0f, 1.0f), rotationMat);

            upDir.Normalize();

            //from those modified direction vectors, determine potential snap points
            Vector3 forwardPos  = fromPosition + facingDir * kGridSize * actor.ReScale;
            Vector3 backwardPos = fromPosition - facingDir * kGridSize * actor.ReScale;
            Vector3 rightPos    = fromPosition + rightDir * kGridSize * actor.ReScale;
            Vector3 leftPos     = fromPosition - rightDir * kGridSize * actor.ReScale;

            //add connections based on pipe type
            PipeConnection nextConnection;

            switch (chassis.PipeType)
            {
            case PipeTypeEnum.PipeStraight:

                //forward
                nextConnection = new PipeConnection {
                    SourcePos = forwardPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);

                //backward
                nextConnection = new PipeConnection {
                    SourcePos = backwardPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);
                break;

            case PipeTypeEnum.PipeCross:

                //forward
                nextConnection = new PipeConnection {
                    SourcePos = forwardPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);

                //backward
                nextConnection = new PipeConnection {
                    SourcePos = backwardPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);

                //left
                nextConnection = new PipeConnection {
                    SourcePos = leftPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);

                //right
                nextConnection = new PipeConnection {
                    SourcePos = rightPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);
                break;

            case PipeTypeEnum.PipeCorner:

                //backward
                nextConnection = new PipeConnection {
                    SourcePos = backwardPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);

                //right
                nextConnection = new PipeConnection {
                    SourcePos = rightPos, SourceUpDir = upDir
                };
                connections.Add(nextConnection);
                break;
            }

            return(connections);
        }