【unity实战】手戳一个库存系统,非常适合RPG、Roguelike和星露谷物语之类的游戏

news2025/1/15 17:24:20

文章目录

  • 前言
  • 素材
  • 开始
    • 配置不同物品信息
    • 实例化物品
    • 拾取物品
    • 物品栏、库存大小
    • 寻找物品栏并可以添加物品
    • 库存已满问题解决
    • 库存UI脚本
    • 显示物品信息
    • 切换指示器
    • 丢弃物品
    • 添加丢弃弹出效果
  • 最终效果
  • 源码
  • 完结

前言

其实前面我已经做过了很多次背包库存系统了,背包系统实现方法千千万,条条大陆通罗马。因为背包系统在游戏中实在太常见和关键了。我相信,新的实现探究总会给我们不一样的启发,所以我还是会一直关注实现他们的不同方式,我希望你们也是。

之前实现的背包系统,有兴趣的可以去看看:
复刻类泰瑞利亚生存建造游戏——包括建造系统和库存系统
从零手戳一个库存背包系统
从零手戳一个背包系统

先看看最终效果
在这里插入图片描述

素材

https://cupnooble.itch.io
在这里插入图片描述

开始

配置不同物品信息

自定义物品菜单添加脚本

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

namespace InventorySystem
{
    [CreateAssetMenu(menuName = "库存/物品定义", fileName = "新物品定义")]
    public class ItemDefinition : ScriptableObject
    {
        [SerializeField]
        private string _name;  // 物品名称
        [SerializeField]
        private bool _isStackable;  // 是否可堆叠
        [SerializeField]
        private Sprite _inGameSprite;  // 游戏内显示的精灵图像
        [SerializeField]
        private Sprite _uiSprite;  // UI界面显示的精灵图像

        public string Name => _name;  // 获取物品名称
        public bool IsStackable => _isStackable;  // 获取是否可堆叠
        public Sprite InGameSprite => _inGameSprite;  // 获取游戏内显示的精灵图像
        public Sprite UiSprite => _uiSprite;  // 获取UI界面显示的精灵图像
    }
}

创建几个不同的物品
在这里插入图片描述

实例化物品

物品堆栈,限制物品数量设置

using System;
using UnityEngine;

namespace InventorySystem
{
    [Serializable]
    public class ItemStack
    {
        [SerializeField]
        private ItemDefinition _item;  // 物品定义
        [SerializeField]
        private int _numberOfItems;  // 物品数量

        public bool IsStackable => _item.IsStackable;  // 是否可堆叠
        public ItemDefinition Item => _item;  // 物品定义
        public int NumberOfItems
        {
            get => _numberOfItems;
            set
            {
                value = value < 0 ? 0 : value;  // 确保物品数量不小于零
                _numberOfItems = IsStackable ? value : 1;   // 如果不可堆叠,将物品数量限制在 1 以内
            }
        }

		//构造方法
        public ItemStack(ItemDefinition item, int numberOfItems)
        {
            _item = item;
            NumberOfItems = numberOfItems;
        }
    }
}

物品挂载脚本

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

namespace InventorySystem
{
    public class GameItem : MonoBehaviour
    {
        [SerializeField]
        private ItemStack _stack;  // 物品堆栈
        private SpriteRenderer _spriteRenderer;  // 精灵渲染器

        // 当对象检验时被调用,只要程序员在这个对象上修改了一个字段,Unity就会自动地调用这个函数。
        private void OnValidate()
        {
            SetupGameObject();  // 设置游戏对象
        }

        // 设置游戏对象
        private void SetupGameObject()
        {
            if (_stack.Item == null) return;  // 如果物品为空,返回
            SetGameSprite();  // 设置游戏精灵
            AdjustNumberOfItems();  // 调整物品数量
            UpdateGameObjectName();  // 更新游戏对象名称
        }

        // 设置游戏精灵
        private void SetGameSprite()
        {
            _spriteRenderer = GetComponent<SpriteRenderer>();
            _spriteRenderer.sprite = _stack.Item.InGameSprite;
        }

