예제 #1
0
        public void DrawHeightmapFlat(WorldPhysics worldPhysics, Position offset, SortedList <int, Color> heightColorGradient)
        {
            // Constrain rendering to the display bounds
            int startX = Math.Max(worldPhysics.StartX, displayBounds.Left - offset.X);
            int endX   = Math.Min(worldPhysics.EndX, displayBounds.Right - offset.X);

            if (endX <= startX)
            {
                return;                                                        // Off screen
            }
            for (int z = worldPhysics.EndZ - 1; z >= worldPhysics.StartZ; z--) // From back to front of heightmap
            {
                for (int x = startX; x < endX; x++)
                {
                    int height = worldPhysics.GetGroundHeightAt(x, z, WorldPhysics.MaximumHeight, WorldPhysics.MaximumHeight, null);
                    if (height == WorldPhysics.MaximumHeight)
                    {
                        continue;
                    }

                    // Draw top surface
                    DrawPixel(new Position(offset.X + x, 0, offset.Z + z), heightColorGradient.GetColorFromGradient(height + offset.Y));
                }
            }
        }
예제 #2
0
        /// <summary>Get the height of the lowest ground position we can stand at at the given XZ coordinates, in some given Y range.</summary>
        /// <returns>The resulting height, or WorldPhysics.MaximumHeight if it did not fit</returns>
        public static int LowestValidGroundHeight(ref CharacterPhysicsInfo info, WorldPhysics world, int x, int z, int startY, int endY, bool staticOnly = false)
        {
            int startX = x + info.startX;
            int endX   = x + info.endX;

            if (endY > WorldPhysics.MaximumHeight)
            {
                endY = WorldPhysics.MaximumHeight;
            }

            // Repeatedly test the walkable height upwards, until it returns somewhere we are confirmed to fit
            int tryingHeight = startY;
            int resultingHeight;

            do
            {
                resultingHeight = world.GetGroundHeightInXRange(startX, endX, z, tryingHeight, tryingHeight + info.height, info.owner, staticOnly);
                if (resultingHeight <= startY)
                {
                    return(startY);
                }
                if (resultingHeight == tryingHeight)
                {
                    break;
                }
                tryingHeight = resultingHeight;
            }while(resultingHeight < endY);

            if (resultingHeight == tryingHeight && resultingHeight >= startY && resultingHeight < endY)
            {
                return(resultingHeight);
            }

            return(WorldPhysics.MaximumHeight); // <- Failed
        }
예제 #3
0
        public static void TryMoveVertical(ref CharacterPhysicsInfo info, WorldPhysics world, int deltaY, ref Position position, bool staticOnly = false)
        {
            //
            // Move on Y axis first...
            //

            if (deltaY < 0)
            {
                int groundHeight = GroundHeight(ref info, world, position, staticOnly);
                if (position.Y > groundHeight) // Don't move down further if already below ground
                {
                    int newY = position.Y + deltaY;
                    if (newY < groundHeight) // Don't go below ground
                    {
                        position.Y = groundHeight;
                    }
                    else
                    {
                        position.Y = newY;
                    }
                }
            }
            else if (deltaY > 0)
            {
                int startY = position.Y + info.height;
                int endY   = startY + deltaY;
                endY       = world.GetCeilingHeightInXRange(position.X + info.startX, position.X + info.endX, position.Z, startY, endY, info.owner, staticOnly);
                position.Y = endY - info.height;
            }
        }
예제 #4
0
        /// <summary>Get the height of the topmost ground at a given position. Used for generating navigation data. (Eventually replace with a multi-layer heightmap.)</summary>
        public static int TopmostGroundHeight(ref CharacterPhysicsInfo info, WorldPhysics world, int x, int z, bool staticOnly = false)
        {
            int startX = x + info.startX;
            int endX   = x + info.endX;

            // Hack: If we slip in just under the ceiling, we can get the result for the next-highest floor
            //       This is a hack because it depends on knowledge of what GetGroundHeightInXRange is doing
            int minCeiling = WorldPhysics.MaximumHeight + info.height;

            if (world.levelCeiling != null)
            {
                for (int xx = startX; xx < endX; xx++)
                {
                    int c = world.levelCeiling[xx, z];
                    if (c == 0)
                    {
                        continue;
                    }

                    if (c < minCeiling)
                    {
                        minCeiling = c;
                    }
                }
            }

            return(world.GetGroundHeightInXRange(startX, endX, z, minCeiling - info.height, minCeiling, info.owner, staticOnly));
        }
