【unity小技巧】Unity 存储存档保存——PlayerPrefs、JsonUtility和MySQL数据库的使用

2023-09-18 23:25:16

前言

游戏存档不言而喻,是游戏设计中的重要元素,可以提高游戏的可玩性,为玩家提供更多的自由和控制权。看完这篇文章就可以构建属于自己的存储系统了。

PlayerPrefs

它是一个仅仅可以存储字符串、浮点数和整数值数据的类

一、基本介绍

保存

PlayerPrefs.SetString(string KeyName, string Value);
PlayerPrefs.SetFloat(string KeyName, float Value);
PlayerPrefs.SetInt(string KeyName, int Value);
# 最后调用Save函数将这些key存入磁盘
PlayerPrefs.Save()

查找

# HasKeyl函数中可以通过传入Key得到一个bool的返回值
PlayerPrefs.HasKey(string KeyName);

读取

string Value = PlayerPrefs.GetString(string KeyName);
float Value = PlayerPrefs.GetFloat(string KeyName);
int Value = PlayerPrefs.GetInt(string KeyName);

删除

# 删除某个key
PlayerPrefs.DeleteKey(KeyName);

# 删除全部
PlayerPrefs.DeleteAll();

二、Demo

实现按下O键保存玩家的位置数据,并通过按下P键加载玩家的位置数据

using UnityEngine;
public class PlayerDataManager : MonoBehaviour
{
	public Transform player;
	private void Update(){
		if (Input.GetKeyDown(KeyCode.O)) Save();//当按下'o'键时保存玩家数据
		if (Input.GetKeyDown(KeyCode.P)) Load();//当按下'P'键时加载玩家数据
	}

	public void Save(){
		PlayerPrefs.SetFloat("PlayerPositionX", player.position.x);
		PlayerPrefs.SetFloat("PlayerPositionY", player.position.y);
		PlayerPrefs.SetFloat("PlayerPositionz", player.position.z);
		PlayerPrefs.Save();//保存玩家偏好设置
		Debug.Log("Save ok!");
	}
	public void Load(){
		if (PlayerPrefs.HasKey("PlayerPositionX")&&
		PlayerPrefs.HasKey("PlayerPositionY")&&
		PlayerPrefs.HasKey("PlayerPositionz"))
		{
			float x = PlayerPrefs.GetFloat("PlayerPositionX");
			float y = PlayerPrefs.GetFloat("PlayerPositionY");
			float z = PlayerPrefs.GetFloat("PlayerPositionz");
			player.position = new Vector3(x,y,z);
			Debug.Log("Load ok!");
		}
	}
}

效果
在这里插入图片描述

三、优缺点

在这里插入图片描述

JsonUtility

它是Unty引擎中提供的一个用于序列化和反序列化JSON数据的工具类,该类提供了三个方法。

一、基本使用

第一个函数ToJson可以将可序列化的对象转换为JSON字符串
第二个可选参数表示是否花费更多的性能将字符转换为更适合阅读的方式

//通过JS0N表示形式创建对象
string json = JsonUtility.ToJson(object obj, bool prettyPrint);

第二个函数FromJson可以将字符转换为对象
Playerlnfo是一个泛型参数,用于指定要将JSoN字符串转换为的对象类型

//生成对象的公共字段的JS0N表示形式
PlayerInfo playerInfo = JsonUtility.FromJson<PlayerInfo>(string json);

第三个函数则可以传入新的数据覆盖到已有对象中,而不是创建新的对象,在频繁读取数据时可以节省开销


//通过读取对象的JS0N表示形式覆盖其数据
JsonUtility.FromJsonOverwrite(string json, object objectTooverwrite);

二、Demo

Application.persistentDataPath是一个持久化的数据路径
在不同的操作系统上,unity会为我们分配不同的持久化数据路径
这样可以确保应用程序在不同平台上都能正确保存和访问

