Scrolling Game Development Kit Forum

SGDK Version 2 => Help, Errors, FAQ => Topic started by: Vincent on 2009-09-24, 01:54:42 PM

Title: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-24, 01:54:42 PM
Hi guys, I'm fishing for ideas here! :)

I've got a couple of rooms done in the first level of my game now.  I felt like it was a good time to try to add something else, so I decided to implement the first dialogs / cutscenes.

In my game, almost all rules verify if the counter Pause equals 0.  If yes, they execute, otherwise, they don't.  When there is a dialog, I put the game in pause, I set another counter "InDialog" to 1 and I execute a special set of rules that execute only then...  But...  I don't know.  It seems like a lot of work and a lot of specific rules for each dialog...  And I'm a little afraid to mess up the sprites that will be used in the gameplay by mistake.

Would there be a better approach?  I thought that maybe I would make map only for dialogs, with sprites specifically designed for these cutscenes, so there would be no danger to mess up the sprites that will be used for the actual gameplay afterwards.  Hoping that swapping cutscene maps and gameplay maps would be invisible to the player... Would it make the game too big to have maps just for cutscenes?

Has anyone done something like this before and found a good way to do it?   :suspious:

Thanks a lot! :)
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-24, 02:28:04 PM
I'm not quite clear on what you're trying to accomplish with InDialog, or what your question is relative to these counters.  You say that it seems like a lot of work, but what is this work accomplishing? When you ask "Would there be a better approach," I ask, "approach to what?"
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-24, 02:43:30 PM
Okay, I admit it was not too clear.  I got confused! :P

I'm trying to make a conversation between 2 characters.  Basically, it works like this: 
- Stop the gameplay (player cannot control the character)
- Character 1 does something (an animation, moves around, etc). 
- Then everything stops and there is a dialog shown, with the text the character is saying (Not a dialog window like a "yes" "no" window, just a part of a conversation).  This dialog stays there until the player presses the proper message dismissal button. 
- When the message disappear, Character 2 does something (an animation, moves around, etc.)
- Then everything stops and there is a dialog shown, with the text the character is saying (Not a dialog window like a "yes" "no" window, just a part of a conversation).  This dialog stays there until the player presses the proper message dismissal button. 
- (Repeat as needed until the conversation is over.) 
- Finally resume the gameplay, giving back the control to the player.

The two counters "Pause" and "inDialog" are used to indicate which are the rules to execute.   I couldn't rely only on the "Pause" counter, because I also use it when the menu appears, etc.  So I had to put the game on hold with the "Pause" counter and then confirm that it really is a dialog or a cutscene that I want to execute by setting another counter: "InDialog".

I'm saying it seems like a lot of work, because I need to be careful with what I do with the sprites during the conversation (since all their rules are turned off, they could walk trough a wall, etc) and, well, it basically becomes like making a movie rather than a game.  There is no real timeline tools to do, for example: "Character 1 moves toward Character 2 for 1 second (or on a specific distance) then stops, then show the dialog, then wait for input".  So I wondered if it would e a better approach to duplicate my gameplay maps to make cutscene maps.  This way I could isolate the problems and be sure that everyhing is okay when I load the gameplay map.

But then, I'm not sure it is the best approach and I haven't tried it either.  So I wondered if someone actually accomplished something similar previously.

I hope it is easier to understand now! :)
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-24, 05:59:43 PM
I always thought that cutscenes would best be handled by re-routing the inputs for some or all of the sprites.  That's why the inputs for each sprite are separated from the player objects and other potential sources of input.  Then you can route inputs from other sources.  My thought is that all the sprites would continue executing the same rules, but instead of mapping input from player objects, the input would come from a Scripted-Input object of some sort, and maybe the script object is created by you recording inputs from a player object.  This has been done in previous implementations of SGDK, but I don't remember if we have it for SGDK2 yet.

Basically this is how it works.  We set up some class that collects the input from the player object.  Note that each set of inputs can be represented as 1 byte (InputBits enum uses bits 0 through 7).  So it's just collecting 1 byte per frame.  The class tracks 2 values: the current input value and the counter value tracking how many frames that same set of inputs has been active.  If the current inputs byte is the same as the last inputs byte, and the counter is less than 255, then you increment the counter, otherwise you add the counter and the input value bytes to the list of bytes, reset the counter and remember the new input value.  Your list of bytes ends up looking like this:
Byte 0: Input value (which inputs are currently being pressed)
Byte 1: Counter value, how many frames are these inputs repeated
Byte 2: Input value
Byte 3: Counter value
etc...

