Rest A-shored
GitHub
- Roles: Programmer
- Time: 4 weeks
- Engine: Unreal Engine 4
- Language: C++
- Genre: Management Survival
- Team Size: 12 (3 programmers)
- Data: 2018
Astrid, go to tent. | ||
Name: Astrid |
Action: Go To |
Object: Tent |
Beatrice, pick up fishing rod. | ||
Name: Beatrice |
Action: Pick Up |
Object: Fishing Rod |
Beatrice, give fishing rod to Astrid. | |||
Name: Beatrice |
Action: Give |
Object: Fishing Rod |
2nd Object: Astrid |
Parsing Commands
- Speech to Text
- Splits the commnd into smaller parts
- Tries to find a Name, the interactable Object and what to use the Object on.
We used an external "speech to text"-plugin called Sphinx. The output from Sphinx were the input used in the parsing system. The system tries to find out if the words are a "Name", "Action" or "Object".
- If the name is in the beginning of the sentence the unit corresponding to that name is selected (registered as a listener to the command system).
- The next thing it looks for is an action like "pick up", "eat" or "hug".
- The last part of the command is what to do the Action to so it tries to identify an Object.
void ATTCommandSystem::StringToCommand(FString text)
{
// Exit function since there's no command listeners
if (listeners.Num() < 1 || !listeners[0])
return;
// Remove the spaces in the beginning of the string
text.TrimStartInline();
// Check if the first word is a name (Special check on the first word)
TArray<UTTCommandListenerComponent*> commandListeners;
// Check if the word is everyone
FString listenerName = "everyone";
if (text.StartsWith(listenerName))
{
// Add all the listeners
for (UTTCommandListenerComponent* listener : listeners)
{
commandListeners.Add(listener);
}
}
// Or check which listeners the player tried to select
else
{
int listenersNum = listeners.Num();
for (int i = 0; i < listenersNum; i++)
{
text.TrimStartInline();
FString listenerName = listeners[i]->ListenerTag.ToString();
bool wordsMatched = text.RemoveFromStart(listenerName);
if (wordsMatched)
{
if(!commandListeners.Contains(listeners[i]))
commandListeners.Add(listeners[i]);
i = -1;
}
}
}
// Select the listeners if any has been found
if(commandListeners.Num() > 0)
SelectListeners(commandListeners);
int verbsNum = verbs.Num();
int interactablesNum = interactableNames.Num();
while(text.Len() > 2)
{
bool wordsMatched = false;
// loop through all the words
for (int i = 0; i < verbsNum + interactablesNum; i++)
{
// Clean up the text
text.TrimStartInline();
// Flag to check if within verbs arrays range
bool withinVerbsRange = i < verbsNum;
// Calculate the correct index to use depending on array
int correctIndex = withinVerbsRange ? i : i - verbsNum;
// Get the word we want to compare
FString wordToCompare = withinVerbsRange ? verbs[correctIndex] : interactableNames[correctIndex];
wordsMatched = text.RemoveFromStart(wordToCompare) ;
if (wordsMatched)
{
// add the command as well
FCommandQueueStruct newCommand;
newCommand.type = withinVerbsRange ? CT_Verb : CT_Object;
newCommand.text = wordToCompare;
commandQueue.Add(newCommand);
break;
}
}
// Remove the first word since it's not recognized
if (!wordsMatched)
{
// Remove first word
int spaceIndex;
text.FindChar(' ', spaceIndex);
if (spaceIndex < 0)
text.Empty();
else
text.RemoveAt(0, spaceIndex + 1);
}
}
PrintQueue(&commandQueue);
SendCommandToUnit();
}
Command System
- Component base
When the system have recognized the whole command it is sent out to the listener. The listener have different events that the desginers of the game could use to create the desired action in game.
void ATTCommandSystem::StringToCommand(FString text)
{
// Exit function since there's no command listeners
if (listeners.Num() < 1 || !listeners[0])
return;
// Remove the spaces in the beginning of the string
text.TrimStartInline();
// Check if the first word is a name (Special check on the first word)
TArray<UTTCommandListenerComponent*> commandListeners;
// Check if the word is everyone
FString listenerName = "everyone";
if (text.StartsWith(listenerName))
{
// Add all the listeners
for (UTTCommandListenerComponent* listener : listeners)
{
commandListeners.Add(listener);
}
}
// Or check which listeners the player tried to select
else
{
int listenersNum = listeners.Num();
for (int i = 0; i < listenersNum; i++)
{
text.TrimStartInline();
FString listenerName = listeners[i]->ListenerTag.ToString();
bool wordsMatched = text.RemoveFromStart(listenerName);
if (wordsMatched)
{
if(!commandListeners.Contains(listeners[i]))
commandListeners.Add(listeners[i]);
i = -1;
}
}
}
// Select the listeners if any has been found
if(commandListeners.Num() > 0)
SelectListeners(commandListeners);
int verbsNum = verbs.Num();
int interactablesNum = interactableNames.Num();
while(text.Len() > 2)
{
bool wordsMatched = false;
// loop through all the words
for (int i = 0; i < verbsNum + interactablesNum; i++)
{
// Clean up the text
text.TrimStartInline();
// Flag to check if within verbs arrays range
bool withinVerbsRange = i < verbsNum;
// Calculate the correct index to use depending on array
int correctIndex = withinVerbsRange ? i : i - verbsNum;
// Get the word we want to compare
FString wordToCompare = withinVerbsRange ? verbs[correctIndex] : interactableNames[correctIndex];
wordsMatched = text.RemoveFromStart(wordToCompare) ;
if (wordsMatched)
{
// add the command as well
FCommandQueueStruct newCommand;
newCommand.type = withinVerbsRange ? CT_Verb : CT_Object;
newCommand.text = wordToCompare;
commandQueue.Add(newCommand);
break;
}
}
// Remove the first word since it's not recognized
if (!wordsMatched)
{
// Remove first word
int spaceIndex;
text.FindChar(' ', spaceIndex);
if (spaceIndex < 0)
text.Empty();
else
text.RemoveAt(0, spaceIndex + 1);
}
}
PrintQueue(&commandQueue);
SendCommandToUnit();
}
Final Thoughts
The greatest hurdle during this project was to find the fun. The lesser used input method did in the end damage the game play by making it harder to control and less responsive. In the end we accepted this as a failed game, but we also recognized that this was still a fun experiment. Even though the game weren’t as fun as we hoped, some players found the game enjoyable in other ways. By just trying commands and see what happens did sometimes have a comical effect.
If I was to create another similar game I would focus more on developing the idea and figuring out beforehand how the input enhances the game play, and not just include it and see it become a gimmick.