【效率开发】游戏开发Debug效率方法总结

news2024/11/14 14:52:17

"程序员的一半生命都浪费在了调试上。"

        ——Brian Kernighan(计算机科学家,曾参与开发C语言)

图片

(图片来源:forbesindia)

Debug无疑是程序员最头疼,也是耗费时间最多的一个环节,因此如何提高Debug效率至关重要。本文将会根据小棋自身多年的开发经验,总结和分享五种常用的调试方式,帮助你提高开发效率。

图片

注:案例中会使用到C#和python语言,其他语言基本同理。


一、Log

> 看起来平平无奇,却是最基础最简洁的debug方式,在没有Vscode等编辑器之前,是最常用的调试方式啦。O(∩_∩)O~

1. python

>>> print("hello world")hello world

2. C#

// C# Console.WriteLine("hello world")
// Unity对此进行了封装Debug.Log("hello world");print("hello world");

其实Unity中print底层调用的也是Debug.Log

图片

3. Log如何帮助我们得到有用信息?

学会如何打Log也是一个重要编程能力,举个简单的例子:Unity开发游戏过程中经常会提示空指针异常。

NullReferenceException: Object reference not set to an instance of an object

这时候我们可以把Log打在报错附近,查看报错附近的代码语义:

ResManager.LoadPrefab(path);

可以看到这里尝试加载某个路径的物体,尝试打印一些关键信息,比如:​​​​​​​

print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");print(path);

其中,第一行是一个显眼的标识,方便快速定位log,第二行是关键信息。最终结果:​​​​​​​

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Panel/MenuPanel1

然后到加载路径一看,原来路径下只有Panel/MenuPanel,没有Panel/MenuPanel1,修改为正确路径,这样问题就得到解决了。


二、traceback

traceback是我入职当年,我认为导师教我的最简单又好用的功能。有时候游戏在运行过程中,莫名其妙执行了一个操作:比如玩家在某个时间执行了两次攻击逻辑,又或者在错误的时间某个UI界面弹出了。

总结下,适合traceback调试有两个基本要求:

  1. 攻击和UI打开的执行逻辑你知道在哪里 (*^▽^*)

  2. 为什么会执行,谁执行了这个逻辑,不知道 o(╥﹏╥)o

这时候怎么做呢?

图片

1、Python

在python中非常简洁:

在被调用的方法中执行,traceback.print_stack。

当这个方法被执行的时候,我们就清楚的知道是谁执行了这个代码。

图片

2. Unity

Unity游戏引擎深知traceback对于开发效率的提升,因此在编辑器中我们甚至无需做任何处理,就能得到调用栈的信息。

图片

下方有完整的traceback调用栈,双击log信息还能跳转到指定的代码行数,非常方便。

但是这有个前提,需要再Project Settings -> Player -> Other 对Stack Trace进行设置,将其统一设置为ScriptOnly就ok了。(这个设置是默认的)

图片


三、把Log输出到文件中

当你把游戏打开输出之后,或者把python编译成exe运行时,没有了编辑器,也没有log窗口了。这时候我们该如何调试项目呢?

把Log输出到文本文件中就是一个不错的方法,市面上主流的软件也都会执行这一操作。

这里有两种办法供大家选择:

1. 方法一,写一个新的Log.Print方法,调用这个方法的log会输出到文件中。

图片

2. 方法二,用户可以继续使用系统内置的打印方法,不改变用户习惯,我们只监听或者劫持系统的打印方法,并将其输出到log文件中。

显然,第二种方法是更好的。其中Unity用于监听默认打印事件的方法是:

Application.logMessageReceived

而python对应的事件是:

sys.stdout

其他语言也有类似的输出流。

这里我以Unity为例,提供一个参考案例(抄了代码记得点点在看和收藏呀,求求您啦~):​​​​​​​