These bytes could be stored nicely in a custom object's embedded data, and the custom object could load them and replay the same actions on that sprite when commanded to become a source of that sprite's input.

It's a relatively compact way to record inputs for a sprite.  Then the sprite simply reacts to inputs as always.  All you have to do is switch the sprite to receive its input from the script instead of the player when appropriate. Of course, you have to make sure that other conditions are the same too.  If your sprite is not in exactly the same location with exactly the same velocity as it was when you recorded the script, then it could play back very differently.

Then the question is, how do you allow the player to choose when to dismiss the dialogs instead of picking that up from the recorded input, and make sure that the states of the sprites aren't changing while it's waiting for the player to dismiss the dialog.  You could override one bit of the script's input with the actual player input, and that will take care of one problem (allowing the real player to dismiss the dialog instead of the recorded actions).  But then you still need to freeze the input and physics while waiting for the player.  One way to deal with this would be to design your sprites and cut scenes so that they don't depend too much on timing.  Don't allow collisions with other sprites to influence the flow of the cut scene and don't allow scripted sprite motions to interact with other movement actions.  Another thing to consider is saving the current map to a memory slot before the cut scene begins using IncludeMapInSaveUnit, then run the cut scene without caring how screwed up the sprites get, then use LoadGame to load that same slot, and your sprites and tiles for only the current map will be restored to exactly the same state that they were in before the cut scene.  Another way to handle it might be to totally disable all sprite rules when a dialog is active, but there isn't a very nice way to do this except to put a rule at the beginning of each sprite definition to avoid processing rules when inDialog = 1.

I don't know if any of this is helping.  You're still kind of left with the same question you started with -- how to disable rules appropriately when a dialog is showing.  My question now is, why not just disable all sprite rules?  Then sprites can't even move so they can't possibly go through walls if you're not calling MoveByVelocity (or anything else).  But that does mean that the dialog has to be managed by a rule that isn' within the sprite, or the user win't be able to even interact with the dialog.

I guess it would help to know more specifically if you have started implementing this and see problems, or are you just trying to think ahead to the problems you will deal with?  Maybe if you get started, we can deal with smaller problems 1 by 1.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-25, 07:27:54 AM
Wow, thanks bluemonkmn!  I never would have thought to actually record inputs and play them back for a cutscene.  That's a great idea! :)
Saving before and loading after the cutscene is good idea too, but wouldn't loading after the cutscene result in playing the cutscene again, and again, resulting in an infinite loop?

Yes, as you pointed out, I have not started making cutscenes yet.  I'm just planning ahead and wondering what would be the best approach.  I'll give it a try, just making some conversations, without animations and movement.  I'll see how it goes and then, I'll try to add some animations between conversations to see how this turns out.  I'll keep you informed of my progress.

I gave a quick look into the SGDK2 help file, but I don't see any way to record some inputs.  I guess I will have to do it. :)

Thanks again bluemonkmn!  I really appreciate it. :)
Title: Re: Cutscenes, dialogs, etc
Post by: durnurd on 2009-09-25, 08:01:16 AM
If you save only the map data, and you play the cutscene based on a counter being equal to X then it wouldn't play the cutscene a second time if it sets the counter to something else after it starts playing.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-25, 08:03:47 AM
Oh, it's possible to save only the map data?  Great!

Thanks durnurd! :)
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-26, 07:05:29 AM
Right, SGDK2 doesn't have a class to record inputs yet, I don't think.  Maybe I'll work on that this morning of something else doesn't get in the way.  I could create an importable code object that would allow you to record the inputs for a sprite, and another that could play them back.  I've done this 2 or 3 times before, so maybe I can do it in my sleep now :).
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-26, 10:08:13 AM
Here's what I have so far.  I haven't tested it (so I'm sure it doesn't work), and I still may need to show you how to create derived custom code objects with the binary resources embedded (like fmod sounds).  But I think the essential bits are there.  Still need to provide a mechanism to write the recorded data to a file so you can load it as an embedded binary resource in a derived code object.  But maybe if I'm lucky you'll figure it all out before I check back ;).