        // 更新游戏对象名称
        private void UpdateGameObjectName()
        {
            var name = _stack.Item.Name;
            var number = _stack.IsStackable ? _stack.NumberOfItems.ToString() : "ns";  // 判断物品是否可堆叠
            gameObject.name = $"{name} ({number})";  // 修改游戏对象名称
        }

        // 调整物品数量
        private void AdjustNumberOfItems()
        {
            _stack.NumberOfItems = _stack.NumberOfItems;
        }
    }
}

挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

拾取物品

修改GameItem,新增拾取方法

//拾取物品方法
public ItemStack Pick()
{
    Destroy(gameObject);
    return _stack;
}

人物挂载碰撞检测脚本

namespace InventorySystem
{
    public class ItemCollisionHandler : MonoBehaviour
    {
        private void OnTriggerEnter2D(Collider2D col)
        {
            // 检测碰撞的对象是否拥有 GameItem 组件
            var gameItem = col.GetComponent<GameItem>();
            if (gameItem == null) return;
            gameItem.Pick();
        }
    }
}

效果
在这里插入图片描述

物品栏、库存大小

InventorySlot

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

namespace InventorySystem
{
    [System.Serializable]
    public class InventorySlot
    {
        // 物品槽状态改变事件
        public event EventHandler<(ItemStack,bool)> StatChanged;

        public ItemDefinition Item{
            get => _state.Item;
        }
        // 物品堆栈状态
        [SerializeField]
        private ItemStack _state;

        // 物品槽是否处于激活状态
        private bool _active;

        // 物品堆栈状态属性
        public ItemStack State
        {
            get => _state;
            set
            {
                _state = value;
                NotifyAboutStateChange();
            }
        }

        // 物品槽激活状态属性
        public bool Active
        {
            get => _active;
            set
            {
                _active = value;
                NotifyAboutStateChange();
            }
        }

        // 物品数量属性
        public int NumberOfItems
        {
            get => _state.NumberOfItems;
            set
            {
                _state.NumberOfItems = value;
                NotifyAboutStateChange();
            }
        }

        // 判断物品槽是否有物品(即物品堆栈中的物品不为空)
        public bool HasItem => _state?.Item != null;

        // 清空物品槽
        public void Clear()
        {
            State = null;
        }

        // 通知物品槽状态改变
        private void NotifyAboutStateChange()
        {
            StatChanged?.Invoke(this, (_state, _active));
        }
    }
}
namespace InventorySystem
{
    public class Inventory : MonoBehaviour
    {
        [SerializeField]
        private int _size = 8; // 背包大小
        [SerializeField]
        private List<InventorySlot> _slots; // 物品槽列表

        private void OnValidate()
        {
            AdjustSize(); // 检查并调整背包大小
        }

        /// <summary>
        /// 检查并调整背包大小
        /// </summary>
        private void AdjustSize()
        {
            _slots ??= new List<InventorySlot>(); // 如果物品槽列表为空,则初始化为一个空的列表
            if (_slots.Count > _size) // 如果物品槽数量大于背包大小
                _slots.RemoveRange(_size, _slots.Count - _size); // 移除多余的物品槽
            if (_slots.Count < _size) // 如果物品槽数量小于背包大小
                _slots.AddRange(new InventorySlot[_size - _slots.Count]); // 添加空的物品槽,直到数量达到背包大小
        }
    }
}

效果
在这里插入图片描述

寻找物品栏并可以添加物品

修改inventory代码

/// <summary>
/// 判断背包是否已满
/// </summary>
public bool IsFull()
{
    return _slots.Count(slot => slot.HasItem) >= _size; // 如果已占用的物品槽数量大于等于背包大小,则背包已满
}

/// <summary>
/// 判断是否可以接收物品堆叠
/// </summary>
/// <param name="itemStack">物品堆叠</param>
/// <returns>如果可以接收,则返回true;否则返回false</returns>
public bool CanAcceptItem(ItemStack itemStack)
{
    var slotWithStackableItem = FindSlot(itemStack.Item, onlyStackable: true); // 查找可以堆叠的物品槽
    return !IsFull() || slotWithStackableItem != null; // 如果背包未满或找到了一个可以堆叠的物品槽,就可以接收该物品
}

