Adonthell 0.4
|
00001 /* 00002 $Id: save.dxt,v 1.1 2001/10/15 15:00:06 gnurou Exp $ 00003 00004 Copyright (C) 2001 Alexandre Courbot 00005 Part of the Adonthell Project http://adonthell.linuxgames.com 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License. 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY. 00011 00012 See the COPYING file for more details. 00013 */ 00014 00015 /*! 00016 00017 \page page6 Saving/Loading 00018 00019 \section objdatobjst Object data and object state 00020 00021 This is another important part of the %game engine. Quite a few %objects should 00022 be loadable and saveable, but there is a difference between two things 00023 that may look like one: an %object's %data itself and an %object's state. 00024 00025 But there is a significant difference. Data is all the information that stays 00026 the same during an %object's lifetime. As a consequence, %data remains persistent 00027 over the whole %game. An %object's state is the information that changes while the 00028 %game progresses. 00029 00030 For example, when loading a map, all the actual graphics are persistant %data. 00031 OTOH, player and NPC's are certainly no longer at their initial position, so 00032 this information belongs to the map's state. 00033 00034 Let's see precisely how it works with a simple %animation class: 00035 00036 \verbatim 00037 class animation 00038 { 00039 public: 00040 // Constructor / Destructor. 00041 animation (); 00042 ~animation (); 00043 00044 ..... 00045 00046 // Saving / Loading methods. 00047 void get (FILE * in); 00048 void put (FILE * out); 00049 00050 // State saving / loading methods. 00051 void get_state (FILE * in); 00052 void put_state (FILE * out); 00053 00054 private: 00055 vector <image> frames; 00056 00057 u_int32 currentframe; 00058 } 00059 \endverbatim 00060 00061 The difference between the %object %data and the %object state is quite obvious here: the 00062 \e frames vector is an array containing the raw %images - they won't change during 00063 gameplay, so they are considered as the %object \e %data, while the \e currentframe 00064 member will change during the %game, and actually when we load a %game we would like 00065 it to have the same value than when we saved it. That's why \e get and \e put will 00066 save the \e frames vector (and maybe put \e currentframe to 0 for \e get, to make sure 00067 the %object is in a stable state), and \e get_state and \e put_state will save/load the 00068 currentframe member. That way, when you load a %game, you can simply get the %object state 00069 from the save file, while the %object itself will be loaded from the %data directory. 00070 00071 \section convsave Conventions for saving/loading methods 00072 To reduce the amount of space needed for the %game, loading/saving methods use the igzstream 00073 and ogzstream classes for disk access. See their own documentation for more details. 00074 00075 The saving methods should be constant - that is, they doesn't change the state of the %object 00076 itself. The loading methods should always bring the %object into a stable state once they 00077 return (think of what would happen if you load an %animation and the \e currenframe member 00078 remains with a value superior to the actual number of %images in this %animation). The 00079 declaration conventions are the following (you can use this template declaration for your 00080 own classes, as it also shows you the proper way to document your code with sections): 00081 00082 \verbatim 00083 class myclass 00084 { 00085 public: 00086 00087 ..... 00088 00089 /** 00090 * @name Loading/Saving methods 00091 * 00092 */ 00093 //@{ 00094 00095 /** 00096 * Loads a <myobject> from an opened file. 00097 * @param file the opened file from which to load. 00098 * @return 0 in case of success, error code otherwise. 00099 * 00100 * @sa load () 00101 * 00102 */ 00103 s_int8 get (igzstream& file); 00104 00105 /** 00106 * Loads a <myobject> from it's filename. 00107 * 00108 * @param fname the name of the file to load. 00109 * @return 0 in case of success, error code otherwise. 00110 * 00111 * @sa get () 00112 */ 00113 s_int8 load (string fname); 00114 00115 /** 00116 * Saves a <myobject> into an opened file. 00117 * 00118 * @param file opened file where to save into. 00119 * @return 0 in case of success, error code otherwise. 00120 * 00121 * @sa save () 00122 */ 00123 s_int8 put (ogzstream& file) const; 00124 00125 /** Saves a <myobject> into a file from it's name. 00126 * @param fname file name where to save into. 00127 * @return 0 in case of success, error code otherwise. 00128 * 00129 * @sa put () 00130 */ 00131 s_int8 save (string fname) const; 00132 //@} 00133 00134 00135 /** 00136 * @name State loading/saving methods 00137 * 00138 */ 00139 //@{ 00140 00141 /** 00142 * Restore the <myobject> state from an opened file. 00143 * 00144 * @param file the opened file from which to load the state. 00145 * @return 0 in case of success, error code otherwise. 00146 */ 00147 s_int8 get_state (igzstream& file); 00148 00149 /** 00150 * Saves the <myobject> state into an opened file. 00151 * 00152 * @param file the opened file where to the state. 00153 * @return 0 in case of success, error code otherwise. 00154 */ 00155 s_int8 put_state (ogzstream& file) const; 00156 00157 //@} 00158 00159 00160 .... 00161 00162 } 00163 \endverbatim 00164 00165 \section objreuse Making your objects reusable 00166 Another issue that can decrease the %game performance is %objects lifetime. 00167 Take our sample %animation class. Say that I've already loaded an %animation that 00168 I don't need anymore, and I need to load another one. If my %object doesn't have 00169 a cleaning method, I'll have to delete my %animation %object and reallocate another 00170 one. And destructor call + deallocation + allocation + constructor call = a lot of 00171 time wasted. This can easily be avoided if your %object has a cleaning method, that 00172 restores it to it's post-constructor state and allow you to reuse it as if it was 00173 a new one. The loading method is a good place where to call this cleaning function, 00174 as you can't expect to load something if your %object isn't empty. In our %animation 00175 sample class, the \e clear () method would delete the \e frames vector (cleaning up 00176 the %datas) and put \e currentframe to 0 (safe, post-constructor state). And I now 00177 can use the same %object multiple times. Most often too, the destructor will be a 00178 simple call to clear (), as it also frees all the memory occupied by the %object. 00179 00180 The declaration convention is quite straightforward then: 00181 \verbatim 00182 class myclass 00183 { 00184 public: 00185 .... 00186 00187 /** 00188 * Puts the <myobject> back to it's post-constructor state. 00189 * 00190 */ 00191 void clear (); 00192 00193 .... 00194 } 00195 \endverbatim 00196 00197 Note that not every %object int the %game needs to be state-saveable. First, they must 00198 have a changeable state, and second, they have to be saved/loaded during %game 00199 saving/loading. 00200 00201 */