Unity2D初级背包设计中篇 MVC分层撰写(万字详解)

         本人能力有限,如有不足还请斧正,理论分析链接如下:

        Unity2D初级背包设计前篇 理论分析-CSDN博客

目录

1.M层:数据存储  

物品

仓库容器

加载方式

2.M层:逻辑撰写

InventoryManager 仓库的管理

SlotData 物品的增删查改*(逻辑层)

3.V层:搭建UI

        1.SlotUI 将物品绘制到格子上

        2.三个类

BarUI工具栏的选中与数字切换

    BarSoltUI格子高亮 

        BagUI 将格子数据绘制到界面上

4.C层:玩家控制类

ItemMoveHandler 物品的增删查改*(表现层)

         Plyaer 拾取与丢弃


1.M层:数据存储  

物品

        一个2D的物品必不可少的就是类型,图标,物体(这个指Gameobjcet和其名字)堆叠数量

        拓展思路:稀有度,价值,耐久,描述,重量,

using UnityEngine;
/// <summary>
/// 不同的物品可以有不同的类型 以用作其他逻辑的判断
/// 举例:食物可以吃但通常不能打人
///       武器通常不能吃但可以打人
/// </summary>
public enum ItemType{a,b,c,d
}
/// <summary>
///
/// </summary>
[CreateAssetMenu()]
public class ItemData:ScriptableObject
{public ItemType itmeType;public Sprite itemSprite;public GameObject itemPrefab;public int maxCount =1;//最大堆叠数量:默认:1
}

        另外可能需要一个外部类去定义其属性,比如可拾取的,不可拾取的 这个的作用体现在玩家拾取方面,需要提前知道一下

public class Pickable : MonoBehaviour
{public ItemType thisItemType;
}

         so对象举例

        

        

仓库容器

        先认识一个单词:Inventory,仓库,库存 在本文中特指背包类

        之所以要对Inventory写为So,是因为游戏中可能存在许多的仓库,在玩家手中叫做背包,物品栏,在NPC手中就可能叫做商店,锻造了,因此:

using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu()]
public class InventoryData :ScriptableObject{//TODO :拓展 仓库名称,最大容量,自动扩容public List<SlotData> slotList;
}

        创建两个

        可以看到其容量是我们自定义的,也就是写死的没有自动扩容功能

        因此在今后的拓展之中可以优化

加载方式

2.M层:逻辑撰写

InventoryManager 仓库的管理

       我们需要一个仓库管理器去管理所有的背包所以用到了InventoryData 对象

        另外,管理所有物品的时候也应需要一个容器去预加载,所以用到了字典

  可以先不看这一行:我们需要为外部提供提供向背包添加物品的方法,所以用到了单例模式

using System.Collections.Generic;
using UnityEngine;public class InventoryManager : MonoBehaviour {private static InventoryManager instance;public static InventoryManager Instance => instance;public InventoryData BagInventory;public InventoryData ToolBarInventory;public Dictionary<ItemType, ItemData> itemDataDict = new Dictionary<ItemType, ItemData>();private void Awake() {if (instance == null) {instance = this;}else {Destroy(this);}InitInventoryData();}private void Start() {}/// <summary>/// 加载本地物品和已有的背包数据/// </summary>private void InitInventoryData() {ItemData[] itemDatas = Resources.LoadAll<ItemData>("Itmes");foreach (var singleItem in itemDatas) {itemDataDict.Add(singleItem.itmeType, singleItem);}BagInventory = Resources.Load<InventoryData>("Inventorys/MyInventory");ToolBarInventory= Resources.Load<InventoryData>("Inventorys/ToolBarInventory");}/// <summary>/// 通过指定的物品类型从字典中获取物品数据/// </summary>/// <param name="type">物品类型</param>/// <returns>如果找到则返回物品数据,否则返回null</returns>private ItemData GetItem(ItemType type) {if (itemDataDict.TryGetValue(type, out var item))return item;else {Debug.LogError("未找到指定物品");return null;}}/// <summary>/// 向背包中添加物品/// </summary>/// <param name="itemType">要添加的物品类型</param>public void AddItemToInventory(ItemType itemType) {ItemData aItem = GetItem(itemType);// 情况1:字典中有该物品且格子未满 如果格子满了将会走情况2foreach (var slot in BagInventory.slotList) {if (slot.item == aItem && slot.CanAddItem()) {slot.Add();return;}}// 情况2:格子为空,添加物品foreach (var slot in BagInventory.slotList) {if (slot.count == 0) {slot.AddItem(aItem);return;}}// 情况3:背包已满Debug.LogWarning($"未能成功添加物品 {aItem.name} 因为 {BagInventory.name} 已经满了");}
}

