Game Development Community

Conversations

by Levi · in Torque Game Builder · 09/13/2007 (3:06 pm) · 3 replies

I have a question about conversations/dialogs. I've been thinking about how to impliment a dialog engine.

To me, it would make sense to put the conversations in a structured data file. XML maybe? Obviously, I don't want dialog spread thoughout the script source.

has anyone impliment this sort of thing before? Also, does anyone have suggested approaches to pushing the conversations to the screen? I'd like to make it as generic as possible.

Thanks.

#1
09/13/2007 (8:04 pm)
XML would be a good idea. I haven't seen any resources covering this sort of thing (though, I have not looked too hard), but it would be a pretty handy resource I would imagine.

It is a pretty basic concept and I don't think it would take a great amount of time to implement nicely, however.
#2
09/14/2007 (7:23 am)
I recently did this with arrays, and storing all of the data in a big script file. Not the prettiest thing in the world, but simple to understand.

You can download the project (source included) here:
FindingKeepers_WIN.zip

It has a full cutscene engine in there -- check out cutscene.cs

Apologies for the ugliness -- it was all done for a 2 week speed game coding contest.

--clint
#3
09/18/2007 (5:30 pm)
Here's a resource that parses XML Docs:

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=9031

I also have a script that will give you that typewriter affect for you text as well:

Typewriter.cs
new t2dImageMapDatablock(TextBox)
    {
       imageMode = "full";
       imageName = "~/data/images/TextBox";
    };

    new AudioProfile( LetterClick )
    {
        filename    = "~/data/audio/click.wav";
        description = "AudioNonLooping";
        preload     = true;
    };

datablock t2dSceneObjectDatablock(BulletLabelDatablock)
{
   class     = "BulletLabel"; // associate this datablock with the namespace
   txtPos    = 1;
   delay     = 30;
   MaxLength = 500;
};

function BulletLabel::CreateLabel(%this)
{

    %Box = new t2dStaticSprite() {
            scenegraph       = SceneWindow2D.getSceneGraph();
            ImageMap         = TextBox;
        };
    %this.Box=%box;

    %BulletText = new t2dTextObject() {
            scenegraph       = SceneWindow2D.getSceneGraph();
            size             = "48.025 31.000";
            font             = "Arial Black";
            textAlign        = "Left";
            wordWrap         = "1";
            hideOverflow     = "1";
            lineHeight       = "3";
            aspectRatio      = "1";
            lineSpacing      = "0";
            characterSpacing = "0";
            autoSize         = "0";
            fontSizes        = "80";
            textColor        = "1 1 1 1";
    //        textColor = "0 0.0313726 1 1";
            hideOverlap      = "0";
            
         };
    %this.BulletText=%BulletText;

}

function BulletLabel::DisplayLabel(%this,%ShowText,%X,%Y)
{
  %this.StartAfterPause(0,%ShowText,%X,%Y);//0 is false
}

function BulletLabel::StartAfterPause(%this,%pause,%ShowText,%X,%Y)
{
  if (!IsObject(%this.BulletText)) %this.CreateLabel();

  %this.text=%ShowText;//store for use in ArrowGroup::PlayInOrder

  %ShowText=%ShowText @ %this.CopyString("*",%this.MaxLength-strLen(%ShowText));

  %this.PositionBoxAndText(strlen(%ShowText),%X,%Y);

  if (!%pause) %this.BulletLetter(%ShowText);
}

function BulletLabel::CopyString(%this,%xStr,%xCnt)
{
    for(%X=0;%X<%xCnt;%X++)
      %MakeStr=%MakeStr @ %xStr;

    return %MakeStr;
  
}

function BulletLabel::BulletLetter(%this,%ThisText)
{
  if (getSubStr(%ThisText,%this.txtPos-1,1)!$= "*")
  {
      %this.BulletText.text=getSubStr(%ThisText,0,%this.txtPos)@"|" ;
      if (getSubStr(%ThisText,%this.txtPos-1,1) !$= " ") alxPlay(LetterClick);
      %this.txtPos++;
      
      if (%this.txtPos<strlen(%ThisText)+1) 
        %this.LabelEvent=%this.Schedule(%this.delay,"BulletLetter",%ThisText);
      else %this.BulletText.text=getSubStr(%ThisText,0,%this.txtPos);//remove cursor line when finished
  }
}

function BulletLabel::PositionBoxAndText(%this,%Length,%X,%Y)
{
  %this.BulletText.position = %X SPC %Y;
  %width=%Length*1.4; 
  %this.Box.size = %width SPC %this.BulletText.LineHeight+2;
  %this.Box.Position = %X SPC %Y-4;
}