/// <summary>
/// 查找具有指定物品的物品槽
/// </summary>
/// <param name="item">物品定义</param>
/// <param name="onlyStackable">是否只查找可堆叠的物品槽</param>
/// <returns>如果找到,返回具有指定物品的物品槽;否则返回null</returns>
private InventorySlot FindSlot(ItemDefinition item, bool onlyStackable = false)
{
    // 遍历物品槽列表,找到第一个物品槽的Item属性等于指定物品的Item属性,并且该物品符合是否只查找可堆叠的物品槽的要求
    return _slots.FirstOrDefault(slot => slot.Item == item && (item.IsStackable || !onlyStackable));
}

/// <summary>
/// 向背包中添加物品堆叠
/// </summary>
/// <param name="itemStack">物品堆叠</param>
/// <returns>实际添加到背包中的物品堆叠</returns>
public ItemStack AddItem(ItemStack itemStack)
{
    var relevantSlot = FindSlot(itemStack.Item, true); // 查找具有相同物品的物品槽
    if (IsFull() && relevantSlot == null) // 如果背包已满并且无法找到可以堆叠的物品槽,就抛出异常
    {
        throw new InventoryException(InventoryOperation.Add, "Inventory is full");
    }
    if (relevantSlot != null) // 如果找到了可以堆叠的物品槽
    {
        relevantSlot.NumberOfItems += itemStack.NumberOfItems; // 合并物品堆叠数量
    }
    else // 如果没有找到可以堆叠的物品槽
    {
        relevantSlot = _slots.First(slot => !slot.HasItem); // 找到第一个空的物品槽
        relevantSlot.State = itemStack; // 设置该物品槽的物品堆叠为指定的物品堆叠
    }
    return relevantSlot.State; // 返回实际添加到背包中的物品堆叠
}

背包异常类InventoryException

using System;

namespace InventorySystem
{
    // 背包操作枚举类型
    public enum InventoryOperation
    {
        Add,// 添加物品
        Remove// 移除物品
    }

    // 背包异常类
    public class InventoryException : Exception
    {
        public InventoryOperation Operation { get; }// 引发异常时的背包操作
        public InventoryException(InventoryOperation operation, string msg) : base($"{operation} Error: {msg}")// 构造函数
        {
            Operation = operation;
        }
    }
}

修改ItemCollisionHandler代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace InventorySystem
{
    public class ItemCollisionHandler : MonoBehaviour
    {
        private Inventory _inventory;
        private void Awake()
        {
            _inventory = GetComponentInParent<Inventory>();
        }
        private void OnTriggerEnter2D(Collider2D col)
        {
            // 检测碰撞的对象是否拥有 GameItem 组件
            var gameItem = col.GetComponent<GameItem>();
            if (gameItem == null) return;
            _inventory.AddItem(gameItem.Pick());
        }

    }
}

效果
在这里插入图片描述

库存已满问题解决

修改GameItem

public ItemStack Stack =>_stack;

修改

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace InventorySystem
{
    public class ItemCollisionHandler : MonoBehaviour
    {
        private Inventory _inventory;
        private void Awake()
        {
            _inventory = GetComponentInParent<Inventory>();
        }
        private void OnTriggerEnter2D(Collider2D col)
        {
            // 检测碰撞的对象是否拥有 GameItem 组件
            var gameItem = col.GetComponent<GameItem>();
            if (gameItem == null || !_inventory.CanAcceptItem(gameItem.Stack)) return;
            _inventory.AddItem(gameItem.Pick());
        }

    }
}

库存UI脚本

绘制插槽ui
在这里插入图片描述

文字粗细和轮廓
在这里插入图片描述
新增UI_InventorySlot脚本

public class UI_InventorySlot : MonoBehaviour
{
}

新增UI_Inventory脚本

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

namespace InventorySystem.UI
{
    // UI物品栏界面类
    public class UI_Inventory : MonoBehaviour
    {
        // 物品槽预制体
        [SerializeField]
        private GameObject _inventorySlotPrefab;
        // 对应的物品栏
        [SerializeField]
        private Inventory _inventory;
        // 物品槽列表
        [SerializeField]
        private List<UI_InventorySlot> _slots;

        // 物品栏属性
        public Inventory Inventory => _inventory;