using UnityEngine;
using System.IO;
public class PlayerDataManager : MonoBehaviour
{
	public Transform player;
	private string savePath;
	private void Awake()
	{
		//获取存档文件路径
		savePath = Path.Combine(Application.persistentDataPath, "saveData.json");
	}
	private void Update(){
		if (Input.GetKeyDown(KeyCode.O)) Save();//当按下'o'键时保存玩家数据
		if (Input.GetKeyDown(KeyCode.P)) Load();//当按下'P'键时加载玩家数据
	}
	public void Save(){
		PlayerGameData saveData = new PlayerGameData();
		saveData.playerPosition = player.position;
		string jsonData = JsonUtility.ToJson(saveData);
		File.WriteAllText(savePath, jsonData);
		Debug.Log("Save ok!");
	}
	public void Load(){
		//首先对路径做一个安全性检查
		if(File.Exists(savePath)){
			string jsonData = File.ReadAllText(savePath);
			//将JSON数据反序列化为游戏数据对象
			PlayerGameData loadedData = JsonUtility.FromJson<PlayerGameData>(jsonData);
			player.position = loadedData.playerPosition;
			Debug.Log("Load ok!");
		}else{
			Debug.Log("Load ok!");
		}
	}
}

[System.Serializable]
public class PlayerGameData
{
    public Vector3 playerPosition;
    // 可以添加其他的游戏数据字段
}

效果
在这里插入图片描述
不同平台存储的路径不一样,我们可以打印savePath查看自己的存储路径
比如我的就是
在这里插入图片描述

三、优缺点

在这里插入图片描述

Mysql(扩展)

首先,您需要从官方MySQL网站下载MySQL Connector/NET。下载并安装后,您可以在Unity项目中添加对MySQL.Data.dll的引用。

如果您需要在整个应用程序中共享数据库连接,那么使用单例模式可能是一个好主意。这将确保只有一个MySQLConnector实例存在,并且可以在应用程序的任何部分使用它。

要实现这一点,您可以将MySQLConnector类的构造函数设置为私有,并添加一个静态GetInstance方法,该方法返回MySQLConnector类的单例实例。在GetInstance方法中,您可以检查是否已经创建了一个MySQLConnector实例,如果没有,则创建一个新实例并返回它。否则,返回现有实例。

using System.Data;
using MySql.Data.MySqlClient;

public class MySQLConnector
{
    private static MySQLConnector instance;
    private MySqlConnection connection;
    private string server;
    private string database;
    private string uid;
    private string password;

    private MySQLConnector(string server, string database, string uid, string password)
    {
        this.server = server;
        this.database = database;
        this.uid = uid;
        this.password = password;
        string connectionString = "SERVER=" + server + ";" + "DATABASE=" + 
            database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
        connection = new MySqlConnection(connectionString);
    }

    public static MySQLConnector GetInstance(string server, string database, string uid, string password)
    {
        if (instance == null)
        {
            instance = new MySQLConnector(server, database, uid, password);
        }
        return instance;
    }

    public void OpenConnection()
    {
        connection.Open();
    }

    public void CloseConnection()
    {
        connection.Close();
    }

    public DataTable ExecuteQuery(string query)
    {
        MySqlCommand cmd = new MySqlCommand(query, connection);
        MySqlDataAdapter adapter = new MySqlDataAdapter(cmd);
        DataTable dataTable = new DataTable();
        adapter.Fill(dataTable);
        return dataTable;
    }
}

现在,您可以在应用程序的任何部分使用MySQLConnector.GetInstance方法来获取MySQLConnector类的单例实例,并调用其方法来执行查询。例如:

MySQLConnector connector = MySQLConnector.GetInstance("localhost", "mydatabase", "username", "password");
connector.OpenConnection();
string query = "SELECT * FROM mytable";
DataTable dataTable = connector.ExecuteQuery(query);

foreach (DataRow row in dataTable.Rows)
{
    Debug.Log(row["column1"] + " " + row["column2"]);
}

connector.CloseConnection();

这段代码获取MySQLConnector类的单例实例,并使用适当的服务器、数据库、uid和密码值打开了数据库连接,在名为“mytable”的表上执行了一个SELECT查询,并为查询返回的每一行的“column1”和“column2”值打印到控制台。最后,它关闭了数据库连接。

完结

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

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

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

更多推荐

测试域: 流量回放-工具篇jvm-sandbox,jvm-sandbox-repeater,gs-rest-service

