• Unity3D学习笔记(二十六):MVC框架下的背包系统(1)


    MVC背包

    需求:
    1、背包格子的装备是可以拖动的
    2、装备栏的装备也是可以拖动的
    3、当背包格子的装备拖动到装备栏时,如果是装备类型和装备栏类型是一致的能装上
    4、背包的装备是按照顺序放在格子中的,有分页的功能
    5、每件装备上有物品的属性加成
    6、人物有基本的属性和装备加成的属性,界面显示就是基本属性+ 加成属性(绿色标识)
    7、当你拖动背包的装备时,对应能装备该物品的装备栏要提示
    8、不光需要拖动才能装备,鼠标右键点击装备也能装备或卸下
    9、背包是通过负重来显示装备的多少的
    10、背包的装备拖动到非背包区域,可以销毁
    11、鼠标悬停装备时,显示装备的属性信息
    12、一件整理,把相同类型的装备放在一起(考虑权重)
    13、一件出售
     
    MVC结构
    Model(数据层)
    1、每一件装备需要一个类来存储属性信息
    2、人物的基本属性,和身上的装备,装备的加成需要一个类来存储
    3、背包里的装备和背包的负重需要一个类来存储
     
    View(视图层)
    1、每个格子是可以拖动装备的,对于背包的格子和装备栏的格子拖动的功能是一致的,但是拖动结束时的判断不一致,我们可以把共有的功能抽象出来一个基类,两个子类分别继承基类。
    2、对于人物显示的界面,需要一个类来管理装备栏的装备,显示人物的属性。
    3、需要一个背包的类来管理每个格子,显示页数,负重等信息。
    4、当鼠标放在装备上时,显示装备的基本信息也需要一个类来做处理。
     
    Control(控制层)
    需要一个控制层来做数据的交换,删除等等
     
    界面搭建
    画布尺寸1920x1080
    字体锚点
    字体自适应10-20

    限制列数,中心对齐

    Model
    ItemData,物品信息类
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    /// <summary>
    /// 该类用于存储装备的基本属性
    /// </summary>
    [System.Serializable]
    public class ItemData
    {
        #region 私有变量
        [SerializeField]
        private int id;//作为物品的唯一标识
        [SerializeField]
        private string itemName;//物品的名字
        [SerializeField]
        private string iconName;//物品显示图片的名字
        [SerializeField]
        private float atk;//攻击力加成
        [SerializeField]
        private float def;//防御力加成
        [SerializeField]
        private float thump;//暴击率加成
        [SerializeField]
        private float hp;//血量加成
        [SerializeField]
        private float mp;//加成
        [SerializeField]
        private float anger;//怒气加成
        [SerializeField]
        private float weight;//重量
        [SerializeField]
        private ItemType type;//物品的类型
        #endregion
        #region 属性
        public int Id
        {
            get
            {
                return id;
            }
        }
        public string ItemName
        {
            get
            {
                return itemName;
            }
        }
        public string IconName
        {
            get
            {
                return iconName;
            }
        }
        public float Atk
        {
            get
            {
                return atk;
            }
        }
        public float Def
        {
            get
            {
                return def;
            }
        }
        public float Thump
        {
            get
            {
                return thump;
            }
        }
        public float Hp
        {
            get
            {
                return hp;
            }
        }
        public float Mp
        {
            get
            {
                return mp;
            }
        }
        public float Anger
        {
            get
            {
                return anger;
            }
        }
        public float Weight
        {
            get
            {
                return weight;
            }
        }
        public ItemType Type
        {
            get
            {
                return type;
            }
        }
        #endregion
        #region 构造函数
        public ItemData() { }
        public ItemData(int id, string itemName, string iconName, float atk,
            float def, float thump, float hp, float mp, float anger, float weight, ItemType type)
        {
            this.id = id;
            this.itemName = itemName;
            this.iconName = iconName;
            this.atk = atk;
            this.def = def;
            this.thump = thump;
            this.hp = hp;
            this.mp = mp;
            this.anger = anger;
            this.weight = weight;
            this.type = type;
        }
        #endregion
    }

    ItemType,物品类型类

    /// <summary>
    /// 物品的类型, 装备栏能装备的类型
    /// </summary>
    public enum ItemType
    {
        Weapon,//武器
        Cap,//头盔
        Armour,//铠甲
        Ring,//戒指
        Belt,//腰带
        Necklace,//项链
        Shoe,//鞋子
        Headwear,//头饰
    }

    PlayerData,角色装备类

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class PlayerData
    {
        #region 单例
        private static PlayerData instance;//这个数据类的单例,从文件中反序列化来的
        public static PlayerData Instance
        {
            get
            {
                return instance;
            }
        }
        private PlayerData() { }
        /// <summary>
        /// 对单例进行赋值
        /// </summary>
        /// <param name="data"></param>
        public static void SetInstance(PlayerData data)
        {
            if (null == data)
            {
                instance = new PlayerData();
            }
            else
            {
                instance = data;
            }
        }
        #endregion
        #region 私有变量
        [SerializeField]
        private List<ItemData> items;//人物身上穿戴的装备
        [SerializeField]
        private float atk;//基础攻击力
        [SerializeField]
        private float def;//基础防御力
        [SerializeField]
        private float thump;//基础暴击率
        [SerializeField]
        private float hp;//基础血量
        [SerializeField]
        private float mp;//基础魔法
        [SerializeField]
        private float anger;//基础怒气
        //装备的属性加成都是装备的装备计算出来的
        private float addAtk;//装备攻击力加成
        private float addDef;//
        private float addThump;//
        private float addHp;//
        private float addMp;//
        private float addAnger;//
        #endregion
        #region 属性
        public float Atk
        {
            get
            {
                return atk;
            }
        }
        public float Def
        {
            get
            {
                return def;
            }
        }
        public float Thump
        {
            get
            {
                return thump;
            }
        }
        public float Hp
        {
            get
            {
                return hp;
            }
        }
        public float Mp
        {
            get
            {
                return mp;
            }
        }
        public float Anger
        {
            get
            {
                return anger;
            }
        }
        public float AddAtk
        {
            get
            {
                return addAtk;
            }
        }
        public float AddDef
        {
            get
            {
                return addDef;
            }
        }
        public float AddThump
        {
            get
            {
                return addThump;
            }
        }
        public float AddHp
        {
            get
            {
                return addHp;
            }
        }
        public float AddMp
        {
            get
            {
                return addMp;
            }
        }
        public float AddAnger
        {
            get
            {
                return addAnger;
            }
        }
        public List<ItemData> Items
        {
            get
            {
                return items;
            }
        }
        #endregion
        #region 提供一些访问或删除装备的方法
        /// <summary>
        /// 通过装备的ID来访问装备
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ItemData GetItem(int id)
        {
            return null;
        }
        /// <summary>
        /// 通过装备的类型来访问装备
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public ItemData GetItem(ItemType type)
        {
            return null;
        }
        /// <summary>
        /// 添加装备
        /// </summary>
        /// <param name="data"></param>
        public void AddItem(ItemData data)
        {
        }
        /// <summary>
        /// 删除装备
        /// </summary>
        /// <param name="data"></param>
        public void RemoveItem(ItemData data)
        {
        }
        /// <summary>
        /// 通过ID删除装备
        /// </summary>
        /// <param name="id"></param>
        public void RemoveItem(int id)
        {
        }
        /// <summary>
        /// 通过装备类型删除装备
        /// </summary>
        /// <param name="type"></param>
        public void RemoveItem(ItemType type)
        {
        }
        #endregion
        public void Init()
        {
            UpdateAdditionData();
        }
        /// <summary>
        /// 计算装备的加成数据, 每次当数据发生改变的时候调用
        /// </summary>
        void UpdateAdditionData()
        {
            this.addAtk = 0;
            this.addDef = 0;
            this.addThump = 0;
            this.addHp = 0;
            this.addMp = 0;
            this.addAnger = 0;
            //把每一件装备的加成数据加给实际的数据
            for (int i = 0; i < items.Count; i++)
            {
                this.addAtk += items[i].Atk;
                this.addDef += items[i].Def;
                this.addThump += items[i].Thump;
                this.addHp += items[i].Hp;
                this.addMp += items[i].Mp;
                this.addAnger += items[i].Anger;
            }
        }
    }

    BagData,背包物品类

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class BagData
    {
        #region 单例
        private static BagData instance;//从文件中反序列化来的
        public static BagData Instance
        {
            get
            {
                return instance;
            }
        }
        private BagData() { }
        public static void SetInstance(BagData data)
        {
            if (data == null)
            {
                data = new BagData();
                data.items = new List<ItemData>();
            }
            else
            {
                instance = data;
            }
        }
        #endregion
        #region 私有变量
        [SerializeField]
        private List<ItemData> items;//当前的所有的装备
        [SerializeField]
        private float maxCapacity;//最大容量, 从文件中读取进来的
        private float currentCapacity;//当前容量, 根据当前背包的装备计算出来的
        #endregion
        #region 属性
        public float MaxCapacity
        {
            get
            {
                return maxCapacity;
            }
        }
        public float CurrentCapacity
        {
            get
            {
                return currentCapacity;
            }
        }
        public List<ItemData> Items
        {
            get
            {
                return items;
            }
        }
        #endregion
        #region 提供一些操作背包装备的方法
        /// <summary>
        /// 使用ID访问背包中的装备
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ItemData GetItem(int id)
        {
            return null;
        }
        /// <summary>
        /// 添加装备
        /// </summary>
        /// <param name="id"></param>
        public void AddItem(ItemData data)
        {
        }
        /// <summary>
        /// 删除装备
        /// </summary>
        /// <param name="data"></param>
        public void RemoveItem(ItemData data)
        {
        }
        /// <summary>
        /// 删除指定ID的装备
        /// </summary>
        /// <param name="id"></param>
        public void RemoveItem(int id)
        {
        }
        #endregion
        public void UpdateCurrentCapacity()
        {
            currentCapacity = 0;
            //把每一件装备的负重累加在一起,就是当前的负重
            for (int i = 0; i < items.Count; i++)
            {
                currentCapacity += items[i].Weight;
            }
        }
    }
     
    View:人物界面UI:属性,装备
    GridBase,格子基类
    PlayerGridUI,格子子类-玩家
    BagGridUI,格子子类-背包
    PlayerUI,玩家界面
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    public class PlayerUI : MonoBehaviour {
        private GridBase[] grids;//所有的装备栏
        //所有显示属性的Text
        private Text atkText;
        private Text defText;
        private Text thumpText;
        private Text hpText;
        private Text mpText;
        private Text angerText;
        void Awake()
        {
            //在子物体里获取所有的GridBase这个组件,返回的是一个数组
            grids = gameObject.GetComponentsInChildren<GridBase>();
            atkText = transform.Find("MessageUI/Message/AtkText").GetComponent<Text>();
            defText = transform.Find("MessageUI/Message/DefText").GetComponent<Text>();
            thumpText = transform.Find("MessageUI/Message/ThumpText").GetComponent<Text>();
            hpText = transform.Find("MessageUI/Message/HPText").GetComponent<Text>();
            mpText = transform.Find("MessageUI/Message/MPText").GetComponent<Text>();
            angerText = transform.Find("MessageUI/Message/AngerText").GetComponent<Text>();
            //新建Json的小技巧
            //ItemData data = new ItemData();
            //Debug.Log(JsonUtility.ToJson(data, true));
        }
        private void Start()
        {
            UpdatePanel();
        }
        /// <summary>
        /// 更新界面的方法
        /// </summary>
        void UpdatePanel()
        {
            //把人物身上装备的物品显示, 所有属性显示
            atkText.text = "攻击力:" + PlayerData.Instance.Atk + "<color="green"> + "
                + PlayerData.Instance.AddAtk + "</color>";
            defText.text = "防御力:" + PlayerData.Instance.Def + "<color="green"> + "
                + PlayerData.Instance.AddDef + "</color>";
            thumpText.text = "暴击率:" + PlayerData.Instance.Thump + "<color="green"> + "
                + PlayerData.Instance.AddThump + "</color>";
            hpText.text = "生命值:" + PlayerData.Instance.Hp + "<color="green"> + "
                + PlayerData.Instance.AddHp + "</color>";
            mpText.text = "魔法值:" + PlayerData.Instance.Mp + "<color="green"> + "
                + PlayerData.Instance.AddMp + "</color>";
            angerText.text = "怒气值:" + PlayerData.Instance.Anger + "<color="green"> + "
                + PlayerData.Instance.AddAnger + "</color>";
        }
    }

    BagUI,背包UI

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    public class BagUI : MonoBehaviour {
        private GridBase[] grids;
        private Text weightText;
        private Text numText;
        private Button rightButton;
        private Button leftButton;
        private Button clearUpButton;
        private int currentNum;
        private int maxNum;//根据背包里物品数量与当前有多少个格子比较
        void Awake()
        {
            //获取所有的格子
            grids = gameObject.GetComponentsInChildren<GridBase>();
            weightText = transform.Find("Capacity/Text").GetComponent<Text>();
            numText = transform.Find("Page/PageNum/Text").GetComponent<Text>();
            rightButton = transform.Find("Page/RightButton").GetComponent<Button>();
            leftButton = transform.Find("Page/LeftButton").GetComponent<Button>();
            clearUpButton = transform.Find("ClearUpButton").GetComponent<Button>();
            //按钮注册事件
            rightButton.onClick.AddListener(RightClick);
            leftButton.onClick.AddListener(LeftClick);
            clearUpButton.onClick.AddListener(ClearUpClick);
        }
        private void Start()
        {
            //maxNum = (int)Mathf.Ceil(BagData.Instance.Items.Count / (float)grids.Length);
            currentNum = 1;//界面一开始,当前页是1
            //UpdatePanel();
        }
        /// <summary>
        /// 更新界面
        /// </summary>
        void UpdatePanel()
        {
            //更新当前页数的物品, 更新当前页数, 更新当前的负重
            //计算当前的最大页数
            maxNum = (int)Mathf.Ceil(BagData.Instance.Items.Count / (float)grids.Length);
            weightText.text = "负重:" + BagData.Instance.CurrentCapacity + "/" +
                BagData.Instance.MaxCapacity;
            numText.text = currentNum + "/" + maxNum;
            //显示当前的页数的物品
            //根据当前页数,确定第一个位置应该排背包数据的里的第几个索引(起始索引)
            //模拟 格子: 20   当第一页是起始索引为0, 当第二页时起始索引为20
            int startIndex = (currentNum - 1) * grids.Length;//(当前页数 - 1) * 格子数量
            //把从起始索引开始,依次的把物品放在对应的格子上
            for (int i = 0; i < grids.Length; i++)
            {
                //当i= 0时,证明是第一个格子,对应的物品索引 startIndex = startIndex + i
                //当i= 1时,证明是第二各格子,对应的物品索引 startIndex + 1 =  startIndex + i
                //....
                //当i = grids.Length - 1时, 最后一个格子, 对应的物品索引 startIndex + grids.Length - 1 =  startIndex + i
                //如果startIndex + i 超出了物品的数量, 证明这个格子没有物品
                //如果startIndex + i 没有超出物品的数量, 这个这个格子有物品
                if (startIndex + i >= BagData.Instance.Items.Count)
                {
                    //超出了物品的数量,该格子没有物品
                    grids[i].UpdateItem(-1, "");
                }
                else
                {
                    grids[i].UpdateItem(BagData.Instance.Items[startIndex + i].Id,
                        BagData.Instance.Items[startIndex + i].IconName);
                }
            }
        }
        /// <summary>
        /// 翻页的右按钮
        /// </summary>
        void RightClick()
        {
            Debug.Log("RightClick");
        }
        /// <summary>
        /// 翻页的左按钮
        /// </summary>
        void LeftClick()
        {
            Debug.Log("LeftClick");
        }
        /// <summary>
        /// 整理按钮
        /// </summary>
        void ClearUpClick()
        {
            Debug.Log("ClearUpClick");
        }
    }

    GridBase

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    public class GridBase : MonoBehaviour,
        IPointerEnterHandler,
        IPointerExitHandler,
        IPointerClickHandler,
        IBeginDragHandler,
        IDragHandler,
        IEndDragHandler
    {
        public int itemID = -1;// 规定-1  那么这个格子空的
        public Transform tempParent;//拖动时临时的父物体
        private Image image;//显示装备的图片
        private Vector2 outPos;//转换之后的坐标
        private Vector2 offset;//鼠标偏移量
        private RectTransform parentRT;
        protected void Init()
        {
            image = transform.Find("Item").GetComponent<Image>();
            image.raycastTarget = false;
            parentRT = tempParent as RectTransform;
        }
        /// <summary>
        /// 更新自己本身的物品
        /// </summary>
        /// <param name="itemID"></param>
        /// <param name="iconName"></param>
        public void UpdateItem(int itemID, string iconName)
        {
            if (this.itemID == itemID)
            {
                return;
            }
            this.itemID = itemID;
            if (itemID < 0)//没有物品
            {
                image.enabled = false;
            }
            else
            {
                image.enabled = true;
                if (image.sprite.name != iconName)
                {
                    Sprite sp = Resources.Load<Sprite>("Texture/Icon/" + iconName);
                    image.sprite = sp;
                }
            }
        }
        #region 接口的虚方法
        //开始拖动的虚方法
        protected virtual void BeginDrag(PointerEventData eventData)
        {
            //Debug.Log("父类:BeginDrag");
            //image.transform.parent = tempParent;
            image.transform.SetParent(tempParent);
            if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRT,
                eventData.position, eventData.enterEventCamera, out outPos))
            {
                offset = outPos - new Vector2(image.transform.localPosition.x, image.transform.localPosition.y);
            }
        }
        //拖动的虚方法
        protected virtual void Drag(PointerEventData eventData)
        {
            //Debug.Log("父类:Drag");
            if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRT,
                eventData.position, eventData.enterEventCamera, out outPos))
            {
                image.transform.localPosition = outPos - offset;
            }
        }
        //拖动结束时的虚方法
        protected virtual void EndDrag(PointerEventData eventData)
        {
            //Debug.Log("父类:EndDrag");
            //image.transform.parent = transform;
            image.transform.SetParent(transform);
            image.transform.localPosition = Vector3.zero;
        }
        //点击的虚方法
        protected virtual void Click(PointerEventData eventData)
        {
            //Debug.Log("父类:Click");
        }
        //进入的虚方法
        protected virtual void Enter(PointerEventData eventData)
        {
            //Debug.Log("父类:Enter");
            //Debug.Log("显示信息");
        }
        //出去的虚方法
        protected virtual void Exit(PointerEventData eventData)
        {
            //Debug.Log("父类:Exit");
            //Debug.Log("隐藏信息");
        }
        #endregion
        #region 实现的接口
        public void OnBeginDrag(PointerEventData eventData)
        {
            BeginDrag(eventData);
        }
        public void OnDrag(PointerEventData eventData)
        {
            Drag(eventData);
        }
        public void OnEndDrag(PointerEventData eventData)
        {
            EndDrag(eventData);
        }
        public void OnPointerClick(PointerEventData eventData)
        {
            Click(eventData);
        }
        public void OnPointerEnter(PointerEventData eventData)
        {
            Enter(eventData);
        }
        public void OnPointerExit(PointerEventData eventData)
        {
            Exit(eventData);
        }
        #endregion
    }

    PlayerGridUI

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    public class PlayerGridUI : GridBase
    {
        public ItemType gridType;
        private Text text;
        // Use this for initialization
        void Awake()
        {
            base.Init();
            text = transform.Find("Text").GetComponent<Text>();
            gameObject.tag = "PlayerGrid";
        }
        protected override void Click(PointerEventData eventData)
        {
            if (eventData.button == PointerEventData.InputButton.Right)
            {
                Debug.Log("卸下: " + itemID);
            }
        }
        protected override void EndDrag(PointerEventData eventData)
        {
            base.EndDrag(eventData);
            if (eventData.pointerCurrentRaycast.gameObject != null &&
                eventData.pointerCurrentRaycast.gameObject.CompareTag("BagGrid"))
            {
                Debug.Log("卸下装备");
            }
        }
    }

    BagGridUI

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    public class BagGridUI : GridBase
    {
        void Awake()
        {
            base.Init();
            gameObject.tag = "BagGrid";
        }
        protected override void Click(PointerEventData eventData)
        {
            if (eventData.button == PointerEventData.InputButton.Right)
            {
                Debug.Log("装备: " + itemID);
            }
        }
        protected override void EndDrag(PointerEventData eventData)
        {
            base.EndDrag(eventData);
            if (eventData.pointerCurrentRaycast.gameObject == null)//当拖出背包区域时
            {
                Debug.Log("卖出物品");
            }
            else if (eventData.pointerCurrentRaycast.gameObject.CompareTag("PlayerGrid"))
            {
                Debug.Log("装备物品");
            }
        }
    }

    Json:StreamingAssets -> Json -> PlayerData -> UTF-8

    SaveManeger

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class SaveManager
    {
        #region 单例
        private static SaveManager instance;
        public static SaveManager Instance
        {
            get
            {
                if (null == instance)
                {
                    instance = new SaveManager();
                }
                return instance;
            }
        }
        private SaveManager() { }
        #endregion
        /// <summary>
        /// 初始化数据
        /// </summary>
        public void InitData()
        {
            //初始化人物的数据
            string playerJson = FileTools.ReadJson(Application.streamingAssetsPath + "/Json/PlayerData.txt");
            if (playerJson == "")
            {
                PlayerData.SetInstance(null);
            }
            else
            {
                PlayerData.SetInstance(JsonUtility.FromJson<PlayerData>(playerJson));
            }
            PlayerData.Instance.Init();
            ////初始化背包数据
            //string bagJson = FileTools.ReadJson(Application.streamingAssetsPath + "/Json/Bag.txt");
            //if (bagJson == "")
            //{
            //    BagData.SetInstance(null);
            //}
            //else
            //{
            //    BagData.SetInstance(JsonUtility.FromJson<BagData>(bagJson));
            //}
            //BagData.Instance.UpdateCurrentCapacity();//更新一次负重
        }
        /// <summary>
        /// 保存数据
        /// </summary>
        public void SaveData()
        {
        }
    }

    GameManeger

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class GameManager : MonoBehaviour
    {
        // Use this for initialization
        void Awake()
        {
            DontDestroyOnLoad(gameObject);
            SaveManager.Instance.InitData();
        }
        // Update is called once per frame
        void OnDestroy()
        {
            SaveManager.Instance.SaveData();
        }
    }

    FileTools

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using System.Text;
    public static class FileTools
    {
        /// <summary>
        /// 读取指定路径的json文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ReadJson(string path)
        {
            if (!File.Exists(path))
            {
                return "";
            }
            string json = "";
            StreamReader sr = new StreamReader(path, Encoding.UTF8);
            try
            {
                json = sr.ReadToEnd();
            }
            catch (System.Exception e)
            {
                Debug.Log(e.ToString());
            }
            sr.Close();
            return json;
        }
        /// <summary>
        /// 把json写入指定的文件a
        /// </summary>
        /// <param name="path"></param>
        /// <param name="json"></param>
        public static void WriteJson(string path, string json)
        {
            if (!File.Exists(path))
            {
                FileStream fs = File.Create(path);
                fs.Close();
            }
            StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8);
            try
            {
                sw.Write(json);
            }
            catch (System.Exception e)
            {
                Debug.Log(e.ToString());
            }
            sw.Close();
        }
    }
  • 相关阅读:
    appium+python自动化项目实战(一):引入nose和allure框架
    jmeter+WebDriver:启动浏览器进行web自动化
    jmeter强大的扩展插件!!
    jmeter+Fiddler:通过Fiddler抓包生成jmeter脚本
    appium+python自动化测试真机测试时报错“info: [debug] Error: Could not extract PIDs from ps output. PIDS: [], Procs: ["bad pid 'uiautomator'"]”
    Appium+python移动端自动化测试-python库及pycharm安装(二)
    Appium+python移动端自动化测试-环境搭建(一)
    安全测试之bWAPP环境搭建
    Battery Historian之App耗电量测试
    (15)Docker之用Nginx实现SpringBoot应用的负载均衡简单记录
  • 原文地址:https://www.cnblogs.com/vuciao/p/10363675.html
Copyright © 2020-2023  润新知