评论

Unity转微信小游戏--PlayerPrefs数据结构解析错误

用unity 转 微信小游戏发现 PlayerPrefs 转换后,对数据结构解析有问题

事情是这样,最近用unity 转 微信小游戏发现 PlayerPrefs 转换后,对数据结构解析有问题,这个问题搜遍互联网没有人提到过,我是一点点的跟踪对比才发现的(对可能转小游戏类型,敏感度不够,哈哈),所以记录一下。

keyNotFoundException: Arg_KeyNotFoundWithKey, Level_1
   at System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Level, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].get_Item(String )
   at Carousel.Create()
   at Carousel.Start()
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
UnityEngine.<>c:b__0_0(Object, UnhandledExceptionEventArgs)
System.ThrowHelper:ThrowKeyNotFoundException(String)
System.Collections.Generic.Dictionary`2:get_Item(String)
Carousel:Create()
Carousel:Start()

刚接触 untiy 的同学可能还不了解PlayerPrefs,简单介绍一下:

一、PlayerPrefs是什么?

PlayerPrefs是Unity3D提供的一个实用类,用于数据的本地持久化保存与读取。其工作原理简单直观,通过key-value形式将数据存储在本地设备上,方便开发者在代码中进行数据的写入、读取和更新操作。

二、PlayerPrefs有什么用?

PlayerPrefs在游戏开发中发挥着重要作用,尤其适用于单机游戏。它可以用来存储非关键性数据,如游戏存档、分数排名等。使用PlayerPrefs可以轻松实现这些数据的持久化存储,无需依赖服务器。

PlayerPrefs基本方法

-存

PlayerPrefs.SetInt("myAge"1);
PlayerPrefs.SetFloat("myHeight"1.1f);
PlayerPrefs.SetString("myName""名字");
PlayerPrefs.Save();// 立即保存,防止崩溃未存上

-读

int age = PlayerPrefs.GetInt("myAge");
float height = PlayerPrefs.GetFloat("myHeight");
string name1 = PlayerPrefs.GetString("myName");
//重载方法:当传入的键错误或没有对应值时返回后面的参数
string name2 = PlayerPrefs.GetString("Name""张麻子");

-查

//判断数据是否存在
if( PlayerPrefs.HasKey("myName") )

{
    print("存在myName对应的键值对数据");
}

-删

//删除指定键值对
PlayerPrefs.DeleteKey("myAge");
 //删除所有存储的信息
PlayerPrefs.DeleteAll();


我想用PlayerPrefs保存类似游戏关卡信息是这么写的:

首先定义要保存的数据类型:

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

// 某一关游戏的对象类型
[Serializable]
public class Level
{

    public string name;
    public int levelNum;
    public int score = 0;
    public bool isComplate = false;

    // 这个要有,不然JsonMapper.ToObject(jsonStr) 会报错
    public Level() { }

    public Level(string name, int levelNum, int score, bool isComplate)
{
        this.name = name;
        this.levelNum = levelNum;
        this.score = score;
        this.isComplate = isComplate;
    }

}

// 多个游戏关卡的集合
[Serializable]
public class Levels
{
     // 字典类型
     public Dictionary dic 
     = new Dictionary();

    // 这个要有,不然JsonMapper.ToObject(jsonStr) 会报错
    public Levels() { }
    public Levels(Dictionary dic){
        this.dic = dic;
    }
}

 然后定义存取类型对象的方法类:

public class LevelsJSON
{
    Levels data;
    public static string NAME = "Level_";
    // 单例
    public static LevelsJSON Instance { get; private set; }
    private void Awake()
    {
        Instance = this;
    }

    public void Setup(int Total)
    {

        for (var i = 0; i <= Total; i++)
        {
            string name = NAME + i;           
            dic[name] = new Level(name, i, 0false);
        }
        data = new Levels(dic);
        string json = DataObjectToJson(data);
        //保存数据
        PlayerPrefs.SetString("Levels", json);  
    }
    // 从playerPrefs读取数据,关键的地方通过反射可以完全还原出
    // 之前的对象
    public load(){
      string json = PlayerPrefs.GetString("Levels"); 
      Levels obj = DataJsonToObject(json);
      return obj;
    }
    
    // json转对象
    public T DataJsonToObject(string jsonStr)
    {
        T jsonObj = JsonMapper.ToObject(jsonStr);        print(jsonObj);
        return jsonObj;
    }

    //对象转json
    public T DataJsonToObject2(string jsonStr)
    {
        T jsonObj = JsonMapper.ToObject(jsonStr);
        return jsonObj;
    }
  }

重点来了:这套逻辑在untiy里没有问题,但是在微信小游戏里就有问题了。问题主要出在上面的数据结构还原成对象出错,保存在playerPrefs里是这样的:

{
"dic":{
  "Level_0":{
     "name":"Level_0",
     "levelNum":"1",
     "score":"0",
     "isComplate":"false"
    }
  }
  ...// 此处类似略过
}

但实际应用读取json转自定义对象会有问题:

Levels levels = LevelsJSON.load();
Level level = levels.dic[0];// 这里小游戏会报错无法解析出Level

纠其原因应该是微信小游戏是自己封装的playerPrefs,映射不到unity 封装类的所有信息。

实际应该怎么解决:

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

// 某一关游戏的对象类型
[Serializable]
public class Level
{

    public string name;
    public int levelNum;
    public int score = 0;
    public bool isComplate = false;

    // 这个要有,不然JsonMapper.ToObject(jsonStr) 会报错
    public Level() { }

    public Level(string name, int levelNum, int score, bool isComplate)
{
        this.name = name;
        this.levelNum = levelNum;
        this.score = score;
        this.isComplate = isComplate;
    }

}

// 多个游戏关卡的集合
[Serializable]
public class Levels
{
    // 数组类型
    public List list;

    // 这个要有,不然JsonMapper.ToObject(jsonStr) 会报错
    public Levels() { }
    public Levels(List list)
    {
        this.list = list;

    }
}


public class LevelsJSON
{
    Levels data;
    public static string NAME = "Level_";
    // 单例
    public static LevelsJSON Instance { get; private set; }
    private void Awake()
    {
        Instance = this;
    }

    public void Setup(int Total)
    {
        List levelList = new List(Total);
        for (var i = 0; i <= Total; i++)
        {
            string name = NAME + i;           
            levelList.Add(new Level(name, i, 0false));
        }
        data = new Levels(dic);
        string json = DataObjectToJson(data);
        //保存数据
        PlayerPrefs.SetString("Levels", json);  
    }
    // 从playerPrefs读取数据,关键的地方通过反射可以完全还原出
    // 之前的对象
    public load(){
      string json = PlayerPrefs.GetString("Levels"); 
      Levels obj = DataJsonToObject(json);
      return obj;
    }
    
    // json转对象
    public T DataJsonToObject(string jsonStr)
    {
        T jsonObj = JsonMapper.ToObject(jsonStr);        print(jsonObj);
        return jsonObj;
    }

    //对象转json
    public T DataJsonToObject2(string jsonStr)
    {
        T jsonObj = JsonMapper.ToObject(jsonStr);
        return jsonObj;
    }
  }

是的,把Levels 里的存储对象从字典Dictionary 换成 List 类型即可,unity 的数组对象和小游戏的数组对象,应该是做了应射关系,这样就能获取到了。

-----

研究unity 转 微信小游戏有段时间了,新的游戏也在审核之中。

对这块感兴趣的话,关注我的公众号就对啦!

最后一次编辑于  10-09  
点赞 0
收藏
评论
登录 后发表内容