SlotData 物品的增删查改*(逻辑层)

        这个类将目光聚焦于背包中的格子,因为它才是背包的最小单位

        

        格子需要持有物品类,并且有一个当前数量的变量

        每次修改格子物品信息的时候需要给到其通知(也就是M层----->V层这一步),所以需要做发布者发布一个委托,让V层去监听  

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class SlotData {public ItemData item;public int currentCount = 0; // 物品数量private Action OnChange;#region 增(Add)// 添加物品到槽位public void Add(int numToAdd = 1) {this.currentCount += numToAdd;OnChange?.Invoke();}// 设置槽位的物品和数量public void AddItem(ItemData item, int count = 1) {this.item = item;this.currentCount = count;OnChange?.Invoke();}#endregion#region 删(Remove)// 减少槽位中的物品数量public void Reduce(int numToReduce = 1) {currentCount -= numToReduce;if (currentCount == 0) {Clear();}else {OnChange?.Invoke();}}// 清空槽位public void Clear() {item = null;currentCount = 0;OnChange?.Invoke();}#endregion#region 查(Check)// 检查槽位是否为空public bool IsEmpty() {return currentCount == 0;}// 检查槽位是否可以添加物品public bool CanAddItem() {return currentCount < item.maxCount;}// 获取槽位的空余空间public int GetFreeSpace() {return item.maxCount - currentCount;}#endregion#region 改(Update)// 移动槽位数据public void MoveSlot(SlotData data) {this.item = data.item;this.currentCount = data.currentCount;OnChange?.Invoke();}// 添加监听器public void AddListener(Action OnChange) {this.OnChange = OnChange;}#endregion
}

        就这么点东西,至此M层就算是写完辣

3.V层:搭建UI

         

        1.SlotUI 将物品绘制到格子上

         自然其应持有SlotData类,并订阅其发布的委托,回调函数就是ChangeUI方法

        SetData实现的就是C---->M层,GetData是V---->C层

using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class SlotUI : MonoBehaviour,IPointerClickHandler
{protected SlotData slotData;protected Image icon;protected TextMeshProUGUI num;private void Start() {icon = transform.Find("icon").GetComponent<Image>();num = transform.Find("num").GetComponent<TextMeshProUGUI>();}public SlotData GetData(){ return slotData;}/// <summary>/// 为该脚本上的对象赋值一个SlotData/// </summary>public void SetData(SlotData slotData) { this.slotData = slotData;//事件监听 - 订阅者slotData.AddListener(UpdateUI2Slot);UpdateUI2Slot();}/ <summary>/ 监听对象/ </summary>//public void ChangeUI(){//    UpdateUI2Slot();//}private void UpdateUI2Slot(){if (slotData==null || slotData.item == null || slotData.currentCount <= 0) {icon.enabled = false;num.enabled = false;}else {icon.enabled = true;num.enabled = true;icon.sprite = slotData.item.itemSprite;num.text = slotData.currentCount.ToString();}}public void OnPointerClick(PointerEventData eventData) {Debug.Log("发生了点击");ItemMoveHandler.Instance.OnSlotClick(this);}
}

选中后将物品依附到鼠标上面 

        2.三个类

BarUI工具栏的选中与数字切换