예제 #5
0
        public static int GroundHeight(ref CharacterPhysicsInfo info, WorldPhysics world, Position position, bool staticOnly = false)
        {
            int startX = position.X + info.startX;
            int endX   = position.X + info.endX;

            return(world.GetGroundHeightInXRange(startX, endX, position.Z, position.Y, position.Y + info.height, info.owner, staticOnly));
        }
예제 #6
0
        private static bool MoveStep(ref CharacterPhysicsInfo info, WorldPhysics world, int deltaX, int deltaZ, ref bool groundSnap, ref Position position, bool staticOnly = false)
        {
            int groundHeight = GroundHeight(ref info, world, new Position(position.X + deltaX, position.Y, position.Z + deltaZ), staticOnly);

            // NOTE: This ensures that we cannot get kicked up later on in the method, when we set to groundHeight
            if (position.Y + info.stairStepMaxHeight < groundHeight)
            {
                return(false); // Cannot move up that high
            }
            position.X += deltaX;
            position.Z += deltaZ;

            if (position.Y < groundHeight)
            {
                // TODO: BUG: We need to know if we're going to hit the ceiling by moving upwards here!
                // Do not go below ground
                position.Y = groundHeight;
            }
            else if (groundSnap)
            {
                if (position.Y < groundHeight + info.stairStepMaxHeight)
                {
                    // Snap to the ground if we are nearby
                    position.Y = groundHeight;
                }
                else
                {
                    // We came "off" the ground, stop trying to snap to it
                    groundSnap = false;
                }
            }

            return(true);
        }
예제 #7
0
        // NOTE: Rendering from world heightmap is slow!!
        // NOTE: Much copy-pasted code from normal heightmap rendering
        public void DrawWorldPhysicsXZRegion(WorldPhysics worldPhysics, MaskData xzMask, SortedList <int, Color> heightColorGradient)
        {
            // Constrain rendering to the display bounds
            int startX = Math.Max(worldPhysics.StartX, displayBounds.Left);
            int endX   = Math.Min(worldPhysics.EndX, displayBounds.Right);

            if (endX <= startX)
            {
                return;                                                        // Off screen
            }
            for (int z = worldPhysics.EndZ - 1; z >= worldPhysics.StartZ; z--) // From back to front of heightmap
            {
                for (int x = startX; x < endX; x++)
                {
                    if (!xzMask.GetOrDefault(x, z)) // TODO: Fix up bounds so we never leave this area (and use regular [,] access) - PERF
                    {
                        continue;
                    }

                    int height = worldPhysics.GetGroundHeightAt(x, z, WorldPhysics.MaximumHeight, WorldPhysics.MaximumHeight, null);
                    if (height == WorldPhysics.MaximumHeight)
                    {
                        continue;
                    }

                    int nextHeight = 0; // Height of the next Z-value (row)
                    if (xzMask.GetOrDefault(x, z - 1))
                    {
                        nextHeight = worldPhysics.GetGroundHeightAt(x, z - 1, WorldPhysics.MaximumHeight, WorldPhysics.MaximumHeight, null);
                    }

                    if (nextHeight != WorldPhysics.MaximumHeight && nextHeight > height)
                    {
                        continue; // Next row will cover this one entirely
                    }
                    // Draw top surface
                    const int zTestOffset = 1; // <- The top surface should be "under" any other pixels
                    DrawPixel(new Position(x, height, z), heightColorGradient.GetColorFromGradient(height), zTestOffset);

                    if (nextHeight != WorldPhysics.MaximumHeight && nextHeight == height)
                    {
                        continue; // Next row covers this one's "solid" section
                    }
                    // Draw solidness
                    for (int h = height - 1; h >= 0; h--)
                    {
                        Color c = Color.Lerp(heightColorGradient.GetColorFromGradient(h), Color.Black, 0.6f);
                        DrawPixel(new Position(x, h, z), c);
                    }
                }
            }
        }