function BulletLabel::SafeDelete(%this)
{
    %this.BulletText.safeDelete();
    %this.Box.safeDelete();

    Cancel(%this.LabelEvent);
    Cancel(%this.PauseEvent);
    %this.Delete();
}

////////////////////////////////////LabelGroup Class: manage all BulletLabel objects/////////////////////////////////////
datablock t2dSceneObjectDatablock(LabelGroupDatablock)
{
   class      = "LabelGroup"; // associate this datablock with the namespace
   LineCnt    = 0;
   PauseLines = 0;//default is 0 false -no pausing between lines
};

function LabelGroup::NewLine(%this,%ShowText,%X,%Y)
{
  %Label = new t2dStaticSprite() 
    {scenegraph = SceneWindow2D.getSceneGraph();
     config = "BulletLabelDatablock";};

   %this.Line[%this.LineCnt]=%Label;//store each Line in an array to be used later, such as in SafeDelete()
   %this.LineCnt++;
   
   %Label.PauseTime=%Label.delay * strLen(%ShowText);

   if (!%this.PauseLines) %Label.DisplayLabel(%ShowText,%X,%Y);
   else if (%this.LineCnt < %this.PauseLines) %Label.DisplayLabel(%ShowText,%X,%Y);
   else {
        %Label.StartAfterPause(1,%ShowText,%X,%Y);//1 is true
        for(%X=0;%X<%this.LineCnt-1;%X++)
           %totpause += %this.Line[%X].PauseTime;

        %Label.PauseEvent[%this.LineCnt-1]=%this.schedule(%totPause,"PlayInOrder",%Label);
   }

}

function LabelGroup::PlayInOrder(%this,%Label)
{
  %Label.BulletLetter(%Label.text);
}

function LabelGroup::SafeDelete(%this)
{
    for(%X=0;%X<%this.LineCnt;%X++)
        if (IsObject(%this.Line[%X])) %this.Line[%X].safedelete();

   %this.Delete();
}

function typeWriterTextObject::onAdd(%this)
{
   %this.CompleteText = "";
   %this.TextSpeed = 0.5;

}

function typeWriterTextObject::onTimer(%this)
{
  %this.text = %this.text @ getSubStr(%this.CompleteText, strlen(%this.text), 1);

  // uncomment below for sound
  // playSound(typeWriterAudio);
}

function typeWriterTextObject::WriteText(%this, %string, %time)
{
   %this.setTimerOff();
   %this.setVisible(false);
   %this.CompleteText = "";
   %this.text = "";
   if(%string !$= "")
   {
      %this.CompleteText = %string;
   }
   if(%time !$= "")
   {
      %this.TextSpeed = %time;
   }
   %this.setVisible(true);
  %this.setTimerOn(%this.TextSpeed * 1000);
}

function TestLabels()
{
   // Create a new XML document.
   %pXml = new xmlDoc();
   echo("Started new Doc");
   // Load and parse XML file.
   if(!%pXml.loadFile("POSGame/gameScripts/level.xml"))
   {
      echo("Failed to load level.xml!");
      return;
   }
   
   // Push the first child element named "invagersgame" onto the XML document stack.
   if(!%pXml.pushFirstChildElement("greatdialog"))
   {
      // The XML file is in the wrong format.
      echo("Failed to load invaders game.");
      return;
   }
   /*$BLabel = new t2dTextObject() 
    {scenegraph = SceneWindow2D.getSceneGraph();
            name = "textBox";
            class = "typeWriterTextObject";
            size             = "48.025 31.000";
            Position = "10.000 40.000";
            font             = "Arial Black";
            textAlign        = "Left";
            wordWrap         = "1";
            hideOverflow     = "1";
            lineHeight       = "3";
            aspectRatio      = "1";
            lineSpacing      = "0";
            characterSpacing = "0";
            autoSize         = "0";
            fontSizes        = "80";
            textColor        = "1 1 1 1";
    //        textColor = "0 0.0313726 1 1";
            hideOverlap      = "0";
            };*/

   //$Blabel.PauseLines =1;//0=false 1=true
   texter.WriteText(%pXml.getText(),0.01);
   //$BLabel.NewLine("Second line HA HA",-20, 15);
   //$BLabel.NewLine("Third line wow...",-20, 20);
}

level.xml
<?xml version="1.0" encoding="utf-8"?>
<greatdialog>Presently this resource only implements the bare minimum functions needed to
parse XML files in.</greatdialog>

I used level.xml to test the reading and writing of the XML Doc.