示例#1
0
        public RaycastChunkHit Raycast(Chunk chunk, Ray ray)
        {
            //World.GlobalToLocal(ray.Origin, out Vector2I minCPos, out Vector3I minBPos);
            //World.GlobalToLocal(ray.Origin + ray.Direction * ray.Length, out Vector2I maxCPos, out Vector3I maxBPos);

            Vector3I minRelDir = World.RelativePositionToChunk(ray.Origin, chunk.Coordinates);
            Vector3I maxRelDir = World.RelativePositionToChunk(ray.Origin + ray.Direction * ray.Length, chunk.Coordinates);

            int minX = Math.Min(minRelDir.X, maxRelDir.X);
            int maxX = Math.Max(minRelDir.X, maxRelDir.X);

            int minY = Math.Min(minRelDir.Y, maxRelDir.Y);
            int maxY = Math.Max(minRelDir.Y, maxRelDir.Y);

            int minZ = Math.Min(minRelDir.Z, maxRelDir.Z);
            int maxZ = Math.Max(minRelDir.Z, maxRelDir.Z);

            RayBoxCollisionProvider provider = new RayBoxCollisionProvider();

            List <RaycastChunkHit> hits = new List <RaycastChunkHit>();

            for (int z = minZ; z <= maxZ; z++)
            {
                if (z < 0 || z > Chunk.Depth - 1)
                {
                    continue;
                }

                for (int y = minY; y <= maxY; y++)
                {
                    if (y < 0 || y > Chunk.Height - 1)
                    {
                        continue;
                    }

                    for (int x = minX; x <= maxX; x++)
                    {
                        if (x < 0 || x > Chunk.Width - 1)
                        {
                            continue;
                        }

                        Block b = chunk[x, y, z];

                        if (b.Identifier != "winecrash:air")
                        {
                            Vector3D blockExtents = new Vector3D(0.5D);
                            Vector3D blockCenter  = new Vector3D(x + chunk.Coordinates.X * Chunk.Width, y,
                                                                 z + chunk.Coordinates.Y * Chunk.Depth) + blockExtents;

                            FreeBoxCollider collider = new FreeBoxCollider()
                            {
                                Center  = blockCenter,
                                Extents = blockExtents
                            };

                            Hit h = provider.Collide(ray, collider);

                            collider.Delete();

                            if (h.HasHit)
                            {
                                hits.Add(new RaycastChunkHit(h.Position, h.Normal, h.Time * ray.Length, b, chunk,
                                                             new Vector3I(x, y, z), true));
                            }
                        }
                    }
                }
            }

            if (hits.Count != 0)
            {
                return(hits.OrderBy(h => h.Distance).First());
            }

            return(new RaycastChunkHit());
        }
        public Sweep SweepCollide(Chunk c, BoxCollider b)
        {
            //force = Vector3D.Zero;
            //translation = Vector3D.Zero;

            RigidBody rb = b.WObject.GetModule <RigidBody>();

            Vector3D bc = b.Center;
            Vector3D be = b.Extents * 4;


            Vector3D cc = c.WObject.Position +
                          Vector3D.Up * Chunk.Height / 2.0D +
                          Vector3D.Right * Chunk.Width / 2.0D +
                          Vector3D.Forward * Chunk.Depth / 2.0D;
            Vector3D ce = Vector3D.One * new Vector3D(Chunk.Width, Chunk.Height, Chunk.Depth) / 2.0D;

            // if outside of chunk, no collision.
            if (                             //Y
                cc.Y - ce.Y > bc.Y + be.Y || // if too low
                cc.Y + ce.Y < bc.Y - be.Y || // if too high

                //X
                cc.X - ce.X > bc.X + be.X || // if too much left
                cc.X + ce.X < bc.X - be.X || // if too much right

                //Z
                cc.Z - ce.Z > bc.Z + be.Z || // if too much behind
                cc.Z + ce.Z < bc.Z - be.Z    // if too much forward
                )
            {
                return(new Sweep());
            }
            else // the box collider is within the chunk
            {
                // max coords

                Vector3D max = bc + be;
                Vector3D min = bc - be;

                Vector3D cmax = new Vector3D(
                    WMath.Clamp(max.X, c.Coordinates.X * Chunk.Width,
                                c.Coordinates.X * Chunk.Width + (Chunk.Width - 1)),
                    WMath.Clamp(max.Y, 0, 255),
                    WMath.Clamp(max.Z, c.Coordinates.Y * Chunk.Depth, c.Coordinates.Y * Chunk.Depth + (Chunk.Depth - 1))
                    );

                Vector3D cmin = new Vector3D(
                    WMath.Clamp(min.X, c.Coordinates.X * Chunk.Width,
                                c.Coordinates.X * Chunk.Width + (Chunk.Width - 1)),
                    WMath.Clamp(min.Y, 0, 255),
                    WMath.Clamp(min.Z, c.Coordinates.Y * Chunk.Depth, c.Coordinates.Y * Chunk.Depth + (Chunk.Depth - 1))
                    );

                World.GlobalToLocal(cmax, out _, out Vector3I maxBpos);
                World.GlobalToLocal(cmin, out _, out Vector3I minBpos);


                List <AABBCollider> colliders = new List <AABBCollider>();

                for (int z = minBpos.Z; z <= maxBpos.Z; z++)
                {
                    for (int y = minBpos.Y; y <= maxBpos.Y; y++)
                    {
                        for (int x = minBpos.X; x <= maxBpos.X; x++)
                        {
                            if (c[x, y, z].Collides)
                            {
                                Vector3D blockExtents = new Vector3D(0.5D);
                                Vector3D blockCenter  = new Vector3D(x + c.Coordinates.X * Chunk.Width, y,
                                                                     z + c.Coordinates.Y * Chunk.Depth) + blockExtents;

                                FreeBoxCollider collider = new FreeBoxCollider()
                                {
                                    Center  = blockCenter,
                                    Extents = blockExtents
                                };

                                colliders.Add(collider);
                            }
                        }
                    }
                }

                Sweep resultingSweep =
                    new BoxBoxCollisionProvider().SweepCollideInto(b, rb.Velocity * Time.PhysicsDelta,
                                                                   colliders.ToArray());

                for (int i = 0; i < colliders.Count; i++)
                {
                    colliders[i].Delete();
                }

                colliders.Clear();
                colliders = null;

                return(resultingSweep);
            }
        }