예제 #8
0
        public ActionResult Assets(string objectType, string objectId, string resource, string resourceId)
        {
            Response.Headers.Add("Content-type", "application/json");

            switch (objectType.ToLower())
            {
            case "map":
            {
                return(MapPath(objectId, resource, resourceId));
            }

            case "characters":
            {
                return(CharacterPath(objectId, resource, resourceId));
            }

            case "manifest":
            {
                var worldPhysics = new WorldPhysics();
                worldPhysics.gravityVector   = new GravityVector();
                worldPhysics.gravityVector.x = 0;
                worldPhysics.gravityVector.y = -20;
                worldPhysics.gravityVector.z = 0;

                var manifest = new UrlManifest();
                manifest.baseUrl                 = "/game";
                manifest.world                   = worldPhysics;
                manifest.map.baseUrl             = "/stargazer";
                manifest.map.texture             = "/ground.jpg";
                manifest.map.skyBox              = "/skybox";
                manifest.map.heightMap           = "/heightmap";
                manifest.map.physics.friction    = 0.5;
                manifest.map.physics.mass        = 0;
                manifest.map.physics.restitution = 0.8;
                manifest.playerUsername          = this.User.Identity.Name;

                //todo fetch from a manifest db

                return(Json(manifest, JsonRequestBehavior.AllowGet));
            }

            case "campaign":
            {
                var IdAsInt = Convert.ToInt32(objectId);
                return(Json(db.Campaigns.Find(IdAsInt), JsonRequestBehavior.AllowGet));
            }
            }

            return(HttpNotFound());
        }
예제 #9
0
파일: Motion.cs 프로젝트: zcxxv1213/Pixel3D
        public static MotionResult PhysicsStepHorizontal(ref CharacterPhysicsInfo cpi,
                                                         ref Position position, ref ThreeDVelocity velocity,
                                                         bool onGround,
                                                         int coefficientOfRestitution256,
                                                         int groundFriction256,
                                                         WorldPhysics physics)
        {
            MotionResult result = MotionResult.None;

            int newPositionX = velocity.X.Update(position.X);
            int newPositionZ = velocity.Z.Update(position.Z);
            int deltaX       = newPositionX - position.X;
            int deltaZ       = newPositionZ - position.Z;

            if (deltaX != 0)
            {
                if (CharacterPhysics.TryMoveHorizontalDidHitWall(ref cpi, physics, deltaX, 0, onGround, ref position))
                {
                    // Hit wall, bounce:
                    velocity.X.Scale256(-coefficientOfRestitution256);
                    result = MotionResult.HitWall;
                }
            }

            // Z-motion just stops if it hits anything
            if (deltaZ != 0 && CharacterPhysics.TryMoveHorizontalDidHitWall(ref cpi, physics, 0, deltaZ, onGround, ref position))
            {
                velocity.Z.Reset();
                // NOTE: Currently not even bothering to give a hit result, just carry on...
            }

            // TODO: Slope handling for rolling objects

            if (onGround)
            {
                // Friction:
                velocity.X.Scale256(groundFriction256);
                velocity.Z.Scale256(groundFriction256);
            }

            return(result);
        }
