DaVikingCode / Citrus-Engine

Modern AS3 Game Engine
http://citrusengine.com/
Other
556 stars 231 forks source link

ObjectMakers and checkpoints #28

Open gsynuh opened 11 years ago

gsynuh commented 11 years ago

I thought I'd start this discussion here since "Issues" is the place to discuss the code itself. So I was wondering, if there is a game to which levels were created using flash pro, and inside this level would be collectable items such as coins maybe. And your hero died at some point and you'd restart the level. Now this may not make sense but maybe you'd want your already collected items to not appear anymore when the level gets restarted... This would make more sense if they were something else rather than coins. I could see various ways of achieving that... but one possibility that would give easy access to such a feature would be to have ObjectMakers accept an array of object names that would refere to objects that shouldn't be created. That way you could restart a level, telling ObjectMaker that the item "item1" shouldn't be re-created on this instance of the level, it would simply bypass the creation of it when processing the level data.

This in turn would benefit in creating a checkpoint system, as levels are not always supposed to be exactly the same. Of course in a checkpoint system, ultimately you would save your score, the position of your hero and ennemies and more properties, but what you wouldn't want to do, is create objects that you would kill instantly just to make it look like you are replaying the same level but in a saved state.

So that is the first Idea I had in mind, There are probably better approaches though, but this seemed fair enough to propose and get the discussion started... As I hope to get a checkpoint system possible , or at least possibly write a tutorial about how such a thing can be done - through the use of "game data" classes as well , which might need a solution for saving data without having to touch SharedObject directly.

Thanks for reading :)

alamboley commented 11 years ago