        // 初始化物品栏UI
        [ContextMenu("初始化库存")]
        private void InitializeInventoryUi()
        {
            if (_inventory == null || _inventorySlotPrefab == null)
                return;

            _slots = new List<UI_InventorySlot>(_inventory.Size);
            for (var i = 0; i < _inventory.Size; i++)
            {
                // 实例化物品槽预制体
                var uiSlot = Instantiate(_inventorySlotPrefab, transform);
                var uiSlotScript = uiSlot.GetComponent<UI_InventorySlot>();

                // 将实例化生成的物品槽脚本添加到列表中
                _slots.Add(uiSlotScript);
            }
        }
    }
}

修改Inventory

public int Size =>_size;

效果
在这里插入图片描述

显示物品信息

修改插槽脚本UI_InventorySlot

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

namespace InventorySystem.UI
{
    public class UI_InventorySlot : MonoBehaviour
    {
        // 物品栏
        [SerializeField]
        private Inventory _inventory;
        // 物品槽索引
        [SerializeField]
        private int _inventorySlotIndex;
        // 物品图标
        [SerializeField]
        private Image _itemIcon;
        // 激活指示器
        [SerializeField]
        private Image _activeIndicator;
        // 物品数量文本
        [SerializeField]
        private TMP_Text _numberOfItems;
        // 物品槽
        private InventorySlot _slot;

        private void Start()
        {
            AssignSlot(_inventorySlotIndex);
        }

        // 分配物品槽
        public void AssignSlot(int slotIndex)
        {
            // 取消之前的事件监听
            if (_slot != null) _slot.StateChanged -= OnStateChanged;

            // 更新物品槽索引
            _inventorySlotIndex = slotIndex;

            // 获取所属的物品栏
            if (_inventory == null) _inventory = GetComponentInParent<UI_Inventory>().Inventory;

            // 获取物品槽
            _slot = _inventory.Slots[_inventorySlotIndex];

            // 添加事件监听
            _slot.StateChanged += OnStateChanged;

            // 更新视图状态
            UpdateViewState(_slot.State, _slot.Active);
        }

        // 更新视图状态
        private void UpdateViewState(ItemStack state, bool active)
        {
            // 更新激活指示器
            _activeIndicator.enabled = active;

            var item = state?.Item;
            var hasItem = item != null;
            var isStackable = hasItem && item.IsStackable;

            // 更新物品图标显示
            _itemIcon.enabled = hasItem;

            // 更新物品数量文本显示
            _numberOfItems.enabled = isStackable;

            if (!hasItem) return;

            // 更新物品图标
            _itemIcon.sprite = item.UiSprite;

            if (isStackable)
            {
                // 更新物品数量文本
                _numberOfItems.SetText(state.NumberOfItems.ToString());
            }
        }

        // 物品槽状态改变事件处理方法
        // private void OnStateChanged(object sender, InventorySlotStateChangedArgs args)
        // {
        //     UpdateViewState(args.NewState, args.Active);
        // }
         private void OnStateChanged(object sender, (ItemStack, bool) e)
        {
            UpdateViewState(e.Item1,e.Item2);
        }
    }
}

修改UI_Inventory

private void InitializeInventoryUi()
{
    //。。。
    for (var i = 0; i < _inventory.Size; i++)
    {
        // 。。。
        uiSlotScript.AssignSlot(i);
        // 。。。
    }
}

修改Inventory

public List<InventorySlot> Slots => _slots;

效果
在这里插入图片描述

切换指示器

新增InventoryInputHandler脚本,挂载在任务身上

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

namespace InventorySystem
{
    public class InventoryInputHandler : MonoBehaviour
    {
        private Inventory _inventory;

        // 初始化_inventory变量
        private void Awake()
        {
            _inventory = GetComponent<Inventory>();
        }

        // 每帧检查是否响应按键
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Q))
            {
                OnPreviousItem(); // 选择上一项
            }
            if (Input.GetKeyDown(KeyCode.E))
            {
                OnNextItem(); // 选择上一项
            }
        }

        // 选择下一项物品
        private void OnNextItem()
        {
            _inventory.ActivateSlot(_inventory.ActiveSlotIndex + 1);
        }

        // 选择上一项物品
        private void OnPreviousItem()
        {
            _inventory.ActivateSlot(_inventory.ActiveSlotIndex - 1);
        }
    }
}

