CREATE YOUR WORLD
Players & Characters: Advanced
Bot Player Creation Guide
17min
bot players are used to fill in when there are not enough people to start a multiplayer world, or when a player leaves during a world how the bot player behaves needs to be implemented for each content this guide describes the general method of creating a bot player 📘 the bot player creation guide is based on the multiplayer guide \[ multiplay tutorial docid t5niungy1dinmcp5fka3 ] step 1 create a bot player 1 1 add a boolean value called isbot to the multiplayer schema 1 2 define the function below to create a bot player in the server script index ts and call it at the desired point index ts // the `createbot()` method is used to create a bot player with the given `userid` createbot(userid string) { // generate a session id for the bot player using the provided `userid` const sessionid = "bot " + userid; // check if a bot player with the same session id already exists if so, return without creating a duplicate if (this state players has(sessionid)) { return; } // create a new `player` object for the bot player const player player = new player(); player sessionid = sessionid; if (userid) { player zepetouserid = userid; } player isbot = true; // add the bot player to the state's players map using the session id as the key this state players set(player sessionid, player); this botmap set(sessionid, player); } 👍 tips the userid of a specific user is stored in advance for the bot player character to be created you can check the userid of a specific user by checking the userid of the client connecting to onjoin on the server after writing the script below in the server script, connect from the relevant world index ts onjoin(client sandboxplayer) { 	console log(client userid); } step 2 create a bot player on the client 2 1 if you have the server create a bot player at some point, the client will recognize it as a new player in onjoinplayer() create project > create > zepeto > typescript and rename it to botplayermanager add logic in onaddedplayer() to create each player, and add logic to distinguish bot players and create their zepeto characters botplayermanager ts import { zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { room } from 'zepeto multiplay'; import { zepetoscriptbehaviour } from 'zepeto script' import { zepetoworldmultiplay } from 'zepeto world'; export default class botplayermanager extends zepetoscriptbehaviour { public zepetoworldmultiplay zepetoworldmultiplay; // private variables to store the current room and bot player data private room room; private botmapdata map\<string, zepetocharacter> = new map\<string, zepetocharacter>(); start() { 		 	 // listen for the `roomjoined` event from the `zepetoworldmultiplay` component this zepetoworldmultiplay roomjoined += (room room) => { this room = room; } 	 // listen for the `onaddedplayer` event from `zepetoplayers instance` to handle newly added players zepetoplayers instance onaddedplayer addlistener((userid string) => { 	 // get the current player data from the room state using the `userid` const currentplayer = this room state players get item(userid); 	 // check if the player is a bot, and if so, set them as a bot player if (currentplayer isbot) { this setbotplayer(currentplayer sessionid); } }); } } 2 2 write the setbotplayer function to add tags and synchronization components to bot players and create scripts to control them set botmapdata to save bot player data in map format to manage bot players botplayermanager ts // the `setbotplayer()` method is used to set a player as a bot setbotplayer(userid string) { // get the zepeto character associated with the bot player using their `userid` const bot = zepetoplayers instance getplayer(userid) character; // set the name of the character to the `userid` for identification bot gameobject name = userid; // store the bot player's data in the ` botmapdata` map using their `userid` as the key 	 this botmapdata set(userid, bot); } 👍 tips you can add additional scripts or settings to setbotplayer() to control the behavior of bot players step 3 create a bot player button on the client for worlds that require a certain number of players to start, sometimes there are not enough players and you have to wait a long time for the world to start in this case, you can start the world by adding a bot player 3 1 register a function to execute createbot() when the server receives a message from the client in index ts async oncreate() { 	 // handle the "createbot" message, which creates a bot player with the given userid this onmessage("createbot", (client, message) => { this createbot(message); }); } 3 2 in the client script botplayermanager ts, write a function to send the "createbot" message to the server the way to execute a function is to send a message by pressing a button send the user id of the bot player to be created as a string through the message botplayermanager ts public buttoncreatebot button; public botplayerid string; start() {	 	 // add a click listener to the "create bot" button to send a message to create a bot player 	 this buttoncreatebot onclick addlistener(() => { this room send("createbot", this botplayerid); }); } 3 3 now, when you run the server and the runtime, you can see that bot players are created when you press the button step 4 start the world by adding a bot player when there are not enough players to start the world, you can add bot players to initiate the world 4 1 in the server script, add the following code during onjoin to check the number of players and start the world when there are at least four players add a function to check the number of players in createbot() add a counter for the number of plays in the startworld() function index ts async onjoin(client sandboxplayer) { // check the number of players in the room after a player joins 	this checkplayernumber(); } // the `checkplayernumber()` method checks the number of players in the room and starts the world if there are at least four players checkplayernumber() { 	// print the current number of players in the room to the console 	console log(`player number, ${this state players size}`); 	// if there are at least four players in the room, start the world 	if (this state players size >= 4) { this startworld(); 	} } // the `createbot()` method is used to create a bot player with the given `userid` createbot(userid string) { 	// generate a session id for the bot player using the provided `userid` 	const sessionid = "bot " + userid; 	// check if a bot player with the same session id already exists if so, return without creating a duplicate if (this state players has(sessionid)) { 	return; 	} 	// create a new `player` object for the bot player 	const player player = new player(); player sessionid = sessionid; 	if (userid) { 	 player zepetouserid = userid; 	} 	player isbot = true; 	// add the bot player to the state's players map using the session id as the key 	this state players set(player sessionid, player); 	this botmap set(sessionid, player); 	// check the number of players in the room after adding the bot player 	this checkplayernumber(); } private playtime number = 0; // the `startworld()` method increments the play time and broadcasts the "startworld" message to all clients startworld() { 	 this playtime += 1; // print a message indicating the start of the world and the current play time console log("start world!"); this broadcast("startworld", this playtime); } on the server, onjoin is executed when a real player joins the room so, when a bot player is created via createbot and when a player enters via onjoin, checkplayernumber() adds the number of people 4 2 in the client script, botplayermanager ts, write startworld(), which is executed when the message startworld is received from the server botplayermanager ts start() { 	// listen for the `roomjoined` event from the `zepetoworldmultiplay` component 	this zepetoworldmultiplay roomjoined += (room room) => { // add a message handler for the "startworld" message type 	this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); } // the `startworld()` method is called when the world starts with the provided `playtime` startworld(playtime number) { 	// print the world start message along with the `playtime` console log(`start world ${playtime}`); } 4 3 at runtime, when there are more than 4 players, including bot players, you can see a log called world start pops up on the server console and on the client's console step 5 synchronize bot player position below is sample code that moves the added bot players to the local player position and synchronizes the movement position 5 1 first, write the code to move the bot players when the message movebot is received from the client in index ts of the server async oncreate() { // handle the "movebot" message, which moves the bot player to the specified position 	this onmessage("movebot", (client, message) => { this movebot(client, message); }); } // the `movebot()` method moves the bot player to the specified position based on the received message movebot(client sandboxplayer, message string) { // parse the json message received from the client to extract the position information const position = json parse(message); // create a new message object with the user's session id and the parsed position data const newmessage = { user client sessionid, positionx position x, positiony position y, positionz position z } // broadcast the "movebottoposition" message to all clients with the new message data as a json string this broadcast("movebottoposition", json stringify(newmessage)); } 5 2 in the client script, botplayermanager ts, write sendbotposition() that sends the local player position to the server when buttoncallbot is pressed then write code to move all bot players to the location information included in the message when the message movebottoposition is received from the server botplayermanager ts public buttoncallbot button; start(){ 	// listen for the `roomjoined` event from the `zepetoworldmultiplay` component this zepetoworldmultiplay roomjoined += (room room) => { this room = room; // add a message handler for the "startworld" message type this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); 	// add a click listener to the "call bot" button to send a message to send a bot player position 	this buttoncallbot onclick addlistener(() => { 	 this sendbotposition(); 	}); } // this method sends the position of the local player's character to the server for bot movement synchronization sendbotposition() { // get the position of the local player's character const localplayerposition = zepetoplayers instance localplayer zepetoplayer character transform position; // create a position object containing the x, y, and z coordinates of the local player's character const position = { x localplayerposition x, y localplayerposition y, z localplayerposition z } // convert the position object to a json string and send it to the server with the "movebot" message type this room send("movebot", json stringify(position)); } movebottoposition(message) { // parse the json message received from the client to extract the position information const jsonmessage = json parse(message); const position = new vector3(jsonmessage positionx, jsonmessage positiony, jsonmessage positionz); // move each bot character in the ` botmapdata` map to the specified position with a small random offset on the x and z axes this botmapdata foreach((character zepetocharacter) => { // the `movetoposition()` method is used to move the character to the specified position // here, a small random offset is added to the target position to create a natural looking movement for the bots character movetoposition(position + new vector3(random range(0 5, 1), 0, random range(0 5, 1))); }); } 5 3 now if you create a bot player at runtime and press the buttoncallbot button you should see the created bot player move to the local player character position botplayermanager ts full code botplayermanager ts import { random, vector3 } from 'unityengine'; import { button } from 'unityengine ui'; import { zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { room } from 'zepeto multiplay'; import { zepetoscriptbehaviour } from 'zepeto script' import { zepetoworldmultiplay } from 'zepeto world'; export default class botplayermanager extends zepetoscriptbehaviour { // public properties to reference necessary components and settings from the inspector public zepetoworldmultiplay zepetoworldmultiplay; public buttoncreatebot button; public buttoncallbot button; public botplayerid string; // private variables to store the current room and bot player data private room room; private botmapdata map\<string, zepetocharacter> = new map\<string, zepetocharacter>(); start() { // listen for the `roomjoined` event from the `zepetoworldmultiplay` component this zepetoworldmultiplay roomjoined += (room room) => { this room = room; // add a message handler for the "startworld" message type this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); } // listen for the `onaddedplayer` event from `zepetoplayers instance` to handle newly added players zepetoplayers instance onaddedplayer addlistener((userid string) => { // get the current player data from the room state using the `userid` const currentplayer = this room state players get item(userid); // check if the player is a bot, and if so, set them as a bot player if (currentplayer isbot) { this setbotplayer(currentplayer sessionid); } }); // add a click listener to the "create bot" button to send a message to create a bot player this buttoncreatebot onclick addlistener(() => { this room send("createbot", this botplayerid); }); this zepetoworldmultiplay roomjoined += (room room) => { this room = room; this room addmessagehandler("movebottoposition", (message string) => { this movebottoposition(message); }); } // add a click listener to the "call bot" button to send a message to send a bot player position this buttoncallbot onclick addlistener(() => { this sendbotposition(); }); } // the `setbotplayer()` method is used to set a player as a bot setbotplayer(userid string) { // get the zepeto character associated with the bot player using their `userid` const bot = zepetoplayers instance getplayer(userid) character; // set the name of the character to the `userid` for identification bot gameobject name = userid; // store the bot player's data in the ` botmapdata` map using their `userid` as the key this botmapdata set(userid, bot); } // the `startworld()` method is called when the world starts with the provided `playtime` startworld(playtime number) { // print the world start message along with the `playtime` console log(`start world ${playtime}`); } // this method sends the position of the local player's character to the server for bot movement synchronization sendbotposition() { // get the position of the local player's character const localplayerposition = zepetoplayers instance localplayer zepetoplayer character transform position; // create a position object containing the x, y, and z coordinates of the local player's character const position = { x localplayerposition x, y localplayerposition y, z localplayerposition z } // convert the position object to a json string and send it to the server with the "movebot" message type this room send("movebot", json stringify(position)); } // this method is called when the server receives the "movebot" message from a client and moves the bot characters to the specified position movebottoposition(message) { // parse the json message received from the client to extract the position information const jsonmessage = json parse(message); const position = new vector3(jsonmessage positionx, jsonmessage positiony, jsonmessage positionz); // move each bot character in the ` botmapdata` map to the specified position with a small random offset on the x and z axes this botmapdata foreach((character zepetocharacter) => { // the `movetoposition()` method is used to move the character to the specified position // here, a small random offset is added to the target position to create a natural looking movement for the bots character movetoposition(position + new vector3(random range(0 5, 1), 0, random range(0 5, 1))); }); } } index ts server full code import { sandbox, sandboxoptions, sandboxplayer } from "zepeto multiplay"; import { datastorage } from "zepeto multiplay datastorage"; import { player, transform, vector3 } from "zepeto multiplay schema"; export default class extends sandbox { storagemap map\<string, datastorage> = new map\<string, datastorage>(); // save the bot player's map data as botmap private botmap map\<string, player> = new map\<string, player>(); private playtime number = 0; constructor() { super(); } oncreate(options sandboxoptions) { // called when the room object is created // handle the state or data initialization of the room object this onmessage("onchangedtransform", (client, message) => { this state players get(client sessionid); const player = this state players get(client sessionid); const transform = new transform(); transform position = new vector3(); transform position x = message position x; transform position y = message position y; transform position z = message position z; transform rotation = new vector3(); transform rotation x = message rotation x; transform rotation y = message rotation y; transform rotation z = message rotation z; if (player) { player transform = transform; } }); this onmessage("onchangedstate", (client, message) => { const player = this state players get(client sessionid); if (player) { player state = message state; player substate = message substate; } }); // handle the "createbot" message, which creates a bot player with the given userid this onmessage("createbot", (client, message) => { this createbot(message); }); // handle the "movebot" message, which moves the bot player to the specified position this onmessage("movebot", (client, message) => { this movebot(client, message); }); } // the `createbot()` method is used to create a bot player with the given `userid` createbot(userid string) { // generate a session id for the bot player using the provided `userid` const sessionid = "bot " + userid; // check if a bot player with the same session id already exists if so, return without creating a duplicate if (this state players has(sessionid)) { return; } // create a new `player` object for the bot player const player player = new player(); player sessionid = sessionid; if (userid) { player zepetouserid = userid; } player isbot = true; // add the bot player to the state's players map using the session id as the key this state players set(player sessionid, player); this botmap set(sessionid, player); // check the number of players in the room after adding the bot player this checkplayernumber(); } // the `checkplayernumber()` method checks the number of players in the room and starts the world if there are at least four players checkplayernumber() { // print the current number of players in the room to the console console log(`player number, ${this state players size}`); // if there are at least four players in the room, start the world if (this state players size >= 4) { this startworld(); } } // the `startworld()` method increments the play time and broadcasts the "startworld" message to all clients startworld() { this playtime += 1; // print a message indicating the start of the world and the current play time console log("start world!"); this broadcast("startworld", this playtime); } // the `movebot()` method moves the bot player to the specified position based on the received message movebot(client sandboxplayer, message string) { // parse the json message received from the client to extract the position information const position = json parse(message); // create a new message object with the user's session id and the parsed position data const newmessage = { user client sessionid, positionx position x, positiony position y, positionz position z } // broadcast the "movebottoposition" message to all clients with the new message data as a json string this broadcast("movebottoposition", json stringify(newmessage)); } async onjoin(client sandboxplayer) { // create the player object defined in schemas json and set the initial value console log(`\[onjoin] sessionid ${client sessionid}, hashcode ${client hashcode}, userid ${client userid}`) const player = new player(); player sessionid = client sessionid; if (client hashcode) { player zepetohash = client hashcode; } if (client userid) { player zepetouserid = client userid; } // \[datastorage] datastorage load of the entered player const storage datastorage = client loaddatastorage(); this storagemap set(client sessionid, storage); let visit cnt = await storage get("visitcount") as number; if (visit cnt == null) visit cnt = 0; console log(`\[onjoin] ${client sessionid}'s visiting count ${visit cnt}`) // \[datastorage] update player's visit count and then storage save await storage set("visitcount", ++visit cnt); // manage the player object using sessionid, a unique key value of the client object // the client can check the information about the player object added by set by adding the add onadd event to the players object this state players set(client sessionid, player); // check the number of players in the room after a player joins this checkplayernumber(); } ontick(deltatime number) void { // it is repeatedly called at each set time in the server, and a certain interval event can be managed using deltatime } async onleave(client sandboxplayer, consented? boolean) { // by setting allowreconnection, it is possible to maintain connection for the circuit, but clean up immediately in the basic guide // the client can check the information about the deleted player object by adding the add onremove event to the players object this state players delete(client sessionid); } }