예제 #1
0
        public Chunk GetChunk(float x, float z)
        {
            Vector2Int key = Chunk.NormalizeToChunkPosition(x, z);

            m_Chunks.TryGetValue(key, out Chunk chunk);
            return(chunk);
        }
예제 #2
0
        private void UpdatePlayerPositionOnMainThread()
        {
            if (m_ChunksUpdatingRequired) // 上一次update未完成
            {
                return;
            }

            Vector3 pos     = m_PlayerTransform.localPosition;
            Vector3 forward = m_PlayerTransform.forward;

            Vector2Int lastChunkPos = Chunk.NormalizeToChunkPosition(m_PlayerPositionX, m_PlayerPositionZ);
            Vector2Int chunkPos     = Chunk.NormalizeToChunkPosition(pos.x, pos.z);

            Interlocked.Exchange(ref m_PlayerPositionY, pos.y);

            if (lastChunkPos != chunkPos || forward.x != m_PlayerForwardX || forward.z != m_PlayerForwardZ)
            {
                Interlocked.Exchange(ref m_PlayerPositionX, pos.x);
                Interlocked.Exchange(ref m_PlayerPositionZ, pos.z);

                Interlocked.Exchange(ref m_PlayerForwardX, forward.x);
                Interlocked.Exchange(ref m_PlayerForwardZ, forward.z);

                m_ChunksUpdatingRequired = true;
            }
        }
예제 #3
0
        private void RandomTickChunkOnMainThread()
        {
            m_TickChunkDeltaTime += Time.deltaTime;

            if (m_TickChunkDeltaTime < m_TickChunkInterval)
            {
                return;
            }

            m_TickChunkDeltaTime = 0;

            Vector3    pos      = m_PlayerTransform.localPosition;
            Vector2Int chunkPos = Chunk.NormalizeToChunkPosition(pos.x, pos.z);

            // 只tick玩家周围的9个chunk中的一个

            int i = m_TickChunkRandom.Next(-1, 2);
            int j = m_TickChunkRandom.Next(-1, 2);

            chunkPos.x += i * ChunkWidth;
            chunkPos.y += j * ChunkWidth;

            if (m_Chunks.TryGetValue(chunkPos, out Chunk chunk))
            {
                chunk.RandomTick(m_TickChunkRandom, m_PlayerPositionY);
            }
        }
예제 #4
0
        private void UpdateChunksThreadMethod()
        {
            ChunkPriorityComparer priorityComparer = new ChunkPriorityComparer();

            PriorityQueue <ChunkNeedsLoading> updateChunkQueue = new PriorityQueue <ChunkNeedsLoading>(priorityComparer);
            HashSet <Vector2Int> inRangeChunks = new HashSet <Vector2Int>(m_ChunkPositionComparer); // 求交集优化

            while (!m_Disposed)
            {
                if (!m_ChunksUpdatingRequired) // 不需要更新
                {
                    continue;
                }

                Profiler.BeginSample("Update Chunks");

                updateChunkQueue.Clear();
                inRangeChunks.Clear();

                float playerX  = m_PlayerPositionX;
                float playerZ  = m_PlayerPositionZ;
                float forwardX = m_PlayerForwardX;
                float forwardZ = m_PlayerForwardZ;

                Vector2Int playerChunkPos = Chunk.NormalizeToChunkPosition(playerX, playerZ);
                Vector2    player         = new Vector2(playerX, playerZ);
                Vector2    forward        = new Vector2(forwardX, forwardZ).normalized;

                for (int x = -m_RenderChunkRadius; x <= m_RenderChunkRadius; x++)
                {
                    for (int z = -m_RenderChunkRadius; z <= m_RenderChunkRadius; z++)
                    {
                        Vector2Int chunkPos = new Vector2Int(playerChunkPos.x + x * ChunkWidth, playerChunkPos.y + z * ChunkWidth);

                        inRangeChunks.Add(chunkPos);

                        lock (m_ChunksToRender)
                        {
                            if (m_ChunksToRender.Contains(chunkPos)) // 已经在渲染队列
                            {
                                continue;
                            }
                        }

                        Vector2 chunkCenterPos = chunkPos + new Vector2(ChunkWidth >> 1, ChunkWidth >> 1);
                        Vector2 toChunkCenter  = chunkCenterPos - player;

                        float sqrDis = toChunkCenter.sqrMagnitude;
                        float angle  = Vector2.Angle(toChunkCenter, forward);

                        bool close   = sqrDis < SqrMinChunkDistance;
                        bool inAngle = angle < m_HorizontalFOVInDEG;

                        if (m_IsStartUp || inAngle || close)
                        {
                            updateChunkQueue.Enqueue(new ChunkNeedsLoading
                            {
                                ChunkPosition  = chunkPos,
                                PriorityFactor = sqrDis / m_SqrRenderRadius + angle / m_HorizontalFOVInDEG
                            });
                        }
                    }
                }

                lock (m_ChunksToRender)
                {
                    m_ChunksToRender.IntersectWith(inRangeChunks);
                }

                while (updateChunkQueue.Count > 0)
                {
                    Vector2Int chunk = updateChunkQueue.Dequeue().ChunkPosition;

                    lock (m_ChunksToRender)
                    {
                        m_ChunksToRender.Add(chunk);
                    }

                    if (!m_Chunks.ContainsKey(chunk))
                    {
                        m_ChunksToLoad.Enqueue(chunk);
                    }
                }

                Profiler.EndSample();

                if (m_Chunks.Count > m_MaxChunkCountInMemory)
                {
                    Parallel.ForEach(m_Chunks, pair =>
                    {
                        Vector2 playerPos = new Vector2(m_PlayerPositionX, m_PlayerPositionZ);
                        pair.Value.MarkAsStartUp();

                        if ((pair.Key - playerPos).sqrMagnitude > 4 * m_SqrRenderRadius)
                        {
                            m_ChunksToUnload.Enqueue(pair.Key);
                        }
                    });
                }

                //END
                m_ChunksUpdatingRequired = false;
            }
        }
