腾讯辅助编程工具---Code Buddy
腾讯的Code Buddy
官网介绍: 点此处跳转
其实,腾讯的code buddy (下文简称为buddy) 和现在大多数的AI辅助编程一样,都是帮助各位IT行业的小伙伴更加高效的编辑代码(make your life better ),目前是免费的阶段(个人版免费 企业版与专业版收费详见官网).使用方法与cursor类似.在代码编辑器扩展中安装,然后登陆账号.即可开始使用.使用是很简单的,但是如何去用,也是一门学问.
新的改变
其实现在有一部分的人,还比较抗拒AI辅助编程,认为机器怎么能代替人类呢?不瞒大家,之前的我也是这么人为的,因为之前我接触过AI智能体.unity官方提供的.我现在仍然记忆深刻.当时我确实是用了很少量的代码.写了大概让智能体怎么躲避障碍,怎么追击玩家.然后就是长达10个小时的训练.当时这个训练方式叫:强化学习.如果我稍有改动,比如哪个地方没有想到,哪个地方还可以优化,那么需要重新开始训练.当时我得出的结论就是节省了编码时间,但是时间都用在试错训练上了.于是后来我没有继续再深入的研究AI 智能体.我自我感觉这种办法做游戏AI还是有些浅显.
- 为什么要拥抱AI? ,AI目前来说是个大趋势,孙子兵法也提到,我们需要顺势而为,现在的AI工具也多.选择一个适合自己的AI工具,与自己的AI工具磨合成为现在必须行动的一部分;我想讲一个故事来说明为什么现在会使用AI刻不容缓.中学的时候,大家一定学过瓦特的蒸汽机的改良后推动了工业革命,这项伟大的改良直接导致了大量纺织工人的大量失业.但是注意它的用词,是大量 那么为什么不是全部呢?以前我觉得是还有落后的生产厂家在排斥,但是不久之前我想明白了,因为 少量 的纺织工人学会了如何操作蒸汽机 当然,这个可能不是现实,是我自己猜测的.我希望通过这个"故事"使你明白.AI以后会进入我们的生活.而且以后会发展的更加强大.不会使用AI的人,也许会被淘汰.
- 辅助编程是什么?,其实我理解的恶辅助编程并不是像现在像buddy 这样你敲个关键字然后等待它给你推荐合适的方法体这样的,其实编辑器自带的智能提示也是辅助编程.只不过buddy这一类的辅助编程做的更智能,更全面.也更方便.
- 如何启用buddy? 我使用的是vscode编辑器 , vscode安装插件还是很方便的,直接在插件市场中搜索"腾讯云代码助手 CodeBuddy";截至写稿日期,还不到半个月,已经有11w的装机量.这个成绩还是不错的.
将它下载到vscode还是需要一个小步骤才能正常使用:在vscode的右下角找到buddy的图表,点击它选择启用代码补全:
如果你够细心的话,你会发现我也启用了GitHub的Copilot,并且我的Copilot是付费版.为了不让Copilot影响buddy的使用结果,还需要将Copilot进行关闭,那么该怎么关闭Copilot呢?
只需要在右下角的Copilot图标处点击,关闭所有选项即可,最后的最后,需要你使用微信号登录,当然你使用其他方式登录也可以.点击右下角的图标,或者是左侧的插件图标都可以
操作完毕之后Copilot那会有个斜杠,那么就代表它的功能已经被屏蔽了.我的vscode中没有继续安装其他的辅助编程,那么剩下所有的智能提示,都是编辑器自带,或者是buddy提供的.
buddy主要功能快捷键
进行代码解释:Shift +Alt + X
进行代码修复:Shift +Alt + Y
进行代码注释:Shift +Alt + M
生成测试单元:Shift +Alt + T
询问 AI 问题:Ctrl +Windows + I
在代码区域打开技术对话:Ctrl +Windows + N
PS:还有在开发中用到的快捷键下方具体开发使用的过程中再介绍
那么到目前为止.buddy 的配置工作已经结束,已经可以在项目中去使用了.为了体现buddy的辅助效果.之前我已经关闭了github的Copilot辅助编程, 目前这算是第一个阶段,新建一个unity工程,并通过注释联想.需求直连(AI对话并让它生成代码)虽然我知道buddy给出的代码应该会有一些问题.我仅仅会修改它的不合理处,不会去人为的写一个代码让它在此基础上继续生成.这个会在第二阶段做个测试,在一个完整的项目中让它生成合理的代码或者直接询问buddy的建议.
那么在这个新建的unity工程中,我准备从level1 开始,就是简单的控制控件.位移,等等基础功能.当然了.工程中的新建脚本,控件添加还是要人工去做的.
首先这个是我新建的工程 ,工程中我已经新建好了一个名为PlayerCtrl.cs的脚本文件.那么通过名字可以知道这个是用来控制游戏物体的移动的.
那么.打开脚本:开始试试buddy到底如何,再次确认GitHub的Copilot是关闭状态.
默认的脚本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
当然,目前还不着急去看左侧边栏的功能只是看一下在日常中最常用的,最基本的效果如何.
1.通过注释智能提示代码
按照普通的开发需求,我现在只打注释,看能不能联想出代码来.首先对于playerCtrl ,最最基本的是需要移动速度.那么我就先打个注释
那么可以发现,通过简单的打出注释即可联想出代码.这一点很不错,那么下一步,我试试让它智能提示出方法体.
也可以实现提示方法体.这一点buddy与GitHub的copilot没什么不同.而且它也可以和之前自己声明的变量联系起来.当然这里我就不花时间测试了,这么简单的代码一眼看过去,是没有任何问题的.从这里看,buddy具备基本的unity初级人员的开发能力.
在使用的时候它的注释也可以联想出来
2.通过需求生成一段代码
通过组合键打开需求描述:Alt + K
那么我这里先做一个玩家移动+相机缓动跟随的功能,那么怎么提问在这里我就不一一写出来了,那样会显得很臃肿.其实怎么与AI沟通也是一个技巧,我会在最后写上我自己总结的经验,这部分经验来自于<ChatGPT提问追问技巧全攻略> 与 <清华104页超详细DeepSeek 从入门到精通>
这里贴上完全由buddy生成的代码:
首先是移动代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpForce = 10f;
private Rigidbody rb;
private bool isGrounded;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
Move();
Jump();
}
void Move()
{
float moveX = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime;
float moveZ = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
transform.Translate(moveX, 0, moveZ);
}
void Jump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isGrounded = false;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
}
当然,如果你对于unity开发比较熟悉应该也能看出来问题:
- if (Input.GetButtonDown(“Jump”) && isGrounded) 这里的按键输入并没有为"Jump"的按键,一般的,键盘输入跳跃应该是空格,即为"Space" .
- 对于是否在地面上的判断,其实这里有2个问题,第一个是只有OnCollisionEnter的方法,没有OnCollisionEnter的方法,这会导致isGrounded标志位一直为false 第二个问题是对于Rigidbody的获取应该考虑到获取失败的情况.基于此种情况.我对buddy的代码进行一点修改.修改后如下
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor.SceneManagement;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpForce = 10f;
private Rigidbody rb;
private bool isGrounded;
void Start()
{
rb = GetComponent<Rigidbody>();
if (rb == null)
{
rb = transform.AddComponent<Rigidbody>();
}
}
void Update()
{
Move();
Jump();
}
void Move()
{
float moveX = Input.GetAxis("Horizontal") * moveSpeed * Time.deltaTime;
float moveZ = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
transform.Translate(moveX, 0, moveZ);
}
void Jump()
{
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
Debug.Log(isGrounded);
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isGrounded = false;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
private void OnCollisionExit(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}
}
多提一句,我在手动敲上OnCollisionExit的时候,它倒是很快给出了我想敲的代码
相机缓动跟随代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[Header("Camera Settings")]
[SerializeField] private float smoothSpeed = 0.125f;
[SerializeField] private Vector3 offset;
[SerializeField] private float lookAtDistance = 5f;
[SerializeField] private float dragSpeed = 2f;
private Transform target;
private float mouseX, mouseY;
void Start()
{
// 默认跟随玩家(假设玩家对象名为"Player")
target = GameObject.Find("Player")?.transform;
}
void LateUpdate()
{
if (target == null) return;
// 平滑跟随目标
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
// 使相机看向目标
transform.LookAt(target.position - offset.normalized * lookAtDistance);
// 鼠标控制视角旋转
if (Input.GetMouseButton(1)) // 右键拖动
{
mouseX += Input.GetAxis("Mouse X") * dragSpeed;
mouseY -= Input.GetAxis("Mouse Y") * dragSpeed;
mouseY = Mathf.Clamp(mouseY, -35, 60); // 限制上下视角范围
Quaternion rotation = Quaternion.Euler(mouseY, mouseX, 0);
transform.rotation = rotation;
}
}
}
这个脚本中也有一些问题.不过问题不大,就是在与对需求的理解上,我给的需求是:相机平滑跟随,并根据鼠辈滑动改变视口. buddy理解成了鼠标滑动是自由视角,而不再看着玩家. 所以我需要再次修改我的需求,并让buddy重新生成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float followSpeed = 5f;
[SerializeField] private float rotationSpeed = 10f;
[SerializeField] private Vector3 offset;
[SerializeField] private float minDistance = 2f;
[SerializeField] private float maxDistance = 10f;
[SerializeField] private LayerMask collisionLayer;
private Vector3 desiredPosition;
void LateUpdate()
{
if (target == null) return;
// 计算目标位置
desiredPosition = target.position + offset;
// 处理鼠标旋转
RotateView();
// 计算相机方向
Vector3 direction = target.position - transform.position;
direction.Normalize();
// 检测碰撞并调整位置
RaycastHit hit;
if (Physics.Linecast(target.position, desiredPosition, out hit, collisionLayer))
{
desiredPosition = hit.point + direction * minDistance;
}
// 平滑移动相机
transform.position = Vector3.Lerp(transform.position, desiredPosition, followSpeed * Time.deltaTime);
// 保持相机看向目标
transform.LookAt(target.position - direction * maxDistance);
}
void RotateView()
{
// 获取鼠标输入
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed;
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed;
// 旋转相机
target.Rotate(Vector3.up * mouseX);
transform.RotateAround(target.position, target.right, -mouseY);
}
}
重新生成后的代码也是有问题,对于处理相机看向玩家处,它的计算完全是反过来的了.所以,这里我需要给它修改一下,那么这次我不再手动修改,而是让它自己修改.
于是我用到左侧的插件栏功能
Craft 模式很强大,可以通过下面的聊天框 @Add添加多个脚本,进行批量修改.那么这里我只为修改一个,那就是相机跟随代码 所以我对相机跟随代码进行引用
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float followSpeed = 5f;
[SerializeField] private float rotationSpeed = 10f;
[SerializeField] private Vector3 offset;
[SerializeField] private float minDistance = 2f;
[SerializeField] private float maxDistance = 10f;
[SerializeField] private LayerMask collisionLayer;
private Vector3 desiredPosition;
void LateUpdate()
{
if (target == null) return;
// 计算目标位置
desiredPosition = target.position + offset;
// 处理鼠标旋转
RotateView();
// 计算相机方向
Vector3 direction = target.position - transform.position;
direction.Normalize();
// 检测碰撞并调整位置
RaycastHit hit;
if (Physics.Linecast(target.position, desiredPosition, out hit, collisionLayer))
{
desiredPosition = hit.point + direction * minDistance;
}
// 平滑移动相机
transform.position = Vector3.Lerp(transform.position, desiredPosition, followSpeed * Time.deltaTime);
// 保持相机看向目标
transform.LookAt(target.position - direction * maxDistance);
}
void RotateView()
{
// 获取鼠标输入
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed;
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed;
// 旋转相机
// 水平旋转:围绕目标的Y轴旋转相机,而不是旋转目标
transform.RotateAround(target.position, Vector3.up, mouseX);
// 垂直旋转:使用正值mouseY,这样鼠标向上移动时相机向上看
transform.RotateAround(target.position, transform.right, -mouseY);
}
}
很遗憾,这里的代码仍然有问题.所以,我自己修改.其实就是一个符号的问题.
transform.LookAt(target.position - direction * maxDistance);
将上方代码中的-号改成+号即可,因为如果是-号的话,那么相机看向的位置一直是相反的方向.
3.联系上下文生成代码
其实做到这个地步,代码还是有问题,比如旋转是可以旋转了,但是它与跟随代码冲突,以及前进的方向不是相机看向的方向,这个功能需要结合playerCtrl与CameraFollow一起修改.
当然,还是要用Craft
修改完后的代码如下:
playerCtrl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCtrl : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpForce = 10f;
[SerializeField] private Transform cameraTransform; // 引用相机的Transform
private Rigidbody rb;
private bool isGrounded;
void Start()
{
rb = GetComponent<Rigidbody>();
if (rb == null)
{
rb = transform.gameObject.AddComponent<Rigidbody>();
}
// 如果没有指定相机,则使用主相机
if (cameraTransform == null)
{
cameraTransform = Camera.main.transform;
}
}
void Update()
{
Move();
Jump();
}
void Move()
{
// 获取输入
float moveX = Input.GetAxis("Horizontal");
float moveZ = Input.GetAxis("Vertical");
if (moveX == 0 && moveZ == 0) return;
// 基于相机方向计算移动向量
Vector3 forward = cameraTransform.forward;
Vector3 right = cameraTransform.right;
// 忽略Y轴,保持在水平面上移动
forward.y = 0;
right.y = 0;
forward.Normalize();
right.Normalize();
// 计算最终移动方向
Vector3 moveDirection = (forward * moveZ + right * moveX).normalized;
// 应用移动
transform.position += moveDirection * moveSpeed * Time.deltaTime;
// 如果有移动输入,让玩家朝向移动方向
if (moveDirection != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(moveDirection);
}
}
void Jump()
{
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
Debug.Log(isGrounded);
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isGrounded = false;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
private void OnCollisionExit(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}
}
cameraFollow
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float followSpeed = 5f;
[SerializeField] private float rotationSpeed = 10f;
[SerializeField] private Vector3 offset;
[SerializeField] private float minDistance = 2f;
[SerializeField] private float maxDistance = 10f;
[SerializeField] private LayerMask collisionLayer;
private Vector3 desiredPosition;
void LateUpdate()
{
if (target == null) return;
// 计算目标位置
desiredPosition = target.position + offset;
// 处理鼠标旋转
RotateView();
// 计算相机方向
Vector3 direction = target.position - transform.position;
direction.Normalize();
// 检测碰撞并调整位置
RaycastHit hit;
if (Physics.Linecast(target.position, desiredPosition, out hit, collisionLayer))
{
desiredPosition = hit.point + direction * minDistance;
}
// 平滑移动相机
transform.position = Vector3.Lerp(transform.position, desiredPosition, followSpeed * Time.deltaTime);
// 保持相机看向目标
transform.LookAt(target.position + direction * maxDistance);
}
void RotateView()
{
// 获取鼠标输入
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed;
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed;
// 旋转相机
// 水平旋转:围绕目标的Y轴旋转相机,而不是旋转目标
transform.RotateAround(target.position, Vector3.up, mouseX);
// 垂直旋转:使用正值mouseY,这样鼠标向上移动时相机向上看
transform.RotateAround(target.position, transform.right, -mouseY);
}
}
那么,从这个动图来看问题还是存在,其一,360度环绕有问题,其二,没有相机避开遮挡之后没有回到原来的距离.
那么还需要细心的修改代码
那么就是代码中的offset的问题,其中offset是个定值,而有环绕观察的功能,offset不能是个定值否则它就会一直缓动到固定的位置.所以,在控制环绕的代码中对offset进行一个赋值.
void RotateView()
{
// 获取鼠标输入
float mouseX = Input.GetAxis("Mouse X") * rotationSpeed;
float mouseY = Input.GetAxis("Mouse Y") * rotationSpeed;
// 旋转相机
// 水平旋转:围绕目标的Y轴旋转相机,而不是旋转目标
transform.RotateAround(target.position, Vector3.up, mouseX);
// 垂直旋转:使用正值mouseY,这样鼠标向上移动时相机向上看
transform.RotateAround(target.position, transform.right, -mouseY);
// 限制垂直旋转角度
Vector3 eulerAngles = transform.eulerAngles;
if (eulerAngles.x > 180f)
eulerAngles.x -= 360f;
eulerAngles.x = Mathf.Clamp(eulerAngles.x, -80f, 80f);
transform.eulerAngles = eulerAngles;
// 更新offset
offset = transform.position - target.position;
}
那么最后的成品如下:
总的来说我没有任何自己的想法,只是用buddy来生成代码,对于它里面的错误进行修改.其实这个过程持续没有超过30分钟,这种开发的效率已经是很可观了(毕竟没有高深的东西).那么我很想看看有点技术含量的东西,buddy的表现如何.
比较难的功能实现
比如软体模拟.让它生成软体模拟的代码,并且使用骨骼球的方式.
这个结果让我很意外
首先它扫描了我的项目结构,并且把生成的代码放在了正确的位置.对于物理计算公式也是正确的.为什么我要用软体模拟呢?因为几年前.我就研究过.那时候只能通过论文来研究,最后是借助了bullet引擎做出来的软体.而现在buddy仅仅用了大概10分钟左右的时间,就完成了软体模拟,它自动生成了近1000行代码,并没有任何报错,最后居然还给我生成了一个使用文档!
我没有做任何修改,按照指导文档中的操作在unity中进行设置.调整了几个参数.效果如下;
这个结果令人震惊,因为不久之前我也试过deepseek与元宝,没有一个是一次就能跑通的,这个buddy我对它的表现还是很满意的.
BlenderMCP AI 建模
在左侧的插件中点击
因为我发现了blender的自动建模插件.这令我很意外.所以试一试,看看好不好用,buddy真是给我诸多惊喜.没想到编程可以,居然连自动建模也可以.
这个插件有些靠后,选择它下载即可,在下载的时候可能会提示安装失败,缺少uv 或者什么ux一类的
windows平台右键windows图标:现在powershell (管理员)
用以下命令开始安装配套程序
安装UV ,打开powershell (管理员)
执行以下代码:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.7.3/install.ps1 | iex"
检查安装是否完成:
powershell -c "irm https://astral.sh/uv/install.ps1 | more"
做完之后回到vscode,如果你的vscode不是管理员权限打开的,还需要你重新用管理员权限打开.然后点击安装即可
安装之后如下:
那么再打开blender 安装vscode 中BlenderMCP中的addon.py插件.地址是 : 点此处跳转
安装好如下
界面中即可看到安装完毕
然后点击Connect MCP server 上面的两个选项可以都不选,因为选择了的话网络不通会有问题.
然后打开duddy的Craft ,让它建立一个简单的模型:
然后按下F12 渲染
最后做出的酒杯渲染效果图:
这个我没有做任何模型的点线面修改,纯AI自己生成的.
以上是我使用buddy的使用经历.个人感觉比copilot的功能多,很值得各位去尝试.
AI提问技巧(个人经验版)
1.简洁明了的提问 不需要礼貌用语 避免模糊的提示 (如帮我写段代码),需要限制AI的思考范围.例如:用unity技术栈开发一个用户登录的功能,并且用户可以扫码登录.
2.区分问题类型 让Ai知道你是需要改bug,还是要生成代码.(如这个地方内存泄漏,分析原因)
3.结构化提问 像流程图一样.让AI从1-100来做,避免直接让它做一个大项目(如 1.设计一个数据表,用来存放玩家信息 2.编写对应的序列化器(不要使用XX方法) 3.抽象出一个接口供unity客户端调用)
4.术语要专业 有些术语是各位私下里的叫法,而AI却不能明白.所以需要使用标准的专业术语(如 加密密码 改成 哈希加密 MD5加密等)