JVM-SandboxJvm-Sandbox-Repeater架构_小小平不平凡的博客-CSDN博客https://www.cnblogs.com/hong-fithing/p/16222644.html流量回放框架jvm-sandbox-repeater的实践_做人,最重要的就是开心嘛的博客-CSDN博客[jvm-s

HTTP代理反爬虫技术详解

HTTP代理是一种网络技术,它可以将客户端的请求转发到目标服务器,并将服务器的响应返回给客户端。在网络安全领域中,HTTP代理经常被用来反爬虫,以保护网站的正常运营。HTTP代理反爬虫的原理是通过限制访问者的IP地址、访问频率、User-Agent和验证码验证等方式,来限制恶意爬虫的访问。下面我们来具体分析一下这几种方

拓世AIGC | 大语言模型螺旋上升式进化,人文、技术与未来

本月初,上海世博园举办外滩大会见解论坛中,众多学者和企业家共同探讨了大语言模型时代的人机关系、硅基生命和碳基生命未来之争等议题。面对全新的局面,论坛释放出积极信号和值得持续关注的论点。从黄浦江的波涛翻涌,我们捕捉到了人工智能未来科技的波澜壮阔。(汇集近20位两院院士、诺贝尔奖和图灵奖得主,超500位科技企业家和专家学者

Websocket集群解决方案以及实战(附图文源码)

最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息。所谓的全双工表示客户端和服务端都能向对方发送消息。不使用同样是全双工的http是因为http只能由客户端主动发起请求,服务接收后返回消息。websocket建立起连接之后,客户端

WebMvcConfigurerAdapter、WebMvcConfigurer、WebMvcConfigurationSupport

WebMvcConfigurerAdapter、WebMvcConfigurer、WebMvcConfigurationSupport的关系?WebMvcConfigurerAdapter、WebMvcConfigurer和WebMvcConfigurationSupport是SpringMVC框架中用于配置Web应用

android系统目录结构

文章目录android系统目录结构问答偏好设置保存在哪里在应用设置中点击清除数据,清除的是什么在应用设置中点击清除缓存,清除的是什么参考android系统目录结构/-system(一般只有root权限才能访问)-data-app(存放应用程序的APK文件)-data(内部存储)-<安装的应用包名>-app_textur

lock和synchronized的区别

lock和synchronized都是在多线程环境下用于保护共享资源的机制,但它们有一些重要的区别:实现方式:synchronized是Java语言内置的关键字,可以用于方法或代码块级别的同步。Lock是一个接口,位于java.util.concurrent.locks包下,提供了更灵活的锁定机制。灵活性:Lock提供

SQL-4大板块(存储过程、函数、视图、触发器)

一、存储过程(做复杂运算)1.做复杂运算,是对变量做运算;2.可以对多个表进行update、insert、delete、select、query;3.可以在最终结果返回多个表,但是对对接环境有苛刻要求,比如:VB不支持接收返回多个表4.当一个查询语句无法实现,或者语句查询速度很慢时,想提高效率就会用到存储过程。先把需要

MongoDB——将时间戳转换为日期

在MongoDB中将时间戳转换为日期从timestamp转换为日期取决于我们保存时间戳的类型。它是对象、数字还是字符串类型?我们可以在mongoshell上使用以下命令检查字段的类型。在本教程中,我们将学习如何将时间戳转换为数字、字符串或对象类型的日期。检查字段类型://MongoDB5.0.8>typeofdb.co

滑动时间窗口的思想和实现,环形数组,golang

固定时间窗口在开发限流组件的时候,我们需要统计一个时间区间内的请求数,比如以分钟为单位。所谓固定时间窗口,就是根据时间函数得到当前请求落在哪个分钟之内,我们在统计的时候只关注当前分钟之内的数量,即[0s,60s],因为流量并不是均匀的,所以就会出现,在两个分钟之间超过阈值,1分50秒时来了150个请求,在2分10秒时来

图像语义分割概述

图像语义分割概述一、图像语义分割概念图像语义分割(ImageSemanticSegmentation)是一项计算机视觉任务,其目标是将输入的图像分割成多个区域,并为每个像素分配一个语义类别标签,以表示该像素属于图像中的哪个物体或区域。与其他图像分割任务不同,图像语义分割不仅关注于分割图像,还要理解图像中不同部分的语义含

热文推荐