Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / How would you implement a Undo/Redo system?

Author
Message
Yodaman Jer
User Banned
Posted: 23rd Jun 2015 02:33
Hey guys,

A few of you may remember that a few months ago, I attempted to create an Undo/Redo system inside of AppGameKit, that could be used in any kind of application that would require such functionality.

Although not perfect, this is the best technique I can come up with.

Basically, what I did is create a UDT called "DataBlock" which has fields which can be used to store any kind of variable, which the user could easily change out for any other.

Then, I created two global, infinite lists based on this UDT, so that both the undo list and redo list can share exactly the same type of data. When the user does a new action, say for example they place a tile in a map editor, the function "AddToUndoList" would be called, and a number would be passed in which would tell the computer "Ok, a tile was just placed, I need to remember what tile it was and where it's placed!". I do that with a Select - EndSelect statement, and a Case - EndCase statement.

Why don't I just paste the code here!



I'm wondering if you guys can maybe think of a better way? I mean sure, this works really well, but after a while, depending on just how functional your program is, you could literally end up with HUNDREDS of Case-EndCase statements to go through, and typing the numbers (it would be better to use clearly-defined #constants) would get quite tiring!

However, this is literally the only thing I can think of, so hopefully someone more brilliant than myself can come up with some suggestions!

Cheers!


Official Forum President from June 20th, 2015 - June 20th, 2016 (when my successor is elected, whomever that may be!).
Markus
Valued Member
20
Years of Service
User Offline
Joined: 10th Apr 2004
Location: Germany
Posted: 23rd Jun 2015 09:24 Edited at: 23rd Jun 2015 09:24
i would try to make for any action/function a opposite one
and put this name with parameters in a list.

means if u call "move, 10" the unso stack get "move, -10"
call "hide", the stack get "show".
just a idea.

AGK 108 (B)19 + AppGameKit V2 Beta .. : Windows 8.1 Pro 64 Bit : AMD Radeon R7 265 : Mac mini OS X 10.10 (Yosemite)
Van B
Moderator
22
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 23rd Jun 2015 22:15
I think maybe that would turn into a bit of a task and the gains might not be worth it, a simpler undo setup might free up time for adding features that will save more time.
Personally, I'd just save the level to an incrementing numbered undo file, deleting old files as you go or recycling them. Of course this would assume that the level would save fairly quickly, so you wouldn't notice the undo file save after releasing the mouse button for instance. Maybe a mix of both is an idea, grid data can be saved directly I mean.

BatVink
Moderator
21
Years of Service
User Offline
Joined: 4th Apr 2003
Location: Gods own County, UK
Posted: 24th Jun 2015 11:09 Edited at: 24th Jun 2015 11:11
I use a similar method to you. You can cover the basics very quickly and simply:

Move
Rotate
Scale
Colour
Alpha
Texture
Create
Delete

Then you need to add anything specific to your application.

When I add to my list, I save the current values and then make the change. E.G

Sprite starts at 0,0
If I move the sprite to 100,100 then I save in a UDT:

SPRITE, ID, POSITION, 0, 0, 10

(There are 3 positions to a sprite, I include depth)
If I undo then I simply know to position Sprite x at 0,0, depth 10.

You only need one array. If you undo, you move the pointer backwards through the list. If you redo, you move it forwards. If you undo and then perform a new action, you clear the list from the pointer forwards, as a redo becomes an invalid action. Then you add the new action.

This uses minimal data and minimal processing of actions. The parameters specific to the action can be held in a string and parsed out. Also bear in mind that nobody is likely to undo beyond 20 or so actions.

In your example you store tile types which seems very specific. Can you not just treat a sprite as a sprite? I don't think any of your tile parameters are necessary, they can all be stored as parameters against an action. For example, if the tile name is important, have a RENAME action and save the name as the parameter attached to the action.

SPRITE, ID, RENAME, MyOriginalTileName

Quidquid latine dictum sit, altum sonatur
TutCity is being rebuilt
Yodaman Jer
User Banned
Posted: 24th Jun 2015 16:23
Quote: "i would try to make for any action/function a opposite one"



This is basically what I would be doing inside of the Case-EndCase statements. For example:



Quote: "You only need one array. If you undo, you move the pointer backwards through the list. If you redo, you move it forwards. If you undo and then perform a new action, you clear the list from the pointer forwards, as a redo becomes an invalid action. Then you add the new action."


Ah, I thought of doing that originally but I remembered having a lot of trouble with trying that back in my DBP days (I tried really hard to make an undo system but could never get it to work!). But with AGK's better implementation of list commands this could be quite possible! Can't believe I didn't think of that!

I'll give that a shot and see how far I can get


Official Forum President from June 20th, 2015 - June 20th, 2016 (when my successor is elected, whomever that may be!).

Login to post a reply

Server time is: 2024-11-25 21:32:39
Your offset time is: 2024-11-25 21:32:39