I'm not a fan of using name, but at the moment I don't find a best process too. My idea would be to register the name into an AGameData var (when the object has been picked up), and then check into the ObjectMakers if there is already some object (so they won't be recreated) or not. And when the level is completed, we flush this array. It seems really easy to set up, but basing on name doesn't sound perfect.

gsynuh commented 11 years ago

there's no other sure way of identifying objects coming from flash pro other than names really.

ideally if we had a new level editor - there could be a numerical ID system - and we wouldn't have to load and parse an swf file but another form of data structure like xml in which ID's would be fixed on objects like names are (and they would be set through the editor, not by the order in which objects were created which wrong), and we'd only have to store in the ID's of objects to not re-create and feed them back to objectmaker the same way we'd do it with names. numerical ID's in that case would be read-only so we can't mess things up on runtime or even when programming.

If we just need to restart a level, we don't even have to parse the swf and recreate objects, simply take them back to where they were and how they were when we saved the checkpoint much like TimeShifter does - a checkpoint would be the snapshot of a frame (we just need to make sure not to try and give a new position to an object that didn't exist anymore when that checkpoint was saved... and possibly kill everything that was created meanwhile (such as monsters that spawned after the checkpoint)

alamboley commented 11 years ago

Yes, ID would be fine. At the moment we could add this property into CitrusObject in read only, it would be generate at the object creation. However to be sure to have exactly one different ID by object, it means that we must be able to loop through them quickly.

ID shouldn't be added into a level editor, it must be internal. This way we're sure there isn't duplicate ID. Also at the moment, nothing prevent several objects to have the same name. The getObjectByName function will return the first one, but we could also create another one which return all objects having the same name.

I think it is better to recreate the state as it was thanks to the swf. This way we're sure everything has been cleaned. It is less CPU & GPU friendly, but we're sure that everything is back to its original version. Some (physics) objects might not be easy to save.

gsynuh commented 11 years ago

I didn't suggest ID's would be assigned manually in a level editor. It would be internal as well (to the editor, that's just what I meant) , surely people shouldn't actually have access to it other than in read only mode. I wasn't sure though if that ID idea would sound good to you. sure the core of CE would take care of asigning new ones upon creation etc... that sounds like the best internal way of identifying objects for checkpoints and maybe other kinds systems (which I can't think of right now).

What I meant though by saving properties, is if we die 3 or 4 steps after checking into the checkpoint, we obviously need to move everything back to their position , whether we re-create the level from the swf or not. we wouldn't care about randomly spawning monsters, but if its a 2D puzzle we would need to move things around at some point anyway. Sure some physics objects wouldn't be easy to save, that's why I think we would give the programmer the tools to save / recover his own stuff... but let him decide when to use the automatic process or not ... because Citrus Engine can't handle all possible cases by itself.

alamboley commented 11 years ago

Maybe the ID system should take care from the entire game, not just a state. Because if we kill an object and remove it, its ID will be free and a new object may take it. Then if we go back to a checkpoints we will have a problem with duplicate ID. However if ID is global, it may be a problem because the same Hero will have different IDs for each new level. Finally maybe we should register IDs into a state and don't remove the ID if the object is killed. Also we have to be sure to not access / change properties of the object using this ID because it is null. What do you think?

In fact there are two ways to manage checkpoint (getting back to the checkpoint if we die/lose) :

Imho, the second one seems to be the best. What dou you think?

useruser3 commented 11 years ago

was thinking about checkpoints last night. is there a way of serialising a state temporarily? that way we could serialize the current state on contact with a checkpoint. couldnt we just have the hero aware of his current location? then when a checkpoint is touched set hero.position.x = heroStart.x and hero.position.y = heroStart.y? no idea if it would work

gsynuh commented 11 years ago

In essence, Id should be like sql Id's with the fact that we can only assign an ID bigger than the latest one used. this of course brings up the fact that no ID is sure to refer to an object that exists... we only know it existed at some point but is probably null now... So you're right in this case, IDs cannot be used to reset properties.

The second option is the best in fact, but not if something died between the checkpoint and the present... which means this would need to be re-created ...

Forgetting about the ID thing here's another thing :

if we stored a level into an xml file for example (when first created).

then once a checkpoint is taken, update this xml file by removing / adding objects that got created/killed... and when "resetting" , feed this xml to a "special" objectmaker - which could be part of the checkpoint system- so what would be created is exactly what was at the moment we took the checkpoint. (as well as resetting properties such as score and health)

This also helps for mutliple checkpoints.

Also a data optimization idea would be to not store a copy of the xml file for each checkpoint, but rather save the differences from the first one (which represents the .swf file) Much like commits here are represented as differences rather than an entire file that changed. Lighter in memory, but to process the differences is maybe not worth it and maybe we'd rather have actual modified copies of the original one.

I guess there is no need for Id's in this case here.

(only the programmer should register the objects he wants to monitor - and the properties he wants to save)

gsynuh commented 11 years ago

@useruser3 , in a way TimeShifter takes "snapshots" of properties on each frame, and only from the properties you asked him to monitor. In a way it is serializing data of a state.

(even if it can actually sound quite ugly how it does it, I guess it illustrates what you're talking about)

it's just not able to revive dead objects... so in a way "serializing data" is only a small element of the entire solution, as we have to have a factory that re-creates dead objects, much like ObjectMaker is actually simply creating a level back to its initial state, but what is the difference between an initial state and a checkpoint state? not much actually, so this is were saving the "differences" might help us I think.

alamboley commented 11 years ago

@gsynuh your idea to register into a xml (I would prefer JSON, also it should make things easier) external file sounds gorgeous! We just need to add the objects we would like to save, and then we don't need to take care of the other things like parallax background art, ect...

useruser3 commented 11 years ago

@gsynuh would it be possible for you to type out your idea for implementing it?

gsynuh commented 11 years ago

@useruser3 , Just know I'd rather discuss about the concepts of the idea and how it would best be implemented rather than the actual implementation I would go for myself as it might be messy even trying to come out with code out of the blue right now - I'd rather wait for the ideas to be more mature in my mind and experiment with them first, and also get ideas from other people much more experienced than I am if I can.... If I start writing, I might not stop, regret almost everything I say and actually waste time that could be used to actually try it out...