예제 #10
0
        public void DrawHeightmapSolid(WorldPhysics worldPhysics, Position offset, SortedList <int, Color> heightColorGradient)
        {
            // Constrain rendering to the display bounds
            int startX = Math.Max(worldPhysics.StartX, displayBounds.Left - offset.X);
            int endX   = Math.Min(worldPhysics.EndX, displayBounds.Right - offset.X);

            if (endX <= startX)
            {
                return;                                                        // Off screen
            }
            for (int z = worldPhysics.EndZ - 1; z >= worldPhysics.StartZ; z--) // From back to front of heightmap
            {
                for (int x = startX; x < endX; x++)
                {
                    int height = worldPhysics.GetGroundHeightAt(x, z, WorldPhysics.MaximumHeight, WorldPhysics.MaximumHeight, null);
                    if (height == WorldPhysics.MaximumHeight)
                    {
                        continue;
                    }

                    int nextHeight = worldPhysics.GetGroundHeightAt(x, z - 1, WorldPhysics.MaximumHeight, WorldPhysics.MaximumHeight, null);
                    if (nextHeight != WorldPhysics.MaximumHeight && nextHeight > height)
                    {
                        continue; // Next row will cover this one entirely
                    }
                    // Draw top surface
                    const int zTestOffset = 1; // <- The top surface should be "under" any other pixels
                    DrawPixel(offset + new Position(x, height, z), heightColorGradient.GetColorFromGradient(height + offset.Y), zTestOffset);

                    if (nextHeight != WorldPhysics.MaximumHeight && nextHeight == height)
                    {
                        continue; // Next row covers this one's "solid" section
                    }
                    // Draw solidness
                    for (int h = height + offset.Y - 1; h >= offset.Y; h--)
                    {
                        Color c = Color.Lerp(heightColorGradient.GetColorFromGradient(h), Color.Black, 0.6f);
                        DrawPixel(new Position(offset.X + x, h, offset.Z + z), c);
                    }
                }
            }
        }
예제 #11
0
        /// <summary>Get the height of the level walkable heightmap at this position, if it is flat, otherwise WorldPhysics.MaximumHeight</summary>
        public static int LevelOnlyFlatGround(ref CharacterPhysicsInfo info, WorldPhysics world, int x, int z)
        {
            if (world.levelHeightmap == null)
            {
                return(WorldPhysics.MaximumHeight);
            }

            int startX = x + info.startX;
            int endX   = x + info.endX;

            int h = world.levelHeightmap[startX, z];

            for (int xx = startX + 1; xx < endX; xx++)
            {
                int c = world.levelHeightmap[xx, z];
                if (c != h)
                {
                    return(WorldPhysics.MaximumHeight);
                }
            }

            return(h);
        }