예제 #5
0
        private void LightBlocksOnMainThread()
        {
            // https://github.com/ddevault/TrueCraft/wiki/Lighting
            // https://github.com/ddevault/TrueCraft/blob/master/TrueCraft.Core/Lighting/WorldLighting.cs

            int count = m_BlocksToLightQueue.Count;

            if (count > MaxLightBlockCountPerFrame)
            {
                count = MaxLightBlockCountPerFrame; // 防止卡死
            }

            WorldManager world = WorldManager.Active;

            while (count-- > 0)
            {
                Vector3Int blockPos = m_BlocksToLightQueue.Pop();

                Vector2Int chunkPos = Chunk.NormalizeToChunkPosition(blockPos.x, blockPos.z);

                if (!m_Chunks.ContainsKey(chunkPos))
                {
                    continue;
                }

                int x = blockPos.x;
                int y = blockPos.y;
                int z = blockPos.z;

                Block block   = world.GetBlock(x, y, z);
                int   opacity = block.LightOpacity < MinBlockLightOpacity ? MinBlockLightOpacity : block.LightOpacity;

                int current    = world.GetBlockLight(x, y, z);
                int finalLight = 0;

                if (opacity < MaxLight || block.LightValue > 0) // 不然就是0
                {
                    int max = world.GetBlockLight(x + 1, y, z);
                    int temp;

                    if ((temp = world.GetBlockLight(x - 1, y, z)) > max)
                    {
                        max = temp;
                    }

                    if ((temp = world.GetBlockLight(x, y + 1, z)) > max)
                    {
                        max = temp;
                    }

                    if ((temp = world.GetBlockLight(x, y - 1, z)) > max)
                    {
                        max = temp;
                    }

                    if ((temp = world.GetBlockLight(x, y, z + 1)) > max)
                    {
                        max = temp;
                    }

                    if ((temp = world.GetBlockLight(x, y, z - 1)) > max)
                    {
                        max = temp;
                    }

                    finalLight = max - opacity;

                    if (block.LightValue > finalLight)
                    {
                        finalLight = block.LightValue; // 假设这个值一定是合法的(不过确实应该是合法的)
                    }
                    else if (finalLight < 0)
                    {
                        finalLight = 0;
                    }
                    //else if (finalLight > MaxLight)
                    //{
                    //    finalLight = MaxLight;
                    //}
                }

                if (current != finalLight)
                {
                    world.SetBlockLight(x, y, z, (byte)finalLight);

                    m_BlocksToLightQueue.Push(new Vector3Int(x - 1, y, z));
                    m_BlocksToLightQueue.Push(new Vector3Int(x, y - 1, z));
                    m_BlocksToLightQueue.Push(new Vector3Int(x, y, z - 1));
                    m_BlocksToLightQueue.Push(new Vector3Int(x + 1, y, z));
                    m_BlocksToLightQueue.Push(new Vector3Int(x, y + 1, z));
                    m_BlocksToLightQueue.Push(new Vector3Int(x, y, z + 1));
                }
            }
        }