using UnityEngine;using System.IO;using System;using System.Diagnostics;
public class LogToFile : MonoBehaviour{    private string logFilePath;    private StreamWriter streamWriter;
    void Start()    {        // 创建一个新的文件名,包含时间戳        string fileName = "log_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";        // 获取日志文件夹的路径        string logFolder = Application.persistentDataPath + "/log";        // 确保日志文件夹存在        Directory.CreateDirectory(logFolder);        // 拼接出完整的日志文件路径        logFilePath = Path.Combine(logFolder, fileName);
        // 开始写入日志        streamWriter = File.AppendText(logFilePath);
        // 监听日志事件        Application.logMessageReceived += LogMessageHandler;    }
    void OnDestroy()    {        // 关闭文件流        if (streamWriter != null)        {            streamWriter.Close();        }    }
    void LogMessageHandler(string logString, string stackTrace, LogType type)    {        // 获取当前时间        string currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");                // 使用 System.Diagnostics.StackTrace 获取调用栈信息        StackTrace trace = new StackTrace(true);        // 获取最后一个帧的栈帧        StackFrame frame = trace.GetFrame(trace.FrameCount - 1);        // 获取调用的脚本路径        string scriptPath = Path.GetFileName(frame.GetFileName());        // 获取调用的行号        int lineNumber = frame.GetFileLineNumber();
        // 将日志信息写入文件        streamWriter.WriteLine(currentTime + " [" + type + "] " + scriptPath + "(" + lineNumber + "): " + logString);        // 强制刷新缓冲区,确保日志信息立即写入文件        streamWriter.Flush();    }}

其中,关键代码是:​​​​​​​

// 监听日志事件        Application.logMessageReceived += LogMessageHandler;

其他代码主要是对log信息进行整理,提供:

  • 事件信息

  • 调用栈信息

  • 调用行信息

把LogToFile文件放到场景中的某个物体上后,来看看执行后的效果:​​​​​​​

2024-03-31 16:55:37 [Log] LoginScene.cs(11): >>>>>>>>>>>>>>>>>>>>>> openUI: MenuPanel2024-03-31 16:55:37 [Exception] (0): ArgumentException: The Object you want to instantiate is null.2024-03-31 16:55:37 [Log] MenuPanel.cs(55): >>>> start2024-03-31 16:55:37 [Exception] (0): NullReferenceException: Object reference not set to an instance of an object

非常方便的可以定位到问题。

图片

图片

图片


四、点击调试

点击调试主要讲游戏开发,这里以Unity举例。

对于用户输入来说,鼠标和手指点击是非常重要的一个操作,但是开发过程中经常发现点不到我们想要的物体,这时候可以通过射线检测判断下当前点击事件被哪些物体拦截了。

下面提供代码:​​​​​​​

using UnityEngine;using UnityEngine.EventSystems;
public class ClickDetector : MonoBehaviour{    void Update()    {        // 检测鼠标左键点击        if (Input.GetMouseButtonDown(0))        {            // 检查是否点击在 UI 上            if (EventSystem.current.IsPointerOverGameObject())            {                // 获取点击的 UI 元素                GameObject clickedObject = EventSystem.current.currentSelectedGameObject;
                // 打印 UI 元素的名称                if (clickedObject != null)                {                    Debug.Log("Clicked on UI element: " + clickedObject.name);                }                else                {                    Debug.Log("Clicked on UI element, but no object found.");                }            }            else            {                // 如果没有点击在 UI 上,则检查物体                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);                RaycastHit hit;
                if (Physics.Raycast(ray, out hit))                {                    // 打印物体的名称                    Debug.Log("Clicked on object: " + hit.collider.gameObject.name);                }                else                {                    Debug.Log("Clicked, but no object found.");                }            }        }    }}

具体使用方法,就是把这个脚本放到场景中,然后鼠标点到某个物体,就会打印出指定的物体名称。如果是因为某个物体挡在前面导致被拦截,就能很快的找到问题所在了。

图片

图片

图片

五、断点调试

断点调试是一种在程序执行过程中暂停执行并允许程序员检查程序状态的调试技术。

在大多数集成开发环境(IDE)和调试器中,你可以通过点击编辑器的某一行代码旁边的区域(通常是左侧)来设置断点

当程序执行到这一行时,会自动停止执行,然后你可以逐步执行代码、观察变量值、检查堆栈跟踪等。

图片

因为之前在其他平台已经发过了,所以这里就简单贴下链接,感兴趣的同学可以跳转过去看看。

图片

图片

图片


 

欢迎大家后台私信补充更多效率开发的方法,目前公众号还不支持留言功能,会尽快想办法哒~

 想了解更多游戏开发知识,可以扫描下方二维码,免费领取游戏开发4天训练营课程


好啦,以上就是本期分享的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1666479.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧停车场管理系统主要组成

智慧泊车场办理体系,完成了泊车办理过程中的车辆类型分类、出场时的车牌辨认、行进路线的引导、空余车位诱导,以及准备离场前的反向寻车和方便缴费等全部环节。这六个流程中,泊车场对车辆的办理,进步了泊车场的运行效率&#xff0…

如何远程访问?

远程访问是指在不同的地理位置之间通过网络连接来实现对目标设备或系统的访问。无论是在个人生活还是商业领域,远程访问都起到了重要的作用,帮助人们实现高效的工作和便捷的生活。本文将介绍一款名为【天联】的组网产品,它是一款强大的异地组…

祝天下母亲节快乐!虚无!——早读(逆天打工人爬取热门微信文章解读)

练功加精力哦 引言Python 代码第一篇 人民日报【夜读】人与人之间最好的关系:遇事靠谱,懂得感恩第二篇 冯站长之家 三分钟新闻早餐结尾 感恩与善行 是人生旅途中的灯塔 怀感恩之心 行小善之事 它们将指引我们走向光明 引言 今天是母亲节 祝天下的所有母…

iOS Failed to create provisioning profile.

错误描述 错误情况参考这张图 解决方案 修改Bundle Identifier就可以解决这个错误,找不到位置可以看图 (具体解决的原理与证书有关,个人不是非常熟悉,还望大神告知)

65-CPLD电路设计(安路为例)

视频链接 CPLD电路设计(安路为例)01_哔哩哔哩_bilibili CPLD电路设计(以安路为例) 浅谈板级电源设计的三种方法_哔哩哔哩_bilibili 参考【浅谈板级电源设计的三种方法】 FPGA板级硬件实战S1~7课 实战Power2-电…

云南区块链商户平台:抓包技术自制开票工具(三)

前言 上节我们将登录的流程梳理完毕了,来到了本章重点,既然开发票就肯定要有以下参数: 原工具不支持识别历史记录,对于我们的小商店来说,开票的公司基本就是固定的几个,如果提供下拉支持选择将会大大降低…

机器学习笔记导航(吴恩达版)

01.机器学习笔记01:机器学习前置概念导入、线性回归、梯度下降算法 02.机器学习笔记02:多元线性回归、多元梯度下降算法、特征缩放、均值归一化、正规方程 03.机器学习笔记03:octave安装、创建矩阵 04.机器学习笔记04:octave中移动…

WordPress插件Plus WebP,可将jpg、png、bmp、gif图片转为WebP

现在很多浏览器和CDN都支持WebP格式的图片了,不过我们以前的WordPress网站使用的图片都是jpg、png、bmp、gif,那么应该如何将它们转换为WebP格式的图片呢?推荐安装这款Plus WebP插件,可以将上传到媒体库的图片转为WebP格式图片&am…

机器学习(1)

目录 1-1.西瓜书 1-2.课程定位 1-3.机器学习 1-4.典型的机器学习过程 1-5.机器学习理论 1-6.基本术语 1-7.归纳偏好 1-8.NFL定理 1-1.西瓜书 建议使用方式 1.初学机器学习的第一本书:通读、速读;细节不懂处略过,了解机器学习的疆域和基本思想,…

异构图神经网络代码详解与实战

相关代码地址见文末 1.数据读取 数据采用的是电影推荐的数据集,movies.csv文件存储为电影及其题材。 ratings.csv下存储为用户对电影的评分。 数据集的读取流程为: 首先,读取movies.csv并将题材根据词的出现,转换为one-hot编码的形式读取ratings.csv,将movie_id和…

带你探索CA和SSL证书

目录 一、什么是CA? 二、什么是SSL证书? 三、SSL证书分类和文件种类? 3.1 证书的分类: 3.2证书格式: 四、SSL和TSL 五、PSK介绍 六、nginx配置介绍 一、什么是CA? CA是证书的签发机构,它是…

基于鹈鹕优化算法POA的复杂城市地形下无人机避障三维航迹规划,可以修改障碍物及起始点(Matlab代码)

复杂城市地形下无人机避障三维航迹规划是指在城市等高密度区域内,通过无人机的传感器和导航系统来实现飞行路径的规划和调整,从而避免无人机与建筑物、其他无人机、地面障碍物等发生碰撞和冲突。具体来说,无人机需要实时感知周围环境&#xf…

事件高级部分

一,注册事件 即给元素添加事件 1.传统注册方式 2.方法监听注册方式 事件类型:字符串形式,不用带on 可以给一个元素添加多个程序 二.删除事件 1.方式 参数见上文 三.DOM事件流 事件的传播过程叫做事件流 js代码只能获取一个阶段&#xf…

Istio 使用 Apache SkyWalking 进行服务链路追踪、链路监控告警

一、Istio 使用 Apache SkyWalking 链路追踪和告警 SkyWalking是一个开源的观测平台,用于从服务和云原生等基础设施中收集、分析、聚合以及可视化数据,SkyWalking 提供了一种简便的方式来清晰地观测分布式系统,甚至可以观测横跨不同云的系统…

Linux修炼之路之基础指令(2)+shell命令及运行原理

目录 一:基础指令 7.rm指令 和 rmdir指令 8.*通配符 9.man指令 10.echo指令 11.cat 指令 12.cp 指令 13.mv指令 14.alias 指令 15.less more head tail wc-l 指令 16.date 时间相关的指令 17.cal指令 18. find which whereis 三个查找文件指令…

Android内核之解决报错:error: ISO C90 forbids mixing declarations and code(七十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

两个手机在一起ip地址一样吗?两个手机是不是两个ip地址

在数字时代的浩瀚海洋中,手机已经成为我们生活中不可或缺的一部分。随着移动互联网的飞速发展,IP地址成为了连接手机与互联网的桥梁。那么,两个手机在一起IP地址一样吗?两个手机是不是两个IP地址?本文将带您一探究竟&a…

Python实战开发及案例分析(18)—— 逻辑回归

逻辑回归是一种广泛用于分类任务的统计模型,尤其是用于二分类问题。在逻辑回归中,我们预测的是观测值属于某个类别的概率,这通过逻辑函数(或称sigmoid函数)来实现,该函数能将任意值压缩到0和1之间。 逻辑回…

docker安装向量数据库milvus

Miluvs Milvus 向量数据库能够帮助用户轻松应对海量非结构化数据(图片 / 视频 / 语音 / 文本)检索。 单节点 Milvus 可以在秒内完成十亿级的向量搜索,分布式架构亦能满足用户的水平扩展需求。 Milvus 向量数据库的应用场景包括:互联网娱乐(图片搜索 / 视频搜索)、新零售…