我正处于游戏开发的最后阶段,我有一堆这样的东西;
roomBedroom = function () {
this.title = "Bedroom";
this.description = "I'm in a bedroom";
this.noun = "bed";
this.entities = new Array();
}
var bedroom = new roomBedroom();我现在想要做的是将我所有的游戏对象放入一个数组中;
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);我们的计划是保存savedGameObjects数组,然后在用户再次加载游戏时调用它。
如果我用savedGameObjects['bed'] = 'slappy';替换savedGameObjects['bedroom'] = bedroom;,它可以工作,但当我有对象的时候就不行了。
我真的需要保存对象的当前状态。我不想逐一查看每个对象,保存关键信息。
发布于 2013-12-12 10:34:57
这感觉有点像黑客,但这是我现在能想到的最好的方法了
序列化/反序列化实用程序
这将在序列化之前将obj.constructor.name附加到obj.__prototype。在反序列化时,原型将被放回原位。
(function(global) {
function serialize(obj) {
obj.__prototype = obj.constructor.name;
return JSON.stringify(obj);
};
function deserialize(json) {
var obj = JSON.parse(json);
obj.__proto__ = global[obj.__prototype].prototype;
return obj;
}
global.serialize = serialize;
global.deserialize = deserialize;
})(window);一个示例"class“
(function(global) {
function Foo() {
this.a = "a";
this.b = "b";
}
Foo.prototype.hello = function() {
console.log("hello");
}
global.Foo = Foo;
})(window);让我们试试看
var foo = new Foo();
var json = serialize(foo);
console.log(json);
var newFoo = deserialize(json);
console.log('a', newFoo.a); // a
console.log('b', newFoo.b); // b
newFoo.hello(); // hello注意一些陷阱
如果你使用一个表达式来定义你的"class",你将会有一个无名的构造函数
var Foo = function() {};
var foo = new Foo();
foo.constructor.name; // ""与命名函数相对
function Foo() {}
var foo = new Foo();
foo.constructor.name; // Foo为了使serialize和deserialize正常工作,您需要使用命名函数
另一个陷阱
deserialize方法期望您的“类”存在于相同的名称空间中(本例中为window)。您可以用另一种方式封装游戏对象类,只需确保重新配置反序列化方法,以便它可以根据需要找到原型。
让变得更好的
不是将serialize附加到全局window,而是让serialize处于活动状态(例如)然后,您的单个类可以从GameObject继承GameObject.prototype。然后,序列化对象就会像这样简单
var json = foo.serialize();
// {"a":"a","b":"b","__prototype":"Foo"}然后,您可以将deserialize定义为GameObject.deserialize,并将foo恢复为
var foo = GameObject.deserialize(json);a alternative solution
您可以非常巧妙地使用Factory Method Pattern,而不是实现自定义的序列化程序和反序列化程序。
这可能有点冗长,但它确实为您提供了对游戏对象应该如何反序列化/恢复的个人控制。
var savedData = // your normal JSON here
var player = Player.create(savedData.player);
var items = [];
for (var i=0, i<savedData.items.length; i++) {
items.push(Item.create(savedData.items[i]));
}
var map = Map.create(savedData.map);这是一个非常有趣的问题,我相信你不是第一个遇到它的人。我真的很好奇,想看看其他人会想出什么。
发布于 2013-12-12 11:43:27
如果我在浏览器中运行以下代码,获取卧室对象的JSON字符串没有问题,但不确定问题是什么。
请注意,JSON是数据,卧室是对象,卧室可能有像turnOffLight()这样的行为,这是JSON没有的。
roomBedroom = function () {
this.title = "Bedroom";
this.description = "I'm in a bedroom";
this.noun = "bed";
this.entities = new Array();
}
var bedroom = new roomBedroom();
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
//logs {"bedroom":{"title":"Bedroom","description":
// "I'm in abedroom","noun":"bed","entities":[]}}
console.log(JSON.stringify(savedGameObjects));因此,如果您想从JSON data重新创建对象实例,那么您可以更改构造函数:
roomBedroom = function (args) {
//following fails fast and loud, you could silently
//fail by setting args to {}
if(typeof args!=="object")
throw new Error("Have to create roomBedroom by passing an object");
//or do args={} to silently fail
this.title = args.title||"Bedroom";
this.description = args.description||"I'm in a bedroom";
this.noun = args.noun||"bed";
//if entities are objects with behavior
// you have to re create them here passing the JSON data
// as I've done with roomBedroom
this.entities = args.entities||new Array();
}
var jsonString='{"bedroom":{"title":"Bedroom",'+
'"description":"I\'m in a bedroom",'+
'"noun":"bed","entities":[]}}';
var bedroom = new roomBedroom({});
bedroom.entities.push({hi:"there"});
bedroom.title="Master Bedroom";
//serialize bedroom to a json string
var jsonString = JSON.stringify(bedroom);
//create a roomBedroom instance named br2 using
// the serialized string
var br2=new roomBedroom(JSON.parse(jsonString));
//compare if they are the same
console.log(JSON.stringify(bedroom)===JSON.stringify(br2));//true发布于 2013-12-12 12:59:14
我有一个可能对你有用的方法。你可以使用。
要点是在解析对象时使用JSON.parse的来重新构造对象。
我使用一个可以为多种不同类型进行配置的通用reviver来实现这一点,尽管这里唯一使用的是RoomBedroom构造函数。此实现假设您具有简单的复制构造函数,这些构造函数使用对现有对象的引用来创建新对象。(有关其他更复杂的可能性,请参阅我在2月份给出的。)为了简化复制构造函数,我还有一个函数,它接受一个非常简单的构造函数和一组默认值,并为您构建一个复制构造函数。
var MultiReviver = function(types) {
return function(key, value) {
var type;
for (var i = 0; i < types.length; i++) {
type = types[i];
if (type.test(value)) {
return new type.constructor(value);
}
}
return value;
};
};
var makeCloningConstructor = (function() {
var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
var F = function() {};
return function(Constructor, defaults) {
var fn = function(obj) {
Constructor.call(this);
var self = this;
var config = obj || {};
Object.keys(defaults).forEach(function(key) {
self[key] = clone(defaults[key]);
});
Object.keys(config).forEach(function(key) {
self[key] = clone(config[key]);
});
};
F.prototype = Constructor.prototype;
fn.prototype = new F();
fn.constructor = Constructor;
return fn;
};
})();
// Note: capitalize constructor functions
var RoomBedroom = makeCloningConstructor(function RoomBedroom() {}, {
title: "Bedroom",
description: "I'm in a bedroom",
noun: "bed",
entities: [] // Note: use `[]` instead of `new Array()`.
});
RoomBedroom.prototype.toggleLight = function() {
this.lightOn = !this.lightOn;
};
RoomBedroom.prototype.checkLights = function() {
return "light is " + (this.lightOn ? "on" : "off");
};
var bedroom = new RoomBedroom();
bedroom.windowCount = 3; // add new property
bedroom.noun = "king-sized bed"; // adjust property
bedroom.toggleLight(); // create new propery, use prototype function
console.log(bedroom.checkLights());
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);
var reviver = new MultiReviver([{
constructor: RoomBedroom,
test: function(obj) {
var toString = Object.prototype.toString, str = "[object String]",
arr = "[object Array]";
return toString.call(obj.title) == str &&
toString.call(obj.description) == str &&
toString.call(obj.noun) == str &&
toString.call(obj.entities) == arr;
}
}]);
var retrievedGameObjects = JSON.parse(jsonGame, reviver);
// data comes back intact
console.log(JSON.stringify(retrievedGameObjects, null, 4));
// constructor is as expected
console.log("Constructor: " + retrievedGameObjects.bedroom.constructor.name);
// prototype functions work
console.log(retrievedGameObjects.bedroom.checkLights());我不知道这是否正是您想要的,但我认为这至少是一种有趣的方法。
https://stackoverflow.com/questions/20533797
复制相似问题