美文网首页
使用 SaveGameFree 实现 Unity 存档/读档/删

使用 SaveGameFree 实现 Unity 存档/读档/删

作者: 简栋梁 | 来源:发表于2021-09-15 14:32 被阅读0次

    SaveGameFree


    初始化项目

    新建项目
    替换原有场景
    添加物体至场景
    调整相机角度

    安装插件 SaveGameFree


    安装插件 Input System

    导入
    激活

    新建脚本 PlayerController.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.InputSystem;
    using BayatGames.SaveGameFree;
    
    
    public class PlayerController : MonoBehaviour
    {
    
        public float speed = 10;
        private Rigidbody rb;
        private float movementX;
        private float movementY;
        private string identifier = "playerPosition";
    
        // 自定义数据类,保存 player 位置信息
        public class PlayerData
        {
            public float x;
            public float y;
        }
    
        void Start()
        {
            GetData();
            
            rb = GetComponent<Rigidbody>();
        }
    
        void Update()
        {
            // 存档快捷键 q(方便调试,不与 IDE 键位冲突)
            if (Input.GetKeyDown(KeyCode.Q))
            {
                SetData();
            }
    
            // 删档快捷键 e(方便调试,不与 IDE 键位冲突)
            if (Input.GetKeyDown(KeyCode.E))
            {
                DeleteData();
            }
        }
    
        void FixedUpdate()
        {
            // 组装 3D 向量
            Vector3 vector3D = new Vector3(movementX, 0.5f, movementY);
    
            // 为刚体施加力
            rb.AddForce(vector3D * speed);
        }
    
        void OnMove(InputValue movement)
        {
            Vector2 vector2D = movement.Get<Vector2>();
            movementX = vector2D.x;
            movementY = vector2D.y;
        }
    
        // 设置 postion
        void SetPlayerPosition(float x, float y)
        {
            transform.position = new Vector3(x, transform.position.y, y);
        }
    
        // 存档
        void SetData()
        {
            PlayerData data = new PlayerData();
            data.x = transform.position.x;
            data.y = transform.position.z;
    
            SaveGame.Save<PlayerData>(identifier, data);
        }
    
        // 读档
        void GetData()
        {
            // 校验数据是否存在
            if (SaveGame.Exists(identifier))
            {
                PlayerData playerPosition = SaveGame.Load<PlayerData>(identifier);
                SetPlayerPosition(playerPosition.x, playerPosition.y);
            }
        }
    
        // 删档
        void DeleteData()
        {
            SaveGame.Clear();
        }
    }
    

    编辑球体组件

    添加组件,以及修改 transform 值
    编辑 Player Input 组件
    • 新建 Inputs 目录,并保存 input action
    • 绑定 input action

    运行项目

    移动:WSAD / 方向键
    读档:自动
    存档:Q
    删档:E


    升级为云存储

    云存储功能建议自己实现,重写 SaveGameWeb 类,以及选择更合适的服务端技术选型。以下是官方文档的实现

    配置数据库(MySQL)

    Git 仓库 Assets/BayatGames/SaveGameFree/Web/Save Game Free - Web/savegamefree.sql

    CREATE DATABASE IF NOT EXISTS `savegamefree`;
    
    USE savegamefree;
    
    CREATE TABLE IF NOT EXISTS savegames (
      id VARCHAR(255) CHARACTER SET utf8 NOT NULL PRIMARY KEY,
      data LONGTEXT CHARACTER SET utf8 NOT NULL
    );
    
    初始化项目(Nodejs)
    mkdir SaveGameFreeServer
    cd SaveGameFreeServer
    
    npm init -y
    npm i koa koa-router koa-bodyparser mysql
    
    touch index.js
    
    编写入口文件(index.js)

    Git 仓库 Assets/BayatGames/SaveGameFree/Web/Save Game Free - Web/savegamefree.php
    以下是基于上述 PHP 脚本改造的 Nodejs 实现

    const Koa = require('koa')
    const Router = require('koa-router')
    const bodyParser = require('koa-bodyparser')
    const mysql = require('mysql')
     
    
    
    const config = {
      portServer: 3000,
      database: {
        DATABASE: 'savegamefree',
        TABLE: 'savegames',
        USERNAME: '数据库账号',
        PASSWORD: '数据库密码',
        HOST: '数据库域名'
      }
    }
    
    const pool = mysql.createPool({
      database: config.database.DATABASE,
      user: config.database.USERNAME,
      password: config.database.PASSWORD,
      host: config.database.HOST
    })
    
    class Mysql {
      constructor() { }
      setPositionById(id, data) {
        return new Promise((resolve, reject) => {
          pool.query(`INSERT INTO ${config.database.TABLE} (id, data) VALUES ('${id}', ${JSON.stringify(data)}) ON DUPLICATE KEY UPDATE data=VALUES (data)`, function (error, results, fields) {
            if (error) {
              throw error
            }
            resolve(results)
          })
        })
      }
      getPositionById(id) {
        return new Promise((resolve, reject) => {
          pool.query(`SELECT data FROM ${config.database.TABLE} WHERE id='${id}'`, function (error, results, fields) {
            if (error) {
              throw error
            }
            resolve(results)
          })
        })
      }
    } 
    
    
    
    const app = new Koa()
    const router = new Router()
    const mysqlInstance = new Mysql()
    
    app
      .use(bodyParser())
      .use(router.routes())
      .use(router.allowedMethods())
    
    router
      .post('/savegamefree', async (ctx, next) => {
        const postData = ctx.request.body
        if (postData.action === 'save') {
          const res = await mysqlInstance.setPositionById(postData.identifier, postData.data)
          ctx.body = res
        }
        else if (postData.action === 'load') {
          const res = await mysqlInstance.getPositionById(postData.identifier)
          ctx.body = res[0] ? res[0].data : null
        }
      })
    
    
    
    app.listen(config.portServer)
    console.log(`listening on port ${config.portServer}`)
    
    运行项目
    node index
    

    修改脚本 PlayerController.cs(云存储版本)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.InputSystem;
    using BayatGames.SaveGameFree;
    
    
    public class PlayerController : MonoBehaviour
    {
    
        public float speed = 10;
        private Rigidbody rb;
        private float movementX;
        private float movementY;
        private string identifier = "playerPosition";
    
        // 自定义数据类,保存 player 位置信息
        public class PlayerData
        {
            public float x;
            public float y;
        }
    
        void Start()
        {
    
            GetDataCloud();
    
            rb = GetComponent<Rigidbody>();
        }
    
        void Update()
        {
            // 存档快捷键 q(方便调试,不与 IDE 键位冲突)
            if (Input.GetKeyDown(KeyCode.Q))
            {
                SetDataCloud();
            }
    
            // 删档快捷键 e(方便调试,不与 IDE 键位冲突)
            if (Input.GetKeyDown(KeyCode.E))
            {
                DeleteData();
            }
        }
    
        void FixedUpdate()
        {
            // 组装 3D 向量
            Vector3 vector3D = new Vector3(movementX, 0.5f, movementY);
    
            // 为刚体施加力
            rb.AddForce(vector3D * speed);
        }
    
        void OnMove(InputValue movement)
        {
            Vector2 vector2D = movement.Get<Vector2>();
            movementX = vector2D.x;
            movementY = vector2D.y;
        }
    
        // 设置 postion
        void SetPlayerPosition(float x, float y)
        {
            transform.position = new Vector3(x, transform.position.y, y);
        }
    
        // 云存档
        void SetDataCloud()
        {
            StartCoroutine(SaveEnumerator());
        }
    
        // 云读档
        void GetDataCloud()
        {
            transform.localScale = Vector3.zero;    // 先隐藏球体,防止异步更新位置 导致球体位置闪烁
            StartCoroutine(LoadEnumerator());
        }
    
        // http://localhost.charlesproxy.com:3000 映射到 http://localhost:3000
        // 防止 charles 抓不到 unity 的请求包
        IEnumerator SaveEnumerator()
        {
            SaveGameWeb web = new SaveGameWeb("usernameFaker", "passwordFaker", "http://localhost.charlesproxy.com:3000/savegamefree");
    
            PlayerData data = new PlayerData();
            data.x = transform.position.x;
            data.y = transform.position.z;
    
            yield return StartCoroutine(web.Save<PlayerData>(identifier, data));
        }
    
        IEnumerator LoadEnumerator()
        {
            SaveGameWeb web = new SaveGameWeb("usernameFaker", "passwordFaker", "http://localhost.charlesproxy.com:3000/savegamefree");
    
            yield return StartCoroutine(web.Download(identifier));
    
            PlayerData defaultData = new PlayerData();
            defaultData.x = 0.0f;
            defaultData.y = 0.0f;
            PlayerData playerPosition = web.Load<PlayerData>(identifier, defaultData);
            SetPlayerPosition(playerPosition.x, playerPosition.y);
            transform.localScale = Vector3.one;
        }
    }
    
    

    运行项目

    移动:WSAD / 方向键
    读档:自动
    存档:Q

    相关文章

      网友评论

          本文标题:使用 SaveGameFree 实现 Unity 存档/读档/删

          本文链接:https://www.haomeiwen.com/subject/rmmkgltx.html