Stand-alone game data automatic saving solution

Thanks to fans for providing material

introduction

Automatic saving solution for stand-alone game data

Hello everyone, there are only the last 3 days of 2023 !

A friend sent me a private message and said:

I always feel that it is unscientific to save all the data regularly. I have also written about saving changed player data, but after changing the data, I have to manually mark the field changes. I feel that it is not smart enough. I don’t know if there is a good design pattern that can solve the problem, so I just do it. Just update the data.

The author thought about it carefully and analyzed it based on what was used in the previous project . You can take a look at it according to the specific situation .

This article will introduce the automatic saving scheme of stand-alone game data .

The source project of this article can be obtained by reading the original text at the end of the article, friends can go there by themselves.

1. Requirements analysis

According to the private message from my friend, the requirements are as follows:

  • It is unscientific to save everything regularly.
  • Saving changed player data requires manual marking, which is not smart.
  • Is there a way to just update the data?

Let’s analyze it in detail next

2.Specific analysis

1. Save the entire disk regularly

In fact, it is not a bad design to save the entire disk regularly , but it also needs to save the changed data.

In other words, we need to mark the changed data , and when performing a full disk save , we need to store it according to the mark bits .

This solution is actually very common in back-end development , scheduled save + offline save .

It can effectively ensure that data storage is error-free , storage efficiency is higher , and losses are minimal when the server goes down .

2. Manual marking

Manual marking is actually the most effective and direct way to control whether specified content needs to be saved.

However, since it is manual marking, that is, human operation, errors and omissions will inevitably occur .

Therefore, you can use design patterns to optimize the design and automatically mark when the data changes .

Let’s take a look at the common design patterns that automatically save

3. Data automatic saving design mode

The following are some design patterns and methods compiled after consulting relevant information :

  1. Observer Mode: Use observer mode to monitor changes in your game. Every object that may modify the data is an observer, and the archiving system is the subject. When the object changes, it notifies the subject, which is then responsible for triggering the save.

  2. Dirty Flag mode: Introducing the "dirty flag" to mark whether the object has changed. Save only when the object changes. This method can reduce unnecessary saving operations.

  3. Snapshot mode: Creates snapshots of the game state periodically instead of saving them entirely. This avoids frequent save operations and only loads the most recent snapshot when needed.

  4. Incremental save: Only save the changed part of the data, rather than the entire data set. This can reduce save and load times, especially with larger data volumes.

Next, let’s look directly at the example

4. Observer pattern

We use the observer pattern to complete an example of automatic data saving .

First we prepare the player data, including:

  • character name
  • grade
// PlayerData.ts
export class PlayerData {
    
    
    name: string;
    level: number;

    constructor(data: any) {
    
    
        this.name = data.name;
        this.level = data.level;
    }
}

Then , we define a generic observer interface:

// Observer.ts
export interface Observer<T> {
    
    
    update(data: T): void;
}

Then , implement a specific observer, that is, an observer that automatically saves data. The core content is as follows:

  • saveResponsible for storing data, which can be stored locally or on the server according to specific needs.
  • loadResponsible for data loading.
import {
    
     sys } from "cc";
import {
    
     Observer } from "./Observer";
import {
    
     PlayerData } from "./PlayerData";

// AutoSaveObserver.ts
export class AutoSaveObserver implements Observer<PlayerData> {
    
    
    update(data: PlayerData): void {
    
    
        // 在这里执行自动保存操作,可以调用存档系统
        console.log(`Auto-saving data: ${
      
      JSON.stringify(data)}`);
        this.save(data);
    }

    save(data: PlayerData) {
    
    
        sys.localStorage.setItem('playerData', JSON.stringify(data));
    }

    load() {
    
    
        const data = sys.localStorage.getItem('playerData');
        if (data) {
    
    
            const parsedData = JSON.parse(data);
            return new PlayerData(parsedData);
        }
        return new PlayerData({
    
     name: "Player", level: 1 });
    }
}

Next , we create a general theme class and use the proxy pattern to handle observer management and notifications :

The core to realize automatic marking/saving is Proxy :

In TypeScript, Proxy is a feature introduced in ES6, which provides a mechanism to intercept and define custom behaviors. Proxy can be used to create a proxy object that can intercept access to the original object, property lookup, assignment, etc. This provides developers with a way to customize behavior at the object level.

code show as below:

import {
    
     Observer } from "./Observer";

// ObservableProxy.ts
export class ObservableProxy<T extends object> {
    
    
    private observers: Observer<T>[] = [];
    private _target: T;

    constructor(target: T) {
    
    
        this._target = new Proxy(target, {
    
    
            set: (obj, prop, value) => {
    
    
                if (obj[prop] !== value) {
    
    
                    obj[prop] = value;
                    this.notifyObservers();
                }
                return true;
            },
        });
    }

    addObserver(observer: Observer<T>): void {
    
    
        this.observers.push(observer);
    }

    removeObserver(observer: Observer<T>): void {
    
    
        const index = this.observers.indexOf(observer);
        if (index !== -1) {
    
    
            this.observers.splice(index, 1);
        }
    }

    private notifyObservers(): void {
    
    
        for (const observer of this.observers) {
    
    
            observer.update(this._target);
        }
    }

    get target(): T {
    
    
        return this._target;
    }
}

Finally, we ObservableProxypackage the player data to achieve automatic saving.

import {
    
     ObservableProxy } from "./ObservableProxy";
import {
    
     PlayerData } from "./PlayerData";

// ObservablePlayerData.ts
export class ObservablePlayerData extends ObservableProxy<PlayerData> {
    
    
    constructor(data: any) {
    
    
        super(new PlayerData(data));
    }
}

test code

import {
    
     _decorator, Component, Node } from 'cc';
import {
    
     ObservablePlayerData } from './ObservablePlayerData';
import {
    
     AutoSaveObserver } from './AutoSaveObserver';
const {
    
     ccclass, property } = _decorator;

@ccclass('Main')
export class Main extends Component {
    
    
    start() {
    
    
        // Main.ts
        const autoSaveObserver = new AutoSaveObserver();
        var playerData = autoSaveObserver.load();
        const observablePlayerData = new ObservablePlayerData(playerData);

        console.log(`Now data: ${
      
      JSON.stringify(observablePlayerData.target)}`);

        // 将自动保存观察者添加到观察者列表中
        observablePlayerData.addObserver(autoSaveObserver);

        // 修改玩家数据,会触发自动保存
        observablePlayerData.target.level = 2;
        observablePlayerData.target.level = 3;
    }
}

Results demonstration

When running for the first time, the initial level is level 1. After modifying the level, the player level is level 3.

open the refrigerator

After logging in again, the level loaded is level 3, and the test automatically saves successfully.

Put the elephant in it

Close the refrigerator door! get out of class is over!

Conclusion

The source project of this article can be obtained through private message AutoSave .

Where can I see such clear ideas? Come and follow me! Follow me and learn about the latest developments in the game industry and learn game development skills with me.

I am a "Billion Dollar Programmer", a programmer with 8 years of experience in the game industry. In game development, I hope to be able to help you, and I hope that through you I can help everyone.

AD: You can click and search for the author's online mini-games "Snake Handheld Classic", "Gravity Maze Ball" and "Coloring Journey" by yourself.

To be honest, I want to like and watch ! Please share this article with other friends who you think need it. Thanks!

Recommended columns:

100 Cocos instances

8 years of experience in building Cocos independent game development framework step by step

Learn design patterns with an 8-year game master programmer

Develop Snake mini game from scratch to online series

Knowledge paid column

Guess you like

Origin blog.csdn.net/lsw_Cs/article/details/135282242