Oh, and I'm not sure if I'm off by one when playing back frameCount.  I'm not sure if I should move to the next set of inputs when frameCount reaches 0 or 1.  I'll have to think about that a moment... later.

In case you're eager to get going and try to figure it out, here it is.

Code: [Select]
using System;
using System.Collections.Generic;
using System.Text;

namespace CustomObjects
{
   [Serializable()]
class SpriteRecorder : IPlayer
{
      [Serializable()]
      class KeyFrame
      {
         public double x;
         public double y;
         public double dx;
         public double dy;
         public double oldX;
         public double oldY;
         public int state;
         public int frame;
         public SpriteBase.InputBits inputs;
         public double LocalDX;
         public double LocalDY;
      }

      static Dictionary<SpriteBase, SpriteRecorder> records = new Dictionary<SpriteBase, SpriteRecorder>();
      List<byte> movements = new List<byte>();
      KeyFrame initialState = new KeyFrame();
      byte frameCount = 0;
      [NonSerialized()]
      SpriteBase.InputBits inputs;
      [NonSerialized()]
      int playbackPosition = 0;

      [System.ComponentModel.Description("Store the current inputs of the sprite into a recording session")]
      public static void RecordFrame(SpriteBase sprite)
      {
         SpriteRecorder sr = null;
         if (!records.TryGetValue(sprite, out sr))
         {
            sr = new SpriteRecorder(sprite);
            records[sprite] = sr;
         }
         byte inputByte = (byte)sprite.inputs;
         bool nextStep = false;
         if (sr.frameCount >= 255)
            nextStep = true;
         else
         {
            if (sr.movements.Count == 0)
            {
               if (sprite.inputs != sr.initialState.inputs)
                  nextStep = true;
            }
            else
            {
               if ((byte)sprite.inputs != sr.movements[sr.movements.Count - 1])
                  nextStep = true;
            }
         }
         if (nextStep)
            sr.frameCount++;
         else
         {
            sr.movements.Add(sr.frameCount);
            sr.movements.Add((byte)sprite.inputs);
            sr.frameCount = 0;
         }
      }

      [System.ComponentModel.Description("Plays back one frame of input for the specified sprite")]
      public static bool Playback(SpriteRecorder playback)
      {
         if (playback.frameCount <= 0)
         {
            if (playback.movements.Count > ++playback.playbackPosition)
            {
               playback.inputs = (SpriteBase.InputBits)(playback.movements[playback.playbackPosition++]);
               playback.frameCount = playback.movements[playback.playbackPosition];
            }
            else
               return false;
         }
         else
            playback.frameCount--;
         return true;
      }

      protected static SpriteRecorder CreatePlayback(string name)
      {
         using (System.IO.Stream spriteStm = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(name + ".bin"))
         {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
               new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            SpriteRecorder sr = (SpriteRecorder)bf.Deserialize(spriteStm);
            sr.inputs = sr.initialState.inputs;
            return sr;
         }
      }

      private static void CopyState(KeyFrame kf, SpriteBase sprite)
      {
         sprite.x = kf.x;
         sprite.y = kf.y;
         sprite.dx = kf.dx;
         sprite.dy = kf.dy;
         sprite.state = kf.state;
         sprite.frame = kf.frame;
         sprite.inputs = kf.inputs;
         sprite.LocalDX = kf.LocalDX;
         sprite.LocalDY = kf.LocalDY;
         sprite.oldX = kf.oldX;
         sprite.oldY = kf.oldY;
      }

      private byte[] Serialize()
      {
         movements.Add(frameCount);
         System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
            new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
         using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
         {
            bf.Serialize(ms,this);
            ms.Flush();
            return ms.ToArray();
         }
      }

      private SpriteRecorder(SpriteBase sprite)
      {
         initialState.x = sprite.x;
         initialState.y = sprite.y;
         initialState.dx = sprite.dx;
         initialState.dy = sprite.dy;
         initialState.state = sprite.state;
         initialState.frame = sprite.frame;
         initialState.inputs = sprite.inputs;
         initialState.LocalDX = sprite.LocalDX;
         initialState.LocalDY = sprite.LocalDY;
         initialState.oldX = sprite.oldX;
         initialState.oldY = sprite.oldY;
      }