예제 #12
0
        public static bool DoLemmingsMotion(ref CharacterPhysicsInfo info, WorldPhysics world, int inputX, int inputZ, int deltaX, int deltaZ, bool groundSnap, bool wallSlide, ref Position position)
        {
            Debug.Assert(Math.Abs(inputX) <= 1 && Math.Abs(inputZ) <= 1);
            bool resultX = true, resultZ = true;

            // WARNING: Delicate copy-paste code ahead (for each direction: X+, X-, Z+, Z-)

            while (deltaX > 0)
            {
                if (MoveStep(ref info, world, 1, 0, ref groundSnap, ref position))
                {
                    deltaX--;
                }
                else if (wallSlide) // Move failed, try wall-slide
                {
                    if (inputX > 0 && inputZ <= 0 && MoveStep(ref info, world, 1, -1, ref groundSnap, ref position))
                    {
                        deltaX--;
                        if (deltaZ < 0)
                        {
                            deltaZ++;
                        }
                        else if (deltaX > 0)
                        {
                            deltaX--;
                        }
                    }
                    else if (inputX > 0 && inputZ >= 0 && MoveStep(ref info, world, 1, 1, ref groundSnap, ref position))
                    {
                        deltaX--;
                        if (deltaZ > 0)
                        {
                            deltaZ--;
                        }
                        else if (deltaX > 0)
                        {
                            deltaX--;
                        }
                    }
                    else
                    {
                        resultX = false;
                        goto doneX; // Failed to move on the X axis
                    }
                }
                else
                {
                    resultX = false;
                    goto doneX; // Failed to move on the X axis
                }
            }

            while (deltaX < 0)
            {
                if (MoveStep(ref info, world, -1, 0, ref groundSnap, ref position))
                {
                    deltaX++;
                }
                else if (wallSlide) // Move failed, try wall-slide
                {
                    if (inputX < 0 && inputZ <= 0 && MoveStep(ref info, world, -1, -1, ref groundSnap, ref position))
                    {
                        deltaX++;
                        if (deltaZ < 0)
                        {
                            deltaZ++;
                        }
                        else if (deltaX < 0)
                        {
                            deltaX++;
                        }
                    }
                    else if (inputX < 0 && inputZ >= 0 && MoveStep(ref info, world, -1, 1, ref groundSnap, ref position))
                    {
                        deltaX++;
                        if (deltaZ > 0)
                        {
                            deltaZ--;
                        }
                        else if (deltaX < 0)
                        {
                            deltaX++;
                        }
                    }
                    else
                    {
                        resultX = false;
                        goto doneX; // Failed to move on the X axis
                    }
                }
                else
                {
                    resultX = false;
                    goto doneX; // Failed to move on the X axis
                }
            }

doneX:

            while (deltaZ > 0)
            {
                if (MoveStep(ref info, world, 0, 1, ref groundSnap, ref position))
                {
                    deltaZ--;
                }
                else if (wallSlide) // Move failed, try wall-slide
                {
                    if (inputZ > 0 && inputX <= 0 && MoveStep(ref info, world, -1, 1, ref groundSnap, ref position))
                    {
                        deltaZ--;
                        if (deltaX < 0)
                        {
                            deltaX++;
                        }
                        else if (deltaZ > 0)
                        {
                            deltaZ--;
                        }
                    }
                    else if (inputZ > 0 && inputX >= 0 && MoveStep(ref info, world, 1, 1, ref groundSnap, ref position))
                    {
                        deltaZ--;
                        if (deltaX > 0)
                        {
                            deltaX--;
                        }
                        else if (deltaZ > 0)
                        {
                            deltaZ--;
                        }
                    }
                    else
                    {
                        resultZ = false;
                        goto doneZ; // Failed to move on the Z axis
                    }
                }
                else
                {
                    resultZ = false;
                    goto doneZ; // Failed to move on the Z axis
                }
            }

            while (deltaZ < 0)
            {
                if (MoveStep(ref info, world, 0, -1, ref groundSnap, ref position))
                {
                    deltaZ++;
                }
                else if (wallSlide) // Move failed, try wall-slide
                {
                    if (inputZ < 0 && inputX <= 0 && MoveStep(ref info, world, -1, -1, ref groundSnap, ref position))
                    {
                        deltaZ++;
                        if (deltaX < 0)
                        {
                            deltaX++;
                        }
                        else if (deltaZ < 0)
                        {
                            deltaZ++;
                        }
                    }
                    else if (inputZ < 0 && inputX >= 0 && MoveStep(ref info, world, 1, -1, ref groundSnap, ref position))
                    {
                        deltaZ++;
                        if (deltaX > 0)
                        {
                            deltaX--;
                        }
                        else if (deltaZ < 0)
                        {
                            deltaZ++;
                        }
                    }
                    else
                    {
                        resultZ = false;
                        goto doneZ; // Failed to move on the Z axis
                    }
                }
                else
                {
                    resultZ = false;
                    goto doneZ; // Failed to move on the Z axis
                }
            }

doneZ:

            return((resultX && inputX != 0) || (resultZ && inputZ != 0) || (inputX == 0 && inputZ == 0));
        }
예제 #13
0
        public static bool TryMoveHorizontalDidHitWall(ref CharacterPhysicsInfo info, WorldPhysics world, int deltaX, int deltaZ, bool groundSnap, ref Position position, bool staticOnly = false)
        {
            bool hitWall = false;

            //
            // Sweep on XZ plane (slow but safe)...
            //

            while (deltaX > 0)
            {
                deltaX--;
                if (!MoveStep(ref info, world, 1, 0, ref groundSnap, ref position, staticOnly))
                {
                    hitWall = true;
                    goto doneX;
                }
            }
            while (deltaX < 0)
            {
                deltaX++;
                if (!MoveStep(ref info, world, -1, 0, ref groundSnap, ref position, staticOnly))
                {
                    hitWall = true;
                    goto doneX;
                }
            }

doneX:

            while (deltaZ > 0)
            {
                deltaZ--;
                if (!MoveStep(ref info, world, 0, 1, ref groundSnap, ref position, staticOnly))
                {
                    hitWall = true;
                    goto doneZ;
                }
            }
            while (deltaZ < 0)
            {
                deltaZ++;
                if (!MoveStep(ref info, world, 0, -1, ref groundSnap, ref position, staticOnly))
                {
                    hitWall = true;
                    goto doneZ;
                }
            }

doneZ:
            return(hitWall);
        }
