Search Unity

Unity Conversation Engine

Discussion in 'Made With Unity' started by Tom163, Dec 14, 2010.

  1. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    I wanted to have a dialog or conversation script that not only plays some audio and throws up subtitles, but also uses cinematic camera shots. I couldn't find any, so I made my own. I originally planned to sell it, but I never got around finishing it, and the project I'm doing it for has been put on the back burner until spring.

    So I'm posting the result here. Find everything at

    http://lemuria.org/projects/wiki/UnityConversationMaker

    UPDATE: It's now on github, use this linke:
    https://github.com/tvogt/conversationengine


    Attached is a screenshot of what it looks like in the editor. This script allows you to set up a branching dialog system with cinematic camera shots, subtitles and a small list of nice features. It's free of charge. If you make any improvements, I'd be happy if you post them or share them with me.
     

    Attached Files:

    Last edited: Dec 11, 2014
  2. WarpedAxiom

    WarpedAxiom

    Joined:
    Oct 27, 2006
    Posts:
    245
    Looks very good.
     
  3. PROTOFACTOR_Inc

    PROTOFACTOR_Inc

    Joined:
    Nov 15, 2009
    Posts:
    4,054
    WOW !!!!! You're awesome Tom !!!! I'm not a coder but i really hope your conversation engine will be implemented by the community ( and fix the few bugs if there are any ...)

    Big Big Thanks !!!!!
     
  4. Demonith

    Demonith

    Joined:
    Mar 14, 2010
    Posts:
    200
    Can this make like quest dialog ?
     
  5. bigkahuna

    bigkahuna

    Joined:
    Apr 30, 2006
    Posts:
    5,434
    Or perhaps an introductory slide show? Very cool stuff Tom.

    P.S. - Why the screenshot from "Inglorious Basterds"?
     
  6. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    @Demonith: That is what it's for, yes.

    @bigkahuna: If you go creative, you could use it for introductions, though it is really built for dialogs, so it needs two actors, etc. The screenshot simply because it illustrates the classic "over the shoulder" shot so well.
     
  7. Stolenbows

    Stolenbows

    Joined:
    Nov 30, 2010
    Posts:
    82
    Thankyou i was just creating a game who really needed this!
    im very thankfull that you make it free
     
  8. aigam

    aigam

    Joined:
    Dec 31, 2005
    Posts:
    170
    Fantastic tool, I can only say thks!
     
  9. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    You're welcome. My Terrain Tools are getting a good reception, so it was time to contribute something for free to the community as well.
     
  10. Falin

    Falin

    Joined:
    Sep 29, 2009
    Posts:
    242
    i get every tim the nullreference exception error
    I don't know what i did wrong.
     

    Attached Files:

  11. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    Downloaded the conversation engine! It's looking good so far. :)

    Very well-done, sir!
     
  12. Ullukai

    Ullukai

    Joined:
    Aug 24, 2010
    Posts:
    746
    Thanks ! This is awesome stuff ! But how do i set the method and parameter areas ? like how do i call functions as you say in the readme file ? and how do i pause the player animations or stop the player completely so that the player does not move when conversations start ? and how do i restart the players movements again ? Good job though ! Even tho i don't know how to use it
     
  13. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Looking at the code, line 98 as the error message says, it appears that you do not have an object with the "Player" tag in your scene. Check that. I agree it should be listed as an explicit requirement, that's one of the downsides of an unfinished script - bad documentation.
     
  14. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    When you activate the "Action" checkbox, further fields will appear that allow you to enter the necesary data.

    To stop, turn or otherwise have player and/or NPC react to the beginning or end of the conversation, make sure they have a script attached with a StartConversationActions() and a StopConversationActions() method. Those will be called when the dialog starts, or ends.
     
  15. Falin

    Falin

    Joined:
    Sep 29, 2009
    Posts:
    242
    this helps
    thanks
     
  16. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    My turn with error detection!

    So, I have a test conversation:

    0: I'm glad you made it, Exile! We've only got one chance to save this village and it involves all the skills a hacker like you would have!
    1: The good news is that we have some spare supplies you can use!

    CHOICE!
    -And the bad news? (To 2)
    -What's the catch? (To 2)

    2: The bad news is that you'll have to use them against a pack of Vernul that are barricading our village's Comms center.

    CHOICE!
    -I understand. I'll go now. (To 3)
    -What do I get out of this? (To 4)
    -Some dogs are why I'm here!? (To 4)

    3: Oh! One more thing before you go! Our comms are fully computer-driven, so make sure you've got equipment to interface with a computer before you fix the Comms system!
    4: Well...our village is rather poor. We're still attracting settlers. We can give you only a little, but you also keep all the gear you use!

    CHOICE!
    -Consider the Comms fixed.

    ...When I end a conversation with this choice, I wind up getting these two errors:

    Code (csharp):
    1. ArgumentOutOfRangeException: Argument is out of range.
    2. Parameter name: index
    3. System.Collections.Generic.List`1[Conversation+DialogItem].get_Item (Int32 index)
    4. Conversation+<StartConversation>c__Iterator0.MoveNext () (at Assets/scripts/Control/Dialogs/Conversation.cs:116)
    Code (csharp):
    1. ArgumentOutOfRangeException: Argument is out of range.
    2. Parameter name: index
    3. System.Collections.Generic.List`1[Conversation+DialogItem].get_Item (Int32 index)
    4. Conversation.OnGUI () (at Assets/scripts/Control/Dialogs/Conversation.cs:217)
    When I look at the code, it appears it dosen't like branching nodes to end the conversation, and I'd rather not make a "null" conversation line - there are plenty of situations like a "I'll just go." dialogue option to quickly back out of the interactive cutscene.
     
  17. Falin

    Falin

    Joined:
    Sep 29, 2009
    Posts:
    242
    i have this too
     
  18. Ullukai

    Ullukai

    Joined:
    Aug 24, 2010
    Posts:
    746
    how do i do that part ? like what am i suppose to type in there or put in there ?
     
  19. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Correct, the jump targets have to exist. I understand what you want to do. A "null" conversation - with empty subtitles and "wait for" set to subtitle - would be the right solution for the moment.
     
  20. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    As a matter of fact, looking into the code I think I didn't finish that part. It should be as easy as adding something like

    Code (csharp):
    1.  
    2. if (has_action) {
    3.    Player.BroadcastMessage(ActionMethod, ActionParameter);
    4. }
    5.  
    into it.
     
  21. Falin

    Falin

    Joined:
    Sep 29, 2009
    Posts:
    242
    this code needs it to be in conversation.js or in own script?
    And with this code its possible to start quests etc. right?
     
  22. Kubaziom

    Kubaziom

    Joined:
    Dec 22, 2010
    Posts:
    6
    I have a small problem to write dialogue that there are no errors.But I do not know what to do to activate dialog.The idea is that when I click on the NPC will start a dialogue.Something you need to add in the script?
     
  23. Falin

    Falin

    Joined:
    Sep 29, 2009
    Posts:
    242
    you need to call StartConversationActions.
    Example:
    Code (csharp):
    1. function OnMouseDown(){
    2. gameObject.BroadcastMessage("StartConversationActions");
    3.      gameObject.BroadcastMessage("OnTriggerEnter");
    4.  
    5. }
    put something like this on the same object as the convesation.
     
  24. psydack

    psydack

    Joined:
    Sep 18, 2009
    Posts:
    8
    revivig the thread:

    Someone know how fix "out of argument"?

    This script is terrific. =)

    Thanks.
     
  25. Slater

    Slater

    Joined:
    May 3, 2011
    Posts:
    23
    I just found this little thingy and hoping for some help and guidance. Im doing a 2d book in unity and Im going to have a narrative voice + text. Would this little package be able to help me out in this area?

    Example.
    You turn to the new page:
    The first 2 sentences are displayed as subtitles and the narrative voice starts automatically. When the voice starts on the third sentence the subtitles switch to the next set of sentences to be displayed.
    When the audio narrative voice is done I will have a button pop up to go to next page.
    Is this possible with this package or do you have any other suggestions?

    Cheers!
     
  26. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    @Slater: You could probably hack it up, but since much of the code is there to deal with actors, camera angles, etc. you would probably be better off to write your own script for your purpose.
     
  27. David Gomez

    David Gomez

    Joined:
    Feb 2, 2012
    Posts:
    1
    Hy every one!!!!First, I have to thanks a lot to Tom for the script, and second I´m doing a game for the university, for learning some programing, but i don´t know why this awesome code not work....maybe my unity version???maybe my unknown???I put the StartConversationActions in the script, on both of them, the player an the NPC, but continue without work.

    Thanks a lot
     
  28. maskedshuuyu

    maskedshuuyu

    Joined:
    Oct 1, 2012
    Posts:
    2
    Reviving this quite old thread, but I can't seem to trigger the script to run at all, all I get is a the error:

    Failed to call function OnTriggerEnter of class triggerconvo
    Calling function OnTriggerEnter with no parameters but the function requires 1.
    UnityEngine.GameObject:BroadcastMessage(String)

    and

    BroadcastMessage StartConversationActions has no receiver!
    UnityEngine.GameObject:BroadcastMessage(String)

    Is there some tag I'm missing? I can make the gameobject turn to the player, but no dialogue appears.
     
    Last edited: Oct 23, 2012
  29. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    My best guess without looking at any code is that the API has changed and OnTriggerEnter() now requires a paramenter. Check the Unity documentation for what that parameter is and update the script to include it.
     
  30. hike1

    hike1

    Joined:
    Sep 6, 2009
    Posts:
    401
    Thanks, Tom, this is working.

    I just made this javascript and put it on the NPC cube made his Box Collider a Trigger-Yes, made the collider larger than the cube

    //StartConversation.js, starts conversation with NPC place on him
    #pragma strict



    function OnMouseDown(){

    gameObject.BroadcastMessage("StartConversationActions");

    gameObject.BroadcastMessage("OnTriggerEnter");
    }


    A few questions. the script jumps to the Conversation camera on start of conversation, what if you just wanted to use the camera built in
    to the FPS controller?

    Does the Player need the conversation scripts or just the NPC's?

    Any way to save the conversations so on reload the conversation would resume where left off?
     
  31. hike1

    hike1

    Joined:
    Sep 6, 2009
    Posts:
    401
    I'm having a little problem getting past a 2 sentence conversation,

    1. Branching choice
    Hello Player-to branching choice -Hello NPC (but there's no way to select who's saying, except on 'add dialog element'
    Goodbye-end conversation-This gives' index out of range error line 116'

    Next bit is "Hello NPC". How do I get the npc to reply and then continue back and forth?

    "Enough chitchat, it's time for some action!" Dupre in Ultima 6
     

    Attached Files:

  32. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Sure, hike1, all of that is easily possible - you just have to code it yourself. :)

    Sorry that I can't provide actual support for this, it's been at least a year until I've looked at the code. Maybe I should put it on github and make it a community project?
     
  33. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
  34. hike1

    hike1

    Joined:
    Sep 6, 2009
    Posts:
    401
    Thanks, there are 2 scripts I didn't have before, DialogControl.js and Dialog.js, are these used in addition to Conversation.cs and ConversationActions.js?
    I assume the Editor is always needed.
     
  35. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Was going to take a look at the github but then saw the license... it's CC-SA which basically works just like GPL; you can not use this code in a game unless you open source the entire game. Is that the intention?
     
  36. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    That's not how I read the license.

    It is GPL-like if you build an adaptation, derivation, etc. - i.e. if you take it, expand it and create a better conversation library with it.

    I don't read it as applying to a game you build using it. But if you're worried, tell me which license you think is better.
     
  37. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Creative Commons themselves don't recommend using CC licenses on software because they agree the interperetation is murky; CC licenses were written with music and movies in mind more than source code. (Link) But GPL has put a lot of work into enforcing the idea that any code that incorporates someone else's code is a derivative work, so CC agrees that a CC-SA license would probably be enforced similarly to GPL.

    Personally I like the MIT license (link) or the BSD license (link). They let people use the code for pretty much whatever they want.
     
  38. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Negative. I don't want MIT or BSD licenses. I didn't put this out there so someone else can take it, polish it a little and then put it on the Asset Store as a commercial product.

    The part where it says that you have to share-alike if you expand it is fully intentional. It's the part about using it in your game that needs clarification.
     
  39. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    I've clarified the license file.

    If you use it to create a game, apply the BSD license.
    If you create a new conversation script based on this, it's still the CC license.
     
  40. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    That sounds good. Thanks Tom!
     
  41. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    It would be fantastic if anyone could provide any additional information about the method and parameter sections and how they work. One of the posters referred to a read_me. But, the download didn't have one included. Any help is appreciated.
     
  42. Aspiring_Failure

    Aspiring_Failure

    Joined:
    Jan 21, 2013
    Posts:
    42
    This is pretty cool. When I clicked here, I was expecting something remarkably simple, -but the branching choices and dynamic cameras are really cool. The interface looks a little bit cumbersome to work with, but I can't speak on experience with it. I might throw together a project on the side that uses this, though.
     
  43. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    I have some people smarter than me working on how to fix the action component. Will post a solution if they agree. It is a bit frustrating that it is unfinished, but a great tool none-the-less
     
  44. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    I'm glad that this is picking up steam. I do think it's a cool tool and I'm kind of sorry that I never finished it, but now that it's on github, the community will probably turn it into something even better, and that's really cool.
     
  45. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    Alright. I am, by no means a coder. But I am trying to figure out how to solve this problem with the action/parameter issue to ensure that using the conversation engine will allow you to complete quests.

    What I know:

    1. Tom mentioned that he did not finished that section of the script. He also provided some sample code that may help solve the problem.

    Code (csharp):
    1. if (has_action) {
    2.  
    3.    Player.BroadcastMessage(ActionMethod, ActionParameter);
    4.  
    5. }
    2. These is a section in Conversation.cs which appears to be relevant, but I don't think this boolean is every referred to anywhere else.

    Code (csharp):
    1. public bool has_action = false;
    2.         public String ActionMethod;
    3.         public String ActionParameter;
    3. Player is never defined in ConversationEditor.cs . Suggests that Tom meant the code provided in (1.) to go into Conversation.cs instead of ConversationEditor.cs.


    What I don't know:

    1. Exactly where in Conversation.cs the provided code should be inserted.
    2. whether the provided code will be sufficient.
    3. whether additional functions need to be written to execute the action (this seems likely).

    Still working on it.

    -----------------------

    EDIT:

    This appears to just add the text fields and other elements to the GUI.

    Code (csharp):
    1. dialog.has_action = EditorGUILayout.Toggle("Action", dialog.has_action);
    2.                     if (dialog.has_action) {
    3.                         EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); EditorGUILayout.BeginVertical();
    4.                             dialog.ActionMethod = EditorGUILayout.TextField("Method", dialog.ActionMethod);
    5.                             dialog.ActionParameter = EditorGUILayout.TextField("Parameter", dialog.ActionParameter);
    6.                         EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal();            
    7.                     }

    I *think* the code Tom provided needs to go somewhere in here:

    Code (csharp):
    1.     // run the conversation tree       
    2.             for (index = 0; index < dialog.Count; index++) {
    3.                 DialogItem d = dialog[index];
    4.  
    5.                 PositionCamera(Camera.main.transform, d);
    6.  
    7.                 if (d.is_branch) {
    8.                     if (CursorLocked) Screen.lockCursor = false; // unlock the cursor, because we need it
    9.                     branching = true; talking = false;
    10.                     yield return StartCoroutine(Branch(d, index));
    11.                     index--; // correct that the for loop will increment it
    12.                     if (CursorLocked) Screen.lockCursor = true; // lock the cursor, if it was locked
    13.                 } else {
    14.                     talking = true; branching = false;
    15.                     yield return StartCoroutine(Talk(d));
    16.                 }
    17.                
    18.            
    19.            
    20.             } // endof loop over all dialog elements
    I am not able to get the syntax right just yet. Still working on it.
     
    Last edited: Jul 22, 2013
  46. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    So, I fixed the problem with the Camera thing.

    If you want to disable the use of the camera created in the script (and just use the camera on your First person controller), find this line:


    Code (csharp):
    1.  
    2.     PositionCamera(Camera.main.transform, d);
    and delete it.

    All of the definitions for the camera are still there, so if you want to added that line back in later, you can.
     
  47. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    I *think* this is right so far.

    Code (csharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [Serializable] 
    7. public class Conversation : MonoBehaviour {
    8.  
    9.     public enum Perspectives {
    10.         Classic_Two_Shot,
    11.         Player_Profile, Player_Halfprofile, Near_Player_looking_at_NPC, Behind_Player_looking_at_NPC,
    12.         NPC_Profile, NPC_Halfprofile, Near_NPC_looking_at_Player, Behind_NPC_looking_at_Player
    13.     };
    14.     public enum Angles {
    15.         low, level, high
    16.     }
    17.     public enum Distances {
    18.         closeup, medium, full
    19.     }
    20.     public enum Sides {
    21.         left, right
    22.     }
    23.     public enum Waits {
    24.         Audio, Animation, Subtitle
    25.     }
    26.     public enum Speakers {
    27.         Player, NPC
    28.     }
    29.  
    30.     [Serializable] 
    31.     public class DialogItem {
    32.         public bool show = true;
    33.         public Speakers speaker = Speakers.NPC;
    34.         public AudioClip spoken = null;
    35.         public string subtitle = "(enter subtitle text)";
    36.         public AnimationClip player_animation = null;
    37.         public AnimationClip npc_animation = null;
    38.         public Waits wait = Waits.Audio;
    39.         public bool show_camera =true;
    40.         public Perspectives perspective = Perspectives.Classic_Two_Shot;
    41.         public Angles angle = Angles.level;
    42.         public Distances distance = Distances.medium;
    43.         public Sides side = Sides.left;
    44.        
    45.         public bool is_branch = false;
    46.         public List<String> choice;
    47.         public List<int> jump;
    48.        
    49.         public bool has_action = false;
    50.         public String ActionMethod;
    51.         public String ActionParameter;
    52.        
    53.         public DialogItem(bool branch=false, bool act=false) {
    54.             if (branch) {
    55.                 is_branch = true;
    56.                 subtitle = "Branching Choice";
    57.             }
    58.            
    59.             if (act) {
    60.                 has_action = true;
    61.                 subtitle = "Action";
    62.             }  
    63.         }
    64. }
    65.        
    66.    
    67.    
    68.     public void Act() {
    69.    
    70.     GameObject player = GameObject.FindGameObjectWithTag("Player");
    71.         player.GetComponent<questCount>().questChange(999);
    72.    
    73.            
    74.     }
    75.    
    76.    
    77.        
    78.     public List<DialogItem> dialog;
    79.  
    80.  
    81.     // other variables
    82.     public bool Repeat = false; // whether or not we repeat the conversation when the player comes a 2nd time
    83.     public GUISkin MySkin;
    84.     public float subtitle_width = 0.8f;
    85.     public float subtitle_offset = 0.05f;
    86.     public float subtitle_margin = 32f;
    87.    
    88.     private bool firsttime = true;
    89.     private GameObject Player;
    90.     private Transform CamOrigParent;
    91.     private Vector3 CamOrigPos;
    92.     private Quaternion CamOrigRot;
    93.  
    94.     private Transform Player_Face;
    95.     private Transform NPC_Face;
    96.     private float scale;
    97.  
    98.     private bool talking = false;
    99.     private bool branching = false;
    100.     private int index = 0;
    101.     private bool CursorLocked = false;
    102.  
    103.     void OnTriggerEnter() {
    104.         if (firsttime || Repeat) {
    105.             firsttime = false;
    106.             gameObject.BroadcastMessage("StartConversationActions", null, SendMessageOptions.DontRequireReceiver);
    107.             StartCoroutine(StartConversation());
    108.         }
    109.     }
    110.  
    111.     IEnumerator StartConversation() {
    112.         if (dialog!=null) {
    113.             CursorLocked = Screen.lockCursor;
    114.             Player = GameObject.FindWithTag("Player");
    115.             Player.BroadcastMessage("SetControllable", false);
    116.             scale = Player.transform.lossyScale.y/2;
    117.             Player_Face = Player.transform.Find("Face");
    118.             if (!Player_Face) { // fallback - our main position
    119.                 Player_Face = Player.transform;
    120.             }
    121.             NPC_Face = transform.Find("Face");
    122.             if (!NPC_Face) { // fallback - we don't have a face, so we use our main position
    123.                 NPC_Face = transform;
    124.             }
    125.  
    126.             CamOrigParent = Camera.main.transform.parent;
    127.             CamOrigPos = Camera.main.transform.localPosition;
    128.             CamOrigRot = Camera.main.transform.localRotation;
    129.             Camera.main.transform.parent = null;
    130.  
    131.             // run the conversation tree       
    132.             for (index = 0; index < dialog.Count; index++) {
    133.                 DialogItem d = dialog[index];
    134.                 DialogItem h = dialog[index];
    135.  
    136.                 PositionCamera(Camera.main.transform, d);
    137.  
    138.                 if (d.is_branch) {
    139.                     if (CursorLocked) Screen.lockCursor = false; // unlock the cursor, because we need it
    140.                     branching = true; talking = false;
    141.                     yield return StartCoroutine(Branch(d, index));
    142.                     index--; // correct that the for loop will increment it
    143.                     if (CursorLocked) Screen.lockCursor = true; // lock the cursor, if it was locked
    144.                 } else {
    145.                     talking = true; branching = false;
    146.                     yield return StartCoroutine(Talk(d));
    147.                 }
    148.                
    149.                 if (h.has_action) {
    150.                
    151.                 Player.BroadcastMessage(ActionMethod, ActionParameter);
    152.                    
    153.                 }
    154.                
    155.             } // endof loop over all dialog elements
    156.  
    157.             ReturnToScene();
    158.         }
    159.     }
    160.  
    161.     IEnumerator Talk(DialogItem d) {
    162.         float WaitTime = 0f;
    163.  
    164.         switch (d.wait) {
    165.             case Waits.Audio:
    166.                 if (d.spoken!=null) WaitTime = d.spoken.length;
    167.                 break;
    168.             case Waits.Animation:
    169.                 if (d.speaker==Speakers.Player) {
    170.                     if (d.player_animation) WaitTime = d.player_animation.length;
    171.                 } else {
    172.                     if (d.npc_animation) WaitTime = d.npc_animation.length;
    173.                 }
    174.                 break;
    175.         }
    176.         // fallback - same as Waits.Subtitle
    177.         if (WaitTime==0f) WaitTime = (float)d.subtitle.Length/12f;
    178.        
    179.         // spoken text audio output
    180.         if (d.spoken) {
    181.             audio.enabled = true;
    182.             audio.clip = d.spoken;
    183.             audio.Play();
    184.         }
    185.        
    186.         // animations
    187.         if (d.player_animation  Player.animation!=null) Player.animation.CrossFade(d.player_animation.name);
    188.         if (d.npc_animation  animation!=null) animation.CrossFade(d.npc_animation.name);
    189.  
    190.         // wait until we are done before doing next in loop
    191.         yield return new WaitForSeconds(WaitTime);
    192.        
    193.     }
    194.  
    195.     IEnumerator Branch(DialogItem d, int i) {
    196.         while (index == i) {
    197.             yield return null;
    198.         }
    199.     }
    200.  
    201.     void ReturnToScene() {
    202.         talking = false;
    203.         gameObject.BroadcastMessage("StopConversationActions", null, SendMessageOptions.DontRequireReceiver);
    204.        
    205.         Camera.main.transform.parent = CamOrigParent;
    206.         Camera.main.transform.localPosition = CamOrigPos;
    207.         Camera.main.transform.localRotation = CamOrigRot;
    208.  
    209.         Player.BroadcastMessage("SetControllable", true);
    210.  
    211.         // back to the default animation - since we're making a camera cut, no need to fade
    212.         if (animation!=null) {
    213.             animation.Stop();
    214.             animation.Play();
    215.         }
    216.     }
    217.  
    218.  
    219.     /* ========== Camera Handling and GUI ========== */
    220.  
    221.     void OnGUI() {
    222.         if (talking || branching) {
    223.             GUI.skin = MySkin;
    224.  
    225.             // estimate the height we will need
    226.             int fontsize = GUI.skin.label.fontSize;
    227.             if (fontsize==0) {
    228.                 // default font size - how do we get this? TODO
    229.                 fontsize=24;
    230.             }
    231.             if (talking) {
    232.                 float chars_per_line = (float)Screen.width*0.8f / (float)fontsize;
    233.                 float lines = 1.2f*Mathf.Ceil((float)(dialog[index].subtitle.Length)/(chars_per_line*2f)); // 1.2 lines-with-spacing times lines required, estimating that width of characters is 1/2 height at average
    234.  
    235.                 GUILayout.BeginArea(new Rect(Screen.width*(1f-subtitle_width)/2f, Screen.height-(fontsize*lines)-(Screen.height*subtitle_offset)-subtitle_margin, Screen.width*subtitle_width, (float)(fontsize*lines)+ subtitle_margin), new GUIStyle("box"));
    236.                 GUILayout.Label(dialog[index].subtitle);
    237.                 GUILayout.EndArea();
    238.             } else {
    239.                 float lines = 1.6f*(float)dialog[index].choice.Count; // need more space, for the buttons
    240.  
    241.                 GUILayout.BeginArea(new Rect(Screen.width*(1f-subtitle_width)/2f, Screen.height-(fontsize*lines)-(Screen.height*subtitle_offset)-subtitle_margin, Screen.width*subtitle_width, (float)(fontsize*lines)+ subtitle_margin), new GUIStyle("box"));
    242.                 for (int i=0; i<dialog[index].choice.Count; i++) {
    243.                     if (GUILayout.Button((i+1)+" - "+dialog[index].choice[i])) {
    244.                         index = dialog[index].jump[i];
    245.                         branching = false;
    246.                     }
    247.                 }
    248.                 GUILayout.EndArea();               
    249.             }
    250.         }
    251.     }
    252.  
    253.  
    254.     void PositionCamera(Transform DialogCamera, DialogItem d) {
    255.         Vector3 Look;
    256.         Vector3 Side;
    257.         float distance = 2f;
    258.            
    259.         if (d.side==Sides.left) Side=Vector3.left; else Side=Vector3.right;
    260.            
    261.         if (d.distance==Distances.closeup) {
    262.             distance = 1f;
    263.         } else if (d.distance==Distances.full) {
    264.             distance = 3f;
    265.         } else { // medium = default
    266.             distance = 2f;
    267.         }
    268.  
    269.  
    270.         if (d.perspective == Perspectives.Near_Player_looking_at_NPC) {
    271.             DialogCamera.position = Player_Face.position;
    272.             DialogCamera.LookAt(NPC_Face);
    273.             DialogCamera.Translate(Side * distance);
    274.             Look = NPC_Face.position;
    275.         } else if (d.perspective == Perspectives.Behind_Player_looking_at_NPC) {
    276.             DialogCamera.position = Player_Face.position;
    277.             DialogCamera.LookAt(NPC_Face);
    278.             DialogCamera.Translate((Side-Vector3.forward)*distance);
    279.             Look = NPC_Face.position;
    280.         } else if (d.perspective == Perspectives.Near_NPC_looking_at_Player) {
    281.             DialogCamera.position = NPC_Face.position;
    282.             DialogCamera.LookAt(Player_Face);
    283.             DialogCamera.Translate(Side*distance);
    284.             Look = Player_Face.position;
    285.         } else if (d.perspective == Perspectives.Behind_NPC_looking_at_Player) {
    286.             DialogCamera.position = NPC_Face.position;
    287.             DialogCamera.LookAt(Player_Face);
    288.             DialogCamera.Translate((Side-Vector3.forward)*distance);
    289.             Look = Player_Face.position;
    290.         } else if (d.perspective == Perspectives.Player_Profile) {
    291.             DialogCamera.position = Player_Face.position;
    292.             DialogCamera.LookAt(NPC_Face);
    293.             DialogCamera.Translate(Side*distance);
    294.             Look = Player_Face.position;
    295.         } else if (d.perspective == Perspectives.Player_Halfprofile) {
    296.             DialogCamera.position = Player_Face.position;
    297.             DialogCamera.LookAt(NPC_Face);
    298.             DialogCamera.Translate((Side+Vector3.forward)*distance);
    299.             Look = Player_Face.position;
    300.         } else if (d.perspective == Perspectives.NPC_Profile) {
    301.             DialogCamera.position = NPC_Face.position;
    302.             DialogCamera.LookAt(Player_Face);
    303.             DialogCamera.Translate(Side*distance);
    304.             Look = NPC_Face.position;
    305.         } else if (d.perspective == Perspectives.NPC_Halfprofile) {
    306.             DialogCamera.position = NPC_Face.position;
    307.             DialogCamera.LookAt(Player_Face);
    308.             DialogCamera.Translate((Side+Vector3.forward)*distance);
    309.             Look = NPC_Face.position;
    310.         } else { // classic two_shot = default
    311.             var Target = Vector3.Min(NPC_Face.position, Player_Face.position) + (Vector3.Max(NPC_Face.position, Player_Face.position) - Vector3.Min(NPC_Face.position, Player_Face.position))/2;
    312.             DialogCamera.position = Target;
    313.             DialogCamera.LookAt(NPC_Face);
    314.             DialogCamera.Translate(Side * distance * Vector3.Distance(NPC_Face.position, Player_Face.position)/2);
    315.             Look = Target;
    316.         }
    317.  
    318.         if (d.angle==Angles.low) {
    319.             DialogCamera.Translate(-Vector3.up * distance * scale, Space.World);
    320.         } else if (d.angle==Angles.high) {
    321.             DialogCamera.Translate(Vector3.up * distance * scale, Space.World);
    322.         } else { // level = default
    323.         }
    324.  
    325.         DialogCamera.LookAt(Look);
    326.        
    327.     }
    328. }
    329.  
    This section will produce errors for right now. ActionMethod and ActionParameter aren't defined yet, I don't think. So it doesn't know what to do with those just yet. But, otherwise I think the structure is right. I think...

    Code (csharp):
    1. Player.BroadcastMessage(ActionMethod, ActionParameter)
    Replacing Player.BroadcastMessage...... with a GetComponent to call a function in another script works. I just need to figure out how to get that call to accept the information from the text fields.
     
    Last edited: Jul 22, 2013
  48. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    Huzzah! This doesn't fix everything. Not yet. But, on to the next problem.

    Code (csharp):
    1. if (h.has_action) {
    2.                    
    3.                     Debug.Log ("Fire1");
    4.                    
    5.                     GameObject player = GameObject.FindGameObjectWithTag("Player");
    6.                     player.BroadcastMessage(j.ActionMethod,p.ActionParameter);
    7.                    
    8.                 }
     
    Last edited: Jul 22, 2013
  49. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    It's late and I'm tired, so, with plenty of salt:


    The basic idea was that the Conversation script knows nothing about your actors, quests or such and doesn't have to. What it does is define points in the dialog tree where a message is broadcast. That message is picked up by the actor and he can do whatever it is he needs to do.


    So the Conversation script would broadcast such messages as StartQuest() or GetGold(100) or whatever, but it would not handle these actions itself.

    In these examples, ActionMethod would be "GetGold" and ActionParameter would be 100. And the Player object would have a GetGold(int amount) method defined that internally does whatever it needs to do to add 100 gold to the player, probably calling the inventory handling system or whatever.
     
  50. mrliioadin

    mrliioadin

    Joined:
    Jul 13, 2013
    Posts:
    21
    Yes, that is understood. In my case, that is the setup I am using. I have no doubt that you built a tool that could be easily polished up to do this effortlessly. But I've been coding in c# for about a week. So, it's been a difficult go to try to sort through everything to figure out exactly what you left out and where.

    I am hoping that I (or someone else) can post a solution to get it working.