RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1073014
Accepted
cyberfrogg
cyberfrogg
Asked:2020-01-22 21:03:19 +0000 UTC2020-01-22 21:03:19 +0000 UTC 2020-01-22 21:03:19 +0000 UTC

在几乎整整一代人之后,世界开始滞后很多。Unity 程序地形

  • 772

我有一个程序景观。有瓦片(块),还有一个 Terrain 对象,当接近景观边缘时,由于生成瓦片时有强烈的 FPS 下降,因此通过 Coroutine 生成。如何解决?

左上角 x/y/z 和 fps 坐标。

GIF:https ://imgur.com/a/GCSFpI2

这是放置块的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

class _Chunk
{
    public GameObject theChunk;
    public float creationTime;

    public _Chunk(GameObject t, float ct)
    {
        theChunk = t;
        creationTime = ct;
    }
}

public class WorldProcedural : MonoBehaviour
{
    public GameObject chunk;
    public GameObject player;

    public int ChunkSize = 16;
    public int halfTilesX = 16;
    public int halfTilesZ = 16;

    Vector3 startPos;
    Hashtable chunks = new Hashtable();

    private void FixedUpdate()
    {
        halfTilesX = ESCManager.DrawDistance;
        halfTilesZ = ESCManager.DrawDistance;

        StartCoroutine(UpdateWorld());
    }

    private void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");

        this.gameObject.transform.position = Vector3.zero;
        startPos = Vector3.zero;

        float updateTime = Time.realtimeSinceStartup;

        for (int x = -halfTilesX; x < halfTilesX; x++)
        {
            for (int z = -halfTilesZ; z < halfTilesZ; z++)
            {
                Vector3 pos = new Vector3((x * ChunkSize + startPos.x), 0, (z * ChunkSize + startPos.z));
                GameObject t = (GameObject)Instantiate(this.chunk, pos, Quaternion.identity);
                t.transform.SetParent(transform);

                string tilename = "Chunk_" + ((int)(pos.x)).ToString() +
                    "_" + ((int)(pos.z)).ToString();
                t.name = tilename;
                _Chunk chunk = new _Chunk(t, updateTime);
                chunks.Add(tilename, chunk);
            }
        }
    }

    private IEnumerator UpdateWorld()
    {
        int xMove = (int)(player.transform.position.x - startPos.x);
        int ZMove = (int)(player.transform.position.z - startPos.z);

        if (Mathf.Abs(xMove) >= ChunkSize || Mathf.Abs(ZMove) >= ChunkSize)
        {
            float updateTime = Time.realtimeSinceStartup;

            int playerX = (int)(Mathf.Floor(player.transform.position.x / ChunkSize) * ChunkSize);
            int playerZ = (int)(Mathf.Floor(player.transform.position.z / ChunkSize) * ChunkSize);

            for (int x = -halfTilesX; x < halfTilesX; x++)
            {
                for (int z = -halfTilesZ; z < halfTilesZ; z++)
                {
                    Vector3 pos = new Vector3((x * ChunkSize + playerX), 0, (z * ChunkSize + playerZ));

                    string tilename = "Chunk_" + ((int)(pos.x)).ToString() +
                        "_" + ((int)(pos.z)).ToString();

                    if (!chunks.ContainsKey(tilename))
                    {
                        GameObject t = (GameObject)Instantiate(this.chunk, pos, Quaternion.identity);
                        t.transform.SetParent(transform);
                        t.name = tilename;
                        _Chunk chunk = new _Chunk(t, updateTime);
                        chunks.Add(tilename, chunk);
                    }
                    else
                    {
                        (chunks[tilename] as _Chunk).creationTime = updateTime;
                    }


                }
                yield return new WaitForSeconds(0.5f);
            }

            Hashtable newTerrain = new Hashtable();
            foreach (_Chunk chk in chunks.Values)
            {
                if (chk.creationTime != updateTime)
                {
                    Destroy(chk.theChunk);
                }
                else
                {
                    newTerrain.Add(chk.theChunk.name, chk);
                }
            }

            chunks = newTerrain;
            startPos = player.transform.position;
        }


    }
}
unity3d
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    earthQuake
    2020-01-24T09:31:15Z2020-01-24T09:31:15Z

    最糟糕的是每次 FixedUpdate 你都会启动一个协程。虽然前一个甚至还没有工作到最后,但很可能您正在启动一个新的,依此类推。在协程中,您使用嵌套循环遍历循环中的所有图块,然后等待半秒钟,然后一切都会再次重复(很可能)。然后你会惊讶于一切都变慢了。

    尝试每 n 次迭代调用一次 yield return null 。

    int everyNthIteration = 10; // будешь каждую десятую итерацию пропускать кадр    
    
    for (int x = -halfTilesX; x < halfTilesX; x++)
    {
        for (int z = -halfTilesZ; z < halfTilesZ; z++)
        {
             if(z % everyNthIteration == 0)
             {
                 yield return null; // то, что ты там по пол секунды ждешь, 
                                    // а потом молотишь по новой на твоим
                                    //  тормозам никак не поможет
             }
    

    这是第一个。第二,代替

    if (!chunks.ContainsKey(tilename))
     {
     }
     else
     {
         chunks[tilename] blah blah
     }
    

    这样做

    if (!chunks.TryGetValue(tilename, out var chunk))
    {
    }
    else
    {
        тут уже делаешь с 'chunk' что тебе надо // 
    }
    

    不要在循环中对字符串执行此操作:

    string tilename = "Chunk_" + ((int)(pos.x)).ToString() +
                        "_" + ((int)(pos.z)).ToString();
    

    至少应该是这样的:string tilename = $"Chunk_{(int)pos.x}_{(int)pos.z}"; //或者使用string.Format..如果你在循环中的某个地方写,那么你应该一般使用stringbuilder。这样你就不会搞砸你的垃圾收集器。

    最后,transform.SetParent() 和 Destroy() 也会给你很多 GC 调用。是否认为可以在循环中没有它。在对 Destroy 的 n 次调用之间,也可以跳过一帧。在这一点上,看看你需要什么“速度”来更新世界。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5