예제 #14
0
 public static void TryMove(ref CharacterPhysicsInfo info, WorldPhysics world, Position delta, bool groundSnap, ref Position position, bool staticOnly = false)
 {
     TryMoveVertical(ref info, world, delta.Y, ref position, staticOnly);
     TryMoveHorizontalDidHitWall(ref info, world, delta.X, delta.Z, groundSnap, ref position, staticOnly);
 }
예제 #15
0
파일: Motion.cs 프로젝트: zcxxv1213/Pixel3D
        public static MotionResult PhysicsStepVertical(ref CharacterPhysicsInfo cpi,
                                                       ref Position position, ref ThreeDVelocity velocity,
                                                       ref bool onGround,
                                                       int coefficientOfRestitution256,
                                                       int gravityUp256, int gravityDown256, bool lockVertical,
                                                       WorldPhysics physics, bool groundIsAPit)
        {
            if (lockVertical)
            {
                velocity.Y.Reset();
            }
            else
            {
                if (velocity.Y.Velocity256 > 0) // Moving upwards
                {
                    onGround = false;

                    int startY = position.Y + cpi.height;
                    position.Y = velocity.Y.Update(position.Y, gravityUp256);
                    int endY = position.Y + cpi.height;

                    if (endY > startY)
                    {
                        int ceiling = physics.GetCeilingHeightInXRange(position.X + cpi.startX, position.X + cpi.endX, position.Z, startY, endY, cpi.owner);
                        if (ceiling < endY) // Hit ceiling
                        {
                            position.Y             = ceiling - cpi.height;
                            velocity.Y.Velocity256 = -((velocity.Y.Velocity256 * coefficientOfRestitution256) >> 8); // <- Bounce (fixed-point multiply)
                            return(MotionResult.HitCeiling);
                        }
                    }
                }
                else // Moving downwards
                {
                    int groundHeight = CharacterPhysics.GroundHeight(ref cpi, physics, position);

                    if (position.Y > groundHeight)
                    {
                        onGround = false;               // we came off the ground
                    }
                    else if (position.Y < groundHeight) // TODO: This needs some rethinking (added to let separation do its thing)
                    {
                        onGround = true;                // we are embedded in the ground (we may start physics in this state, if we are put here by teleport/animation)
                    }
                    else if (position.Y == groundHeight && velocity.Y.Velocity256 == 0)
                    {
                        onGround = true; // we were gently placed on the ground (don't trigger OnHitGround)
                    }
                    if (!onGround)
                    {
                        position.Y = velocity.Y.Update(position.Y, gravityDown256);

                        if (position.Y <= groundHeight) // Hit the ground
                        {
                            position.Y = groundHeight;

                            if (groundHeight == 0 && groundIsAPit)
                            {
                                velocity = new ThreeDVelocity();
                                return(MotionResult.HitBottomOfPit);
                            }
                            else if (velocity.Y.Velocity256 > -128) // <- Kill velocity of we're moving too slowly downwards (start rolling)
                            {
                                onGround = true;
                                velocity.Y.Reset();
                            }
                            else
                            {
                                onGround = false;
                                velocity.Y.Scale256(-coefficientOfRestitution256);
                                velocity.X.Scale256(coefficientOfRestitution256);
                                velocity.Z.Scale256(coefficientOfRestitution256);
                            }

                            return(MotionResult.HitGround);
                        }
                    }
                }
            }

            return(MotionResult.None);
        }
예제 #16
0
 /// <summary>Determine whether a position is on (or inside) the ground at a given position.</summary>
 public static bool OnGround(ref CharacterPhysicsInfo info, WorldPhysics world, Position position)
 {
     return(position.Y <= GroundHeight(ref info, world, position));
 }
예제 #17
0
파일: Actor.cs 프로젝트: rosebud667/Pixel3D
        /// <summary>Get the Y position of the ground for this actor.</summary>
        public int GroundHeight(WorldPhysics physics)
        {
            var cpi = new CharacterPhysicsInfo(animationSet, this);

            return(CharacterPhysics.GroundHeight(ref cpi, physics, position));
        }
예제 #18
0
 // Start is called before the first frame update
 void Start()
 {
     Instance = this;
 }