      #region IPlayer Members

      bool IPlayer.Up
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Up); }
      }

      bool IPlayer.Left
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Left); }
      }

      bool IPlayer.Right
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Right); }
      }

      bool IPlayer.Down
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Down); }
      }

      bool IPlayer.Button1
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Button1); }
      }

      bool IPlayer.Button2
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Button2); }
      }

      bool IPlayer.Button3
      {
         get { return 0 != (inputs & SpriteBase.InputBits.Button3); }
      }

      bool IPlayer.Button4
      {
         get { return 0 !=( inputs & SpriteBase.InputBits.Button4); }
      }

      #endregion
   }
}
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-27, 07:18:02 PM
Cool!  I didn't try it yet, but it seems great.  :)

I'll keep you informed! ;D
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-27, 09:09:55 PM
Wish I had more time to work on it.  Maybe tomorrow.
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-28, 09:28:38 PM
I worked on it a bunch and have a much better vision of how it can be used now, (as you might if you look at what's available now).  But I still haven't tested anything.  I know it compiles, but that's it.  (Also, I'm not clear on how/if playback will pause and merge with real player input when a dialog appears, but maybe you already have a solution for that.)  Hopefully I'll get time for testing soon.
Code: [Select]
using System;
using System.Collections.Generic;
using System.Text;

namespace CustomObjects
{
   [Serializable()]
   class RecordingDirectory : System.Collections.Generic.Dictionary<string, SpriteRecorder>
   {
      public static readonly RecordingDirectory value;