using System.Collections.Generic;
using UnityEngine;public class BarUI : MonoBehaviour
{//工具栏ui列表 先给这个列表对应好ui格子,之后将数据列表粘贴到ui列表中 并更新UI即完成可视化[SerializeField]private List<BarSlotUI> barSlotUIList;[SerializeField] private GameObject ContentList;[SerializeField] private BarSlotUI curSelectBarSlotUI;//当前选中的工具栏的格子// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start(){barSlotUIList = new List<BarSlotUI>();ContentList =transform.Find("Bar/ContentList").gameObject;InitSlotUI();}private void Update() {SelectBarSlot();}/// <summary>/// 默认curSelectBarSlotUI为空,所以首次不会进入第二个if/// 当第二次选中格子时,curSelectBarSlotUI指向第一个格子,所以不为空就高亮第一个格子/// </summary>public void SelectBarSlot(){for (int i = (int)KeyCode.Alpha1; i < (int)KeyCode.Alpha9 + 1; i++) {if (Input.GetKeyDown((KeyCode)i)) {if (curSelectBarSlotUI != null) {curSelectBarSlotUI.BarSlotLight();}int index = i - (int)KeyCode.Alpha1;curSelectBarSlotUI = barSlotUIList[index];curSelectBarSlotUI.BarSlotDark();}}}public void InitSlotUI() {if (ContentList != null) {foreach (BarSlotUI barSlotUI in ContentList.GetComponentsInChildren<SlotUI>()) {barSlotUIList.Add(barSlotUI);}}UpdataUI();}public void UpdataUI() {for (int i = 0; i < InventoryManager.Instance.ToolBarInventory.slotList.Count; i++) {barSlotUIList[i].SetData(InventoryManager.Instance.ToolBarInventory.slotList[i]);}}}

    BarSoltUI格子高亮 

using TMPro;
using UnityEngine;
using UnityEngine.UI;public class BarSlotUI : SlotUI
{[SerializeField] private Sprite slotLight;[SerializeField] private Sprite slotDark;[SerializeField]private Image thisImage;// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start(){InitBar_Slot();}public void InitBar_Slot(){this.icon = transform.Find("Bar_icon").GetComponent<Image>();this.num = transform.Find("Bar_num").GetComponent<TextMeshProUGUI>();thisImage =GetComponent<Image>();slotLight = Resources.Load<Sprite>("SlotUI/slotLight");slotDark = Resources.Load<Sprite>("SlotUI/slotDark");}public void BarSlotLight(){thisImage.sprite = slotLight;}public void BarSlotDark() {thisImage.sprite = slotDark;}
}

        BagUI 将格子数据绘制到界面上

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class BagUI : MonoBehaviour {[SerializeField] private Button close;[SerializeField] private GameObject BG;[SerializeField] private GameObject slotGrid;[SerializeField] private List<SlotUI> soltuiList = new List<SlotUI>();// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start() {InitElement();InitSlotUI();}// Update is called once per framevoid Update() {ColseBag();}public void InitElement() {BG = transform.Find("BG").gameObject;close = transform.Find("BG/BgElement/Close").GetComponent<Button>();slotGrid = transform.Find("BG/SlotGrid").gameObject;if (close != null) {close.onClick.AddListener(() => {if (BG != null)BG.SetActive(!BG.activeSelf);else {Debug.LogWarning("没找到BG对象");return;}});}elseDebug.LogWarning("没有加载到close按钮");}public void UpdataUI() {for (int i = 0; i < InventoryManager.Instance.BagInventory.slotList.Count; i++) {soltuiList[i].SetData(InventoryManager.Instance.BagInventory.slotList[i]);}}public void InitSlotUI() {if (slotGrid != null) {foreach (SlotUI slotUi in slotGrid.GetComponentsInChildren<SlotUI>()) {soltuiList.Add(slotUi);}}UpdataUI();}public void ColseBag() {if (Input.GetKeyDown(KeyCode.Tab))BG.SetActive(!BG.activeSelf);}
}

4.C层:玩家控制类

ItemMoveHandler 物品的增删查改*(表现层)

        这个类其实应该好好讲一讲,但是笔者写了一个多小时雀氏有点累了,反正都是一些常见的逻辑 所以用ai给到注释,如果前面的代码都理解了,那么这里一点也不难

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class ItemMoveHandler : MonoBehaviour {// 单例模式的实例public static ItemMoveHandler Instance {get; private set;}// 图标private Image icon;// 选中的槽数据private SlotData selectedSlotData;// 玩家对象private Player player;// 控制键是否按下private bool isCtrlDown = false;// Awake方法在脚本实例化时调用private void Awake() {Instance = this;icon = GetComponentInChildren<Image>();HideIcon();player = GameObject.FindAnyObjectByType<Player>();}// Update方法在每帧调用private void Update() {// 如果图标启用,更新图标位置if (icon.enabled) {Vector2 position;RectTransformUtility.ScreenPointToLocalPointInRectangle(GetComponent<RectTransform>(), Input.mousePosition,null,out position);icon.GetComponent<RectTransform>().anchoredPosition = position;}// 左键点击时,如果没有点击UI元素,丢弃物品if (Input.GetMouseButtonDown(0)) {if (EventSystem.current.IsPointerOverGameObject() == false) {ThrowItem();}}// 检测Ctrl键按下和松开if (Input.GetKeyDown(KeyCode.LeftControl)) {isCtrlDown = true;}if (Input.GetKeyUp(KeyCode.LeftControl)) {isCtrlDown = false;}// 右键点击时,强制清空手上的物品if (Input.GetMouseButtonDown(1)) {ClearHandForced();}}// 槽点击事件处理public void OnSlotClick(SlotUI slotui) {// 判断手上是否有物品if (selectedSlotData != null) {// 手上有物品if (slotui.GetData().IsEmpty()) {// 当前点击了一个空格子MoveToEmptySlot(selectedSlotData, slotui.GetData());}else {// 当前点击了一个非空格子if (selectedSlotData == slotui.GetData())return;else {// 点击了别的格子 且 两个格子的物品相同if (selectedSlotData.item == slotui.GetData().item) {MoveToNotEmptySlot(selectedSlotData, slotui.GetData());}else {SwitchData(selectedSlotData, slotui.GetData());}}}}else {// 手上没有物品if (slotui.GetData().IsEmpty())return;selectedSlotData = slotui.GetData();ShowIcon(selectedSlotData.item.itemSprite);}}// 隐藏图标void HideIcon() {icon.enabled = false;}// 显示图标void ShowIcon(Sprite sprite) {icon.sprite = sprite;icon.enabled = true;}// 清空手上的物品void ClearHand() {if (selectedSlotData.IsEmpty()) {HideIcon();selectedSlotData = null;}}// 强制清空手上的物品void ClearHandForced() {HideIcon();selectedSlotData = null;}// 丢弃物品private void ThrowItem() {if (selectedSlotData != null) {GameObject prefab = selectedSlotData.item.itemPrefab;int count = selectedSlotData.currentCount;if (isCtrlDown) {player.ThrowItem2Creat(prefab, 1);selectedSlotData.Reduce();}else {player.ThrowItem2Creat(prefab, count);selectedSlotData.Clear();}ClearHand();}}// 移动物品到空槽private void MoveToEmptySlot(SlotData fromData, SlotData toData) {if (isCtrlDown) {toData.AddItem(fromData.item);fromData.Reduce();}else {toData.MoveSlot(fromData);fromData.Clear();}ClearHand();}// 移动物品到非空槽private void MoveToNotEmptySlot(SlotData fromData, SlotData toData) {if (isCtrlDown) {if (toData.CanAddItem()) {toData.Add();fromData.Reduce();}}else {int freespace = toData.GetFreeSpace();if (fromData.currentCount > freespace) {toData.Add(freespace);fromData.Reduce(freespace);}else {toData.Add(fromData.currentCount);fromData.Clear();}}ClearHand();}// 交换槽数据private void SwitchData(SlotData data1, SlotData data2) {ItemData item = data1.item;int count = data1.currentCount;data1.MoveSlot(data2);data2.AddItem(item, count);ClearHandForced();}
}

         Plyaer 拾取与丢弃

using UnityEngine;public class Player : MonoBehaviour
{private void OnTriggerEnter2D(Collider2D collision) {Debug.Log("进入了触发检测");if (collision.CompareTag("Item")){Debug.Log("检测到了物品");InventoryManager.Instance.AddItemToInventory(collision.GetComponent<Pickable>().thisItemType);Destroy(collision.gameObject);}}/// <summary>/// 丢弃背包的物品 并在场景中实例化出来/// </summary>/// <param name="itemPrefab">丢弃对象</param>/// <param name="count">丢弃数量</param>public void ThrowItem2Creat(GameObject itemPrefab,int count){ for(int i = 0;  i < count; i++){GameObject go  =Instantiate(itemPrefab);Vector2 dir = Random.insideUnitCircle.normalized * 0.8f;go.transform.position = new Vector3(dir.x,dir.y,0);} }
}

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

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

相关文章

深入理解 Linux 管道:创建与应用详解(匿名管道进程池)

在现代操作系统中&#xff0c;进程间通信&#xff08;IPC&#xff09;是实现多任务、多进程协作的关键技术之一。Linux 提供了多种 IPC 机制&#xff0c;本博客将帮助您详细的理解进程间通信的原理 首先&#xff0c;在学习管道之前&#xff0c;我们先理解一下管道的存在是为了什…

SWM221系列芯片之电机应用及控制

经过对SWM221系列的强大性能及外设资源&#xff0c;TFTLCD彩屏显示及控制进行了整体介绍后&#xff0c;新迎来我们的电控篇---SWM221系列芯片之电机应用及控制。在微控制器市场面临性能、集成度与成本挑战的当下&#xff0c;SWM221系列芯片以其卓越性能与创新设计&#xff0c;受…

qt qss文件的使用

qt样式的修改方式 一 通过ui界面的改变样式表来直接修改显示效果。 不推荐&#xff0c;其他人不好修改&#xff0c;不够直观&#xff0c;不易维护。 二 通过setStyleSheet接口修改。 一般&#xff0c;界面很少的时候可以使用。一旦界面多起来&#xff0c;代码部分就显得杂乱…

Centos文件已删除空间未释放

原创作者&#xff1a;运维工程师 谢晋 Centos文件已删除空间未释放 释放已删除空间 释放已删除空间 很多时候&#xff0c;你会发现&#xff0c;明明已经删除了文件或日志&#xff0c;但是系统空间就是未缩减&#xff0c;很明显&#xff0c;有空间被已删除文件占用&#xff…

reactor中的并发

1. reactor中的并发有两种方式 1.1 flatmap&#xff0c;底层是多线程并发处理。在reactor的演讲中&#xff0c;flatmap对于io类型的并发效果较好. flamap有两个参数: int concurrency, int prefetch。分别代表并发的线程数和缓存大小 注意凡是参数中有prefetch的&#xff0c;都…

深入 Redis:高级特性与最佳实践

引言 在分布式系统和高并发环境中&#xff0c;Redis 已经成为了一个不可或缺的工具。作为一个内存数据结构存储系统&#xff0c;Redis 不仅支持丰富的数据类型&#xff0c;还提供了高效的操作和极低的延迟&#xff0c;这使得它广泛应用于缓存、消息队列、计数器、排行榜等场景…

如何在 JavaScript 中实现日期格式化?

在 JavaScript 中&#xff0c;日期格式化的常见方法是通过使用内置的 Date 对象来进行处理。JavaScript 本身并没有直接提供一个强大的日期格式化函数&#xff0c;因此通常会使用一些流行的第三方库&#xff0c;比如 date-fns 或 moment.js&#xff0c;但如果我们不依赖外部库&…

Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】

随着城市化进程的快速推进&#xff0c;城市高层建筑不断增多&#xff0c;对建筑质量的要求也在不断提高。建筑外墙检测&#xff0c;如平整度和垂直度检测&#xff0c;是衡量建筑质量的重要指标之一。传统人工检测方法不仅操作繁琐、效率低下&#xff0c;还难以全面反映墙体的真…

浅谈棋牌游戏开发流程二:后端技术选型与基础环境搭建

一、前言&#xff1a;客户端只是台前&#xff0c;后端才是幕后“指挥中心” 在上一篇“客户端技术”中&#xff0c;我们聊到玩家看到的一切动作、动画、界面逻辑&#xff0c;都靠客户端去渲染和交互。但若没有后端的支撑&#xff0c;玩家点了“出牌”可能就像一拳打在空气里—…

机器人手眼标定

机器人手眼标定 一、机器人手眼标定1. 眼在手上标定基本原理2. 眼在手外标定基本原理 二、眼在手外标定实验三、标定精度分析 一、机器人手眼标定 要实现由图像目标点到实际物体上抓取点之间的坐标转换&#xff0c;就必须拥有准确的相机内外参信息。其中内参是相机内部的基本参…

unity中的UI系统---GUI

一、工作原理和主要作用 1.GUI是什么&#xff1f; 即即时模式游戏用户交互界面&#xff08;IMGUI&#xff09;&#xff0c;在unity中一般简称为GUI&#xff0c;它是一个代码驱动的UI系统。 2.GUI的主要作用 2.1作为程序员的调试工具&#xff0c;创建游戏内调测试工具 2.2为…

【Golang 面试题】每日 3 题(二十)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

【JS】Promise的执行顺序

概述 理解 Promise 的执行顺序时&#xff0c;需要牢记以下两点&#xff1a; 微任务与宏任务的优先级&#xff1a; 微任务&#xff1a;Promise.then()、catch、finally 是微任务。宏任务&#xff1a;setTimeout、setInterval 是宏任务。微任务的优先级高于宏任务&#xff1a;在…

Java开发 PDF文件生成方案

业务需求背景 业务端需要能够将考试答卷内容按指定格式呈现并导出为pdf格式进行存档&#xff0c;作为紧急需求插入。导出内容存在样式复杂性&#xff0c;包括特定的字体&#xff08;中文&#xff09;、字号、颜色&#xff0c;页面得有页眉、页码&#xff0c;数据需要进行表格聚…

SpringCloud微服务架构

文章目录 认识微服务&#xff1a;SpringCloud 服务拆分及远程调用实现夸远程服务调用使用RestTemplateEureka注册中心 搭建EruekaServer注册服务服务发现 Ribbon负载均衡 修改负载均衡规则解饿加载 Nacos注册中心&#xff08;nacos一部分功能&#xff09; 服务注册到nacosnacos…

【设计模式-02】23 种设计模式的分类和功能

在软件工程领域&#xff0c;设计模式是解决常见设计问题的经典方案。1994 年&#xff0c;Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides&#xff08;四人帮&#xff0c;GoF&#xff09;在《设计模式&#xff1a;可复用面向对象软件的基础》一书中系统性地总结了…

大模型在自动驾驶领域的应用和存在的问题

大模型在自动驾驶领域的应用与挑战 大模型&#xff08;如 GPT-4、BERT等&#xff09;已经在多个领域取得了突破&#xff0c;自动驾驶是其中一个受益颇多的行业。随着人工智能和深度学习的快速发展&#xff0c;自动驾驶技术正在向更加智能化、自动化和安全的方向发展。大模型在…

简历_专业技能_熟悉分布式锁Redisson的原理以及使用

系列博客目录 文章目录 系列博客目录怎么样才能够在简历上写熟悉redisson的应用以及原理1. 清晰描述技能与经验示例&#xff1a; 2. 列举具体应用场景示例项目经验&#xff1a; 3. 展示你对原理的理解示例&#xff1a; 4. 用简历中的关键词突出你的能力示例段落&#xff1a; 5.…

在 IntelliJ IDEA 中开发 GPT 自动补全插件

背景与目标 随着 AI 的发展&#xff0c;GitHub Copilot 等智能代码补全工具在开发者中获得了广泛的应用&#xff0c;极大地提高了编程效率。本篇文章将教你如何开发一个 IntelliJ IDEA 插件&#xff0c;使用 OpenAI 的 GPT API 来实现类似 Copilot 的代码自动补全功能。通过这…

分布式任务调度xxl-job入门案例

XXL-JOB是一个分布式任务调度平台&#xff0c;简单来说就是可以在你指定的时间内调用某个功能&#xff0c;就例如购物某个商品的限时抢购从什么时候开始以及结束抢购类似于这样的。 下面是它的一个仓库地址 http://gitee.com/xuxueli0323/xxl-job 下载之后将项目导入进idea中&…