Game Builder

Game Builder

Not enough ratings
Talking with NPCs
By Sandles
Do you want to talk with NPCs in your game? Follow the instructions in this guide!
   
Award
Favorite
Favorited
Unfavorite
In-action
This is an example of the dialog you can have with an NPC. In this example, I'm displaying the dialog after I collide with the NPC, but you can very easily set up another trigger.

The setup
To talk with any NPC, you'll need to hook up the dialog card to any event, in this example, we are listening for a message that is sent to the player after the NPC collides with the player. When the message is heard, the dialog will start. You do not have to follow this example, and instead can choose another way to initiate the dialog.

The code
Here is the code for the dialog panel.


export const PROPS = [
propEnum("TalkKey", "t", getKeyEnumValues(), {
label: "Key to talk?",
}),
propString("text1", "", {
label: "Dialog 1"
}),
propString("text2", "", {
label: "Dialog 2"
}),
propString("text3", "", {
label: "Dialog 3"
}),
propString("text4", "", {
label: "Dialog 4"
}),
propString("text5", "", {
label: "Dialog 5"
})
];

function getKeyEnumValues() {
const ret = [];
for (const keyName in KeyCode) {
ret.push({
value: KeyCode[keyName],
label: keyName
});
}
return ret;
}

function getMyKeyName() {
// Note: old versions of this card accepted TalkKey as string, which means
// it can be in uppercase, which is why we convert below:
return (props.TalkKey || "").toLowerCase();
}

const dialogMinX = 500;
const dialogMinY = 725;
const dialogXLen = 600;
const dialogYLen = 100;
const dialogColor = 0x353232;
const dialogOptions = {
opacity: 0.75
};

function buildTextData() {
var rawText = [];
if (props.text1.length > 0) {
rawText.push(props.text1);
}
if (props.text2.length > 0) {
rawText.push(props.text2);
}
if (props.text3.length > 0) {
rawText.push(props.text3);
}
if (props.text4.length > 0) {
rawText.push(props.text4);
}
if (props.text5.length > 0) {
rawText.push(props.text5);
}

card.textData = [];
var set = "";

for (var i = 0; i < rawText.length; i++) {
card.textData.push([]);
set = "";

for (var j = 0; j < rawText[i].length; j++) {

if (uiGetTextWidth(set + rawText[i][j]) >= dialogXLen) {
card.textData[i].push(set);
set = rawText[i][j];
} else {
set += rawText[i][j];

if (j + 1 === rawText[i].length) {
card.textData[i].push(set);
set = "";
}
}
}

if (set.length > 0) {
if (uiGetTextWidth(set + card.textData[i][card.textData[i].length - 1]) >= dialogXLen) {
card.textData[i].push(set);
} else {
card.textData[i][card.textData[i].length - 1] += set;
}
}
}

card.built = true;
}


function drawDialogBox() {
// 1600 x 900
uiRect(dialogMinX, dialogMinY, dialogXLen, dialogYLen, dialogColor, dialogOptions);
}

function drawText() {
var totalChars = Math.floor(card.tick / 5);
var waiterDots = Math.floor(card.waiterTick / 30);
var waiter = false;
if (totalChars >= card.textData[card.pageNum].join('').length) {
waiter = true;
}

var totalCharsFirstLineTemp = totalChars;
var indexStrHeight = 0;
var totalHeight = 0;
var heightMaxed = false;
var firstLine = 0;
var spaceBetweenLines = 20;

for (var i = 0; i < card.textData[card.pageNum].length; i++) {
if (totalCharsFirstLineTemp === 0) {
break;
}

indexStrHeight = 0;
if (indexStrHeight === 0) {
indexStrHeight = uiGetTextHeight(card.textData[card.pageNum][i]);
}

if ((totalHeight + (indexStrHeight)) <= dialogYLen) {
totalHeight += (indexStrHeight);
} else {
heightMaxed = true;
totalChars -= card.textData[card.pageNum][firstLine].length;
firstLine++;
}

if (totalCharsFirstLineTemp > card.textData[card.pageNum][i].length) {
totalCharsFirstLineTemp -= card.textData[card.pageNum][i].length;
} else {
break;
}
}

if (waiter) {
card.waiterTick++;

if (heightMaxed) {
totalChars -= card.textData[card.pageNum][firstLine].length;
firstLine++;
}

if (!card.endOfText) {
card.endOfText = true;
card.textData[card.pageNum].push("Continue");
}

var dots = "";
switch (waiterDots) {
case 1:
dots += ".";
break;
case 2:
dots += "..";
break;
case 3:
dots += "...";
break;
default:
break;
}
card.textData[card.pageNum][card.textData[card.pageNum].length - 1] = `Continue${dots}`;

if (waiterDots > 3) {
card.waiterTick = 1;
}
}

for (var i = firstLine; i < card.textData[card.pageNum].length; i++) {
if (card.textData[card.pageNum][i].length <= totalChars) {
uiText(dialogMinX, dialogMinY + ((i - firstLine) * spaceBetweenLines), card.textData[card.pageNum][i]);
} else {
uiText(dialogMinX, dialogMinY + ((i - firstLine) * spaceBetweenLines), card.textData[card.pageNum][i].substring(0, totalChars));
break;
}
totalChars -= card.textData[card.pageNum][i].length;
}
}

export function onKeyDown(msg) {
if (msg.keyName === getMyKeyName()) {
card.goFaster = true;
}
}

export function onKeyUp(msg) {
if (msg.keyName === getMyKeyName() && !card.endOfText){
card.goFaster = false;
}

if (msg.keyName === getMyKeyName() && card.endOfText) {
card.endOfText = false;

if (card.pageNum + 1 < card.textData.length) {
card.pageNum++;
card.tick = 0;
card.waiterTick = 0;
} else {
// end of conversation
card.pageNum = 0;
card.tick = 0;
card.waiterTick = 0;
card.goFaster = false;
card.active = false;
for (var i = 0; i < card.textData.length; i++) {
card.textData[i].pop();
}
}
}
}

export function onAction() {
card.active = true;
}

export function onTick() {
if (card.active && card.built) {
if (typeof card.tick === "undefined") {
card.tick = 1;
}
if (typeof card.waiterTick === "undefined") {
card.waiterTick = 1;
}

if (!card.goFaster){
card.tick++;
} else {
card.tick += 3;
}

drawDialogBox();
drawText();
} else if (!card.built) {
buildTextData();
}
}

export function onResetGame() {
card.active = false;
card.built = false;
card.endOfText = false;
card.goFaster = false;
card.pageNum = 0;
card.tick = 0;
card.waiterTick = 0;
card.textData = [];
}
Options
The dialog card has a few options available for you.

  • Key to talk - is the key to make the text appear faster on your screen (if this key is held down). This key is also the key to move from dialog 1 to dialog 2, and then to dialog 3, etc.
  • Dialog 1-5 - these are separate "chunks" of text you'd like the NPC to say.

Workshop link
Please go here if you'd like to look at the workshop link.

NEW - go here if you'd like to download the card.
2 Comments
Sandles  [author] 22 Sep, 2019 @ 10:17pm 
I'm glad you like it evyn!
elkaylk 22 Sep, 2019 @ 9:08pm 
thx!