修改Inventory

private void Awake()
{
    if (_size > 0)
    {
        _slots[0].Active = true;// 激活第一个物品槽
    }
}

public void ActivateSlot(int atIndex)
{
    ActiveSlotIndex = atIndex;
}

效果

在这里插入图片描述

丢弃物品

修改InventoryInputHandler

void Update()
{
    if (Input.GetKeyDown(KeyCode.G))
    { // 如果按下G键
        OnThrowItem(); // 丢弃物品
    }
}

// 丢弃当前物品
private void OnThrowItem()
{
    _inventory.RemoveItem(_inventory.ActiveSlotIndex, true);
}

新增GameItemSpawner代码,生成物品,挂载在人物身上

namespace InventorySystem
{
    public class GameItemSpawner : MonoBehaviour
    {
        [SerializeField]
        private GameObject _itemBasePrefab;

        // 生成物品
        public void SpawnItem(ItemStack itemStack)
        {
            // 如果物品基础预制体为空,直接返回
            if (_itemBasePrefab == null) return;

            Debug.Log(transform.position);

            // 实例化物品基础预制体,并将其设置为当前对象的子对象
            var item = Instantiate(_itemBasePrefab, transform.position, Quaternion.identity);
            item.transform.SetParent(null);

            // 获取物品的GameItem组件
            var gameItemScript = item.GetComponent<GameItem>();

            // 设置堆叠数量和物品定义到GameItem组件
            gameItemScript.SetStack(new ItemStack(itemStack.Item, itemStack.NumberOfItems));
        }
    }
}

修改Inventory

private int _activeSlotIndex;

public int ActiveSlotIndex
{
   get => _activeSlotIndex;
    private set
    {
        _slots[_activeSlotIndex].Active = false;
        _activeSlotIndex = value < 0 ? _size - 1 : value % Size;// 如果索引小于0,循环到最后一个物品槽;否则取模获取合法索引
        _slots[_activeSlotIndex].Active = true;
    }
}

public bool HasItem(ItemStack itemStack, bool checkNumberOfItems = false)
{
    var itemSlot = FindSlot(itemStack.Item);
    if (itemSlot == null) return false;
    if (!checkNumberOfItems) return true;
    if (itemStack.Item.IsStackable)
    {
        return itemSlot.NumberOfItems >= itemStack.NumberOfItems; // 检查物品数量是否足够
    }
    return _slots.Count(slot => slot.Item == itemStack.Item) >= itemStack.NumberOfItems;// 检查物品槽数量是否足够
}
        
public ItemStack RemoveItem(int atIndex, bool spawn = false)
{
   if (!_slots[atIndex].HasItem)
        throw new InventoryException(InventoryOperation.Remove, "槽位为空");

    if (spawn && TryGetComponent<GameItemSpawner>(out var itemSpawner))
    {
        // 添加生成物品的逻辑
        itemSpawner.SpawnItem(_slots[atIndex].State);
    }
    ClearSlot(atIndex);
    return new ItemStack(null, 0);
}

public void ClearSlot(int atIndex)
{
    _slots[atIndex].Clear();
}

修改GameItem

// 设定物品堆栈
public void SetStack(ItemStack itemStack)
{
    _stack = itemStack;
}

效果
在这里插入图片描述

添加丢弃弹出效果

修改GameItemSpawner

// 生成物品
public void SpawnItem(ItemStack itemStack)
{
    // 。。。

    // 抛掷物品(根据当前对象的缩放比例来确定抛掷方向)
    gameItemScript.Throw(transform.localScale.x);
}

修改GameItem

[Header("丢弃设置")]
[SerializeField]
private float _colliderEnabledAfter = 1f; // 多少秒后启用碰撞器
[SerializeField]
private float _throwGravity = 2f; // 扔出的物品受到的重力系数
[SerializeField]
private float _minThrowXForce = 3f; // 扔出物品时在X轴方向最小的力量值
[SerializeField]
private float _maxThrowXForce = 5f; // 扔出物品时在X轴方向最大的力量值
[SerializeField]
private float _throwYForce = 5f; // 扔出物品时在Y轴方向的力量值
private Collider2D _collider; // 碰撞器
private Rigidbody2D _rb; // 刚体