      static RecordingDirectory()
      {
         using (System.IO.Stream playbackDataStm = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SpriteRecorder.bin"))
         {
            if (playbackDataStm != null)
            {
               System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
                  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
               value = (RecordingDirectory)bf.Deserialize(playbackDataStm);
            }
            else
            {
               value = new RecordingDirectory();
            }
         }
      }

      private RecordingDirectory()
      {
      }

      protected RecordingDirectory(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
      {
      }

      [System.ComponentModel.Description("Store the current inputs of the sprite into a recording session of the specified name.")]
      public static void RecordSpriteFrame(SpriteBase sprite, string name)
      {
         SpriteRecorder sr = null;
         if (!value.TryGetValue(name, out sr))
         {
            sr = new SpriteRecorder(sprite);
            value[name] = sr;
         }
         sr.RecordFrame(sprite);
      }

      [System.ComponentModel.Description("Sends recorded input to the specified sprite; returns false if playback is complete.")]
      public static bool Playback(String name, SpriteBase sprite)
      {
         SpriteRecorder playback = null;
         if (!value.TryGetValue(name, out playback))
            throw new ApplicationException(String.Format("Sprite recording \"{0}\" not found", name));

         return playback.Playback(sprite);
      }

      [System.ComponentModel.Description("Reset the specified sprite movement recording to the beginning.")]
      public static void ResetPlayback(String name)
      {
         SpriteRecorder playback = null;
         if (!value.TryGetValue(name, out playback))
            throw new ApplicationException(String.Format("Sprite recording \"{0}\" not found", name));

         playback.Reset();
      }

      [System.ComponentModel.Description("Save all sprite recordings to a binary file named SpriteRecorder.bin.")]
      private void SaveRecordings(string Name)
      {
         string existingDataFile = System.Reflection.Assembly.GetExecutingAssembly().Location;
         existingDataFile = System.IO.Path.GetDirectoryName(existingDataFile);
         existingDataFile = System.IO.Path.Combine(existingDataFile, "SpriteRecorder.bin");
         foreach (KeyValuePair<String, SpriteRecorder> entry in this)
            entry.Value.Flush();
         using (System.IO.FileStream stm = new System.IO.FileStream(existingDataFile, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
         {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
               new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            bf.Serialize(stm, value);
         }
      }
   }

   [Serializable()]
   class SpriteRecorder
   {
      [Serializable()]
      class KeyFrame
      {
         public double x;
         public double y;
         public double dx;
         public double dy;
         public double oldX;
         public double oldY;
         public int state;
         public int frame;
         public SpriteBase.InputBits inputs;
         public double LocalDX;
         public double LocalDY;

         public void CopyToSprite(SpriteBase sprite)
         {
            sprite.x = x;
            sprite.y = y;
            sprite.dx = dx;
            sprite.dy = dy;
            sprite.state = state;
            sprite.frame = frame;
            sprite.inputs = inputs;
            sprite.LocalDX = LocalDX;
            sprite.LocalDY = LocalDY;
            sprite.oldX = oldX;
            sprite.oldY = oldY;
         }
      }

      List<byte> movements = new List<byte>();
      KeyFrame initialState = new KeyFrame();
      [NonSerialized()]
      byte frameCount = 0;
      [NonSerialized()]
      SpriteBase.InputBits inputs;
      [NonSerialized()]
      int playbackPosition = 0;

      public void RecordFrame(SpriteBase sprite)
      {
         byte inputByte = (byte)sprite.inputs;
         bool nextStep = false;
         if (frameCount >= 255)
            nextStep = true;
         else
         {
            if (movements.Count == 0)
            {
               if (sprite.inputs != initialState.inputs)
                  nextStep = true;
            }
            else
            {
               if ((byte)sprite.inputs != movements[movements.Count - 1])
                  nextStep = true;
            }
         }
         if (nextStep)
         {
            movements.Add(frameCount);
            movements.Add((byte)sprite.inputs);
            frameCount = 1;
         }
         else
            frameCount++;
      }

      public bool Playback(SpriteBase sprite)
      {
         if (frameCount <= 1)
         {
            if ((frameCount == 0) && (playbackPosition == 0))
            {
               initialState.CopyToSprite(sprite);
               frameCount = movements[playbackPosition];
            }
            else if (movements.Count > ++playbackPosition)
            {
               inputs = (SpriteBase.InputBits)(movements[playbackPosition++]);
               sprite.oldinputs = sprite.inputs;
               sprite.inputs = inputs;
               frameCount = movements[playbackPosition];
            }
            else
               return false;
         }
         else
            frameCount--;
         return true;
      }

      public void Reset()
      {
         playbackPosition = 0;
         frameCount = 0;
      }

      public SpriteRecorder(SpriteBase sprite)
      {
         initialState.x = sprite.x;
         initialState.y = sprite.y;
         initialState.dx = sprite.dx;
         initialState.dy = sprite.dy;
         initialState.state = sprite.state;
         initialState.frame = sprite.frame;
         initialState.inputs = sprite.inputs;
         initialState.LocalDX = sprite.LocalDX;
         initialState.LocalDY = sprite.LocalDY;
         initialState.oldX = sprite.oldX;
         initialState.oldY = sprite.oldY;
         inputs = initialState.inputs;
      }

      public void Flush()
      {
         if ((frameCount > 0) && (playbackPosition == 0))
            movements.Add(frameCount);
         frameCount = 0;
      }
   }
}
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-29, 05:33:03 AM
Wow, this is impressive.  I only had to change one line of code (although I did have to change it 3 times):
Code: [Select]
      private void SaveRecordings(string Name)

should be:
Code: [Select]
      public static void SaveRecordings()

Then it works!

Here's how I used it.  Let me know if you need any additional info/help:
1. Create a new game from the sample game template.
2. Add/Import the SpriteRecorder code as SpriteRecorder.cs.
3. In Level 1, open the Main layer and edit the plan "Player Inputs" in the plan editor.
4. After the "Read player 1 inputs" rule, add a rule named "Record player 1 input".
5. For the rule function, choose CustomObjects.RecordingDirectory.RecordSpriteFrame.
6. Pass the sprite you want to record as a parameter, and provide a quoted string for the name of the recording you want.  I used "p1" as the name.
7. Edit the rules for sprite "Player".
8. Inside the "If menu requested" rule save the recording by adding a rule called "Save recording" which calls the "CustomObjects.RecordingDirectory.SaveRecordings" function.
9. Run the game and play around with the sprite a bit, then press Esc to go to the menu and quit.
10. Open SpriteRecorder.cs for editing in the SGDK2 IDE.
11. From the Embedded Data menu, choose "Load from file...".
12. Go to the directory where your game's EXE file is and select SpriteRecorder.bin.
13. Go back to edit the "Player Inputs" plan
14. Move "Record player 1 input" rule up 1 and change the function to "CustomObjects.RecordingDirectory.Playback"
15. You also have to swap the parameters (I will change this when I release the code as a standard object.  The parameter order should be cosistent. I will use the order currently used by the playback function for both playback and record, I think.)
16. Run the game again and watch the sprite repeat what you did!

Note that the message is not dismissed.  Still have to work that out.  For a while I considered recording and playing back player inputs instead of sprite inputs, but I think for cut scenes you would rather have this operating closer to the sprite.

Hope this works for you.  You can record multiple recordings with different names (and/or different sprites) and have them all saved in the same binary file.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-29, 07:10:25 AM
Wow!!!  :o

I'll give it at try as soon as possible

Thanks a lot bluemonkmn!  ;D
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-09-29, 08:06:36 AM
I forgot to mention, right before step 16, you should also disable the Map Player to Inputs rule (whatever it's called).
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-09-29, 08:31:55 AM
Allright, I will.
Title: Re: Cutscenes, dialogs, etc
Post by: bluemonkmn on 2009-10-10, 08:22:53 AM
Have you had a chance to try it yet.  I've added SpriteRecorder to source control as a code object in the source code library, but I want to make any corrections that may be necessary.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-10-10, 09:12:10 AM
Hi!  Well, finally, I decided not to use it.  I'll explain why:

Using this record/playback feature allows me to make the movements in the cutscene for the character that the player uses, but it limits me in certain aspects.  The player can move the character around, etc.  But some animations are not available to the player by pressing the buttons.  So, for example, when the character dies, he is tranformed in a cloud of bats.  But I also want the character to move around (although not available to the player) in this bat form.  So I can't record inputs to accomplish that.

Also, I cannot use this to move around NPCs, like enemies and friends that are not controlled by the player.  I don't know if you remember, but my character is sort of split in a couple sprites: a hit-zone (invisible, contains most of the code for the player), the character (visible, contains animation but no code), etc.  So, when I switch to a cut scene, I freeze the hitzone, so the player cannot interact, and I make the character move around, play his animations, etc.  When the cutscene ends, I am sure to resume the game at the right position, since the hitzone that dictates everything hasn't moved at all.  The character is moved by to the hitzone location and everything is well.

The only thing that makes it tedious, is that I cannot record what I want to happen, so I have to figure it out frame by frame.  But, since I don't plan making some very difficult cutscenes, I guess I'll be okay.

I'm very sorry if I had you work on this for nothing...  :-[ :-[ :-[

Anyway, I'm sure it will be a great addition to SGDK2, I will probably use it in my future projects, or even in this one later on.

I hope you're not too mad at me...  :-[

Thanks for your time bluemonkmn!  I really appreciate it. :)
Title: Re: Cutscenes, dialogs, etc
Post by: durnurd on 2009-10-10, 11:55:21 AM
You know, you could use this to record NPC sprites as well.  Just for the duration of recording, map the player inputs to whatever sprite you want to control, then when you're done recording, go back to the normal inputs.  Then, during playback, map the inputs to another playback object that has the data for that sprite.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-10-10, 08:14:56 PM
Yes, I know I could, but I would have to define a set of rules specifically for that moving the NPCs around, and well, I thing it's still a little more trouble than to just move them according to frame numbers.  I would probably do it if the cutscenes were long or complex, but since they are not (for the moment)...

Anyway, you will be able to get a more precise idea when you see the cutscenes for yourself.  :)

Title: Re: Cutscenes, dialogs, etc
Post by: durnurd on 2009-10-11, 08:01:50 AM
You may not have built your sprites to work with it, but there's a reason that there's a separation between the player and the player sprite.  The inputs should be allowed to be mapped from anywhere, and that's a good way to design a sprite: map it's inputs from source (x) then do actions based on current inputs, including moving the sprite and performing the special abilities that a sprite can do based on the state of buttons 1-4.

If I'm explaining something you're already doing, forgive me.  But for example, it's easier to set the Right input bit then call AccelerateByInputs, than it is to manually set the dx and dy.
Title: Re: Cutscenes, dialogs, etc
Post by: Vincent on 2009-10-11, 03:41:41 PM
I absolutely agree with you!  ;)

But I would still have to map some abilities to the buttons, and those sprites are not designed to receive any inputs.  So I had a choice: either I mapped some abilities to the buttons and then record the proper actions or I could manage a timeline by counting frames and set all movements and animations by code rather than by a play back.  I opted for the second option.