// 初始化
private void Awake()
{
    _collider = GetComponent<Collider2D>();
    _rb = GetComponent<Rigidbody2D>();
    _collider.enabled = false; // 防止在还没扔出时被玩家拾取
}

// 开始游戏时的初始化
private void Start()
{
    SetupGameObject(); // 设置游戏对象
    StartCoroutine(EnableCollider(_colliderEnabledAfter)); // 在设定的时间后启用碰撞器
}

// 等待一段时间后启用碰撞器
private IEnumerator EnableCollider(float afterTime)
{
    yield return new WaitForSeconds(afterTime);
    _collider.enabled = true;
}

// 扔出物品
public void Throw(float xDir)
{
    _rb.gravityScale = _throwGravity; // 设定重力值
    var throwXForce = Random.Range(_minThrowXForce, _maxThrowXForce); // 随机力量值
    _rb.velocity = new Vector2(Mathf.Sign(xDir) * throwXForce, _throwYForce); // 设定物体的速度向量
    StartCoroutine(DisableGravity(_throwYForce));
}

// 一定的高度后禁用重力,让物品飞行更自然
private IEnumerator DisableGravity(float atYVelocity)
{
    yield return new WaitUntil(() => _rb.velocity.y < -atYVelocity);
    _rb.velocity = Vector2.zero;
    _rb.gravityScale = 0;
}

效果
在这里插入图片描述

最终效果

在这里插入图片描述

源码

整理好后我会放上来

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

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

相关文章

【计算机网络】数据链路层(学习笔记)

一、数据链路层概述 1、基本概念 1&#xff09;数据链路层模型 2&#xff09;数字管道 常常在两个对等的数据链路层之间画出一个数字管道&#xff0c;而在这条数字管道上传输的数据单位是帧。 3&#xff09;链路与数据链路 链路是一条点到点的物理线路段&#xff0c;中间没…

Vue中如何进行滚动加载与无限滚动

Vue中的滚动加载与无限滚动 滚动加载&#xff08;Infinite Scroll&#xff09;是现代Web应用程序中常见的用户体验功能之一。它允许在用户滚动到页面底部时自动加载更多内容&#xff0c;通常用于分页显示大量数据。Vue.js作为一种流行的前端框架&#xff0c;提供了实现滚动加载…

备忘录:Docker基础操作与常用命令

文章目录 Docker基础操作1.1 Docker在线安装1.1.1 安装基础软件包1.1.2 安装docker主程序1.1.2.1 设置国内源1.1.2.2 安装docker 1.2 Docker离线安装1.2.1 下载离线安装包1.2.2 安装docker依赖包以及docker 1.3 设置自启动并启动dokcer1.4 安装docker-compose1.4.1 命令行下载文…

ADB的概念、使用场景、工作原理

文章目录 一、adb概念&#xff1a;Android Debug Bridge&#xff0c;一个可以控制安卓设备的通用命令行工具二、adb的使用场景&#xff1a;操作手机设备、app 自动化测试1.传输文件2.兼容性测试&#xff08;手机墙&#xff09;3.云测平台4.测试框架底层封装&#xff1a;APP自动…

柠檬水找零【贪心1】

由于是贪心算法的第一道题&#xff0c;所以先介绍一下贪心算法。 贪心策略&#xff1a;一种解决问题的策略&#xff0c;局部最优->全局最优。&#xff08;贪婪鼠目寸光&#xff09; 1、把解决问题的过程分为若干步 2、解决每一步时&#xff0c;都选择当前看起来最优的解法。…

tcp滑动窗口原理

18.1 滑动窗口 我们再来看这个比喻&#xff1a; 网络仅仅是保证了整个网络的连通性&#xff0c;我们我们基于整个网络去传输&#xff0c;那么是不是我想发送多少数据就发送多少数据呢&#xff1f;如果是这样的话&#xff0c;是不是就会像我们的从一个池塘抽水去灌到另外一个…

【Java】微服务——微服务介绍和Eureka注册中心

目录 1.微服务介绍2.服务拆分和远程调用2.1.提供者与消费者 3.Eureka注册中心3.1.Eureka的结构和作用3.2.Eureka的结构3.3.搭建Eureka服务3.3.1.引入eureka依赖3.3.2.编写配置文件 3.4.服务注册及拉1&#xff09;引入依赖2&#xff09;配置文件3&#xff09;启动多个user-servi…

剑指offer——JZ24 反转链表 解题思路与具体代码

一、题目描述与要求 反转链表_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 数据范围&#xff1a; …

Mongodb7启动报错排除解决方案

一&#xff1a; 报错信息: [rootwww log]# journalctl -xe -- Unit mongodb.service has begun starting up. /usr/local/mongodb/mongdb7/bin/mongod --help for more information 10月 03 13:47:39 www.yhchange.com systemd[1]: mongodb.service: control process exited, …

10.03

代码 #include <iostream>using namespace std; class cz { private:int num1; //实部int num2; //虚部 public:cz(){}cz(int a,int b):num1(a),num2(b){}cz(const cz &other):num1(other.num1),num2(other.num2){}~cz(){}const cz operator(const cz &othe…

2023年中国BaaS行业发展概况及未来发展趋势分析:未来多链支持和发展将是BaaS平台发展重点方向[图]

BaaS是指将区块链框架嵌入云计算平台&#xff0c;利用云服务基础设施的部署和管理优势&#xff0c;为开发者提供便捷、高性能的区块链生态环境和生态配套服务&#xff0c;支持开发者的业务拓展及运营支持的区块链开放平台。通常情况下&#xff0c;一套完整的 BaaS 解决方案包括…

文件管理:极速复制粘贴,畅享无限次文件管理!

亲爱的用户&#xff0c;您是否经常需要将文件夹里的所有文件进行无限次复制粘贴&#xff0c;但又觉得这个过程繁琐而耗时&#xff1f;现在&#xff0c;我们为您推出一款极速文件管理工具&#xff0c;让您可以轻松实现无限次的文件复制粘贴&#xff0c;让文件管理更加高效畅快&a…

正则验证用户名和跨域postmessage

正则验证用户名 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </hea…

剑指offer——JZ6 从尾到头打印链表 解题思路与具体代码

一、题目描述与要求 从尾到头打印链表_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一个链表的头节点&#xff0c;按链表从尾到头的顺序返回每个节点的值&#xff08;用数组返回&#xff09;。 如输入{1,2,3}的链表如下图: 返回一个数组为[3,2,1] 0 < 链表长度 < …

最新SparkAI创作系统V2.6.2/ChatGPT网站系统H5源码+微信公众号版+AI绘画系统源码/支持GPT联网提问/支持Prompt应用

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的AI智能问答系统和AI绘画系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图…

2023年中国电动汽车充换电站行业现状分析:随车配建私人充电桩增量持续上升[图]

充电站指为电动汽车提供充电服务的专用场所&#xff0c;由多台集中布置的充电设备以及相关的供电设备、监控设备﹑配套设施等组成。可将充电站规模分为3类&#xff1a;大型充电站、中型充电站和小型充电站。换电站指为电动汽车提供电池更换服务的场所。按换电模式分类&#xff…

掌机小霸王,开源俄罗斯方块小游戏

俄罗斯方块试玩gi PC或手机 点开即玩: https://chvin.github.io/react-tetris/?lanzh-cn 也可以扫码开玩: 实现了数据的持久化 游戏进度的数据可以持久存储到本地浏览器, 即使刷新网页也无需重新开始游戏 小结: 俄罗斯方块属于超级经典的游戏, 感兴趣可以玩一下, 找回一点童…

【算法练习Day10】有效的括号删除字符串中的所有相邻重复项逆波兰表达式求值

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 有效的括号删除字符串中的所…

树莓派4B与STM32串口通信

目录 2上篇文章的补充 2.1 树莓派通信设置 3树莓派与STM32通信 3.1接线准备 3.2代码 3.2.1 STM32代码&#xff1a; 3.2.2树莓派代码&#xff1a; 2上篇文章的补充 2.1 树莓派通信设置 在上篇文章的基础上&#xff0c;进一步的设置 终端输入&#xff1a;sudo minicom …