CREATE YOUR WORLD
Players & Characters: Basic

ZEPETO Players

22min
zepetoplayers is a manager (singleton) class designed for controlling both the zepeto player and zepeto character by adding zepetoplayers to a scene, you can create, delete, and manipulate a zepeto player zepetoplayer represents an individual instance of a zepeto character used to manage both the player you control directly in a multiplayer world and other players every zepetoplayer created in a multiplayer world is assigned a unique session id and is managed using this session id because zepetoplayer possesses the attributes of zepetocharacter, it can be controlled using functions related to zepetocharacter there are three types of zepetoplayer zepetoplayer description local player represents a zepeto character instance directly controlled by the local user \ attached with character controller/zepeto camera components network player (remote player) a zepeto character instance that can be loaded and utilized in multiplay content \ does not have the character controller/zepeto camera components attached bot player a zepeto character instance for multiplay content, but controlled by a bot instead of a real user used as a substitute when starting a multiplayer world with insufficient players or if a player leaves during play \ does not have the character controller/zepeto camera components attached please refer to the following guide \[ zepeto players docid\ hkhdijsc keifucm88qjq ] \[ bot player creation guide docid iv7fms7tlgg02saugvk ] zepetocharacter is a basic instance unit of zepeto character that can be loaded and controlled in the world scene zepetocharacter possesses the appearance of an avatar created through the zepeto app please refer to the following guide \[ zepeto character docid 1sjftquomtcxfkg3tjh g ] adding zepetoplayers in the hierarchy window, select zepeto → zepetoplayers tab you can now add it to your scene note that just adding zepetoplayers doesn't bring the zepeto player into the scene you need to implement a script using the character creation api of zepetoplayers if you wish to quickly create and try out only the local player in a scene, refer to the guide please refer to the following guide \[ creating a zepeto character docid k4o tkiw83wg jhy0isa ] for a sample on how to display a zepeto player's name and profile picture, check out the guide please refer to the following guide \[ user information docid\ lyicyvjyqztqnkwbng2uu ] zepeto players api if you're interested in the zepetoplayers api, refer to the documentation please refer to the following guide \[ zepeto character controller api ] this guide primarily covers examples of using zepeto players in multiplayer scenarios implementing multiplay position synchronization using zepeto players in a single player world, only a local player needs to be created and since only the local player appears on the screen, synchronization is unnecessary however, in a multiplay world, not only the local player which you control directly but also other players, referred to as network players, need to be displayed on the screen every action of the network players moving, jumping, and performing specific gestures should appear identically on your screen this process is called synchronization without implementing the synchronization script, you won't be able to see the network player's appearance or movement in a multiplay world without synchronization, the only way to know if another client has entered the room is through the home button step 1 setting up the multiplay environment it's recommended to start by understanding the basic settings and concepts of multiplay through a multiplay tutorial video please refer to the following guide \[ multiplay tutorial docid t5niungy1dinmcp5fka3 ] \[ multiplay docid 2vrtjxdya 27bcwdacza ] step 2 displaying other players on your screen your local player is treated as a network player on someone else's device this means that even your local player must send information to the server for synchronization all players connected to the multiplay world should share their information all clients connected to the multiplay room share the multiplay room state data this room state data follows the schema defined in schemas json (please consider schema as a data structure) in this guide, you will synchronize the player's position through the room state data thus, define a schema in schemas json that can represent the position data for each player schema json { "state" {"players" {"map" "player"}}, "player" {"sessionid" "string","zepetouserid" "string","transform" "transform","state" "number","substate" "number"}, "transform" {"position" "vector3","rotation" "vector3"}, "vector3" {"x" "number","y" "number","z" "number"} } please refer to the following guide \[ multiplay room state docid\ b8pz8w6damhkjm8rl lsp ] 👍 tips store all the information that servers and all clients should share in the multiplay room state save individual data for each player, such as levels, experience points, scores, etc , using datastorage the server script can recognize when another player has entered the room and can send that information to the client to load that player into the scene step 2 1 basic server script when a player enters the multiplay world's room, onjoin() is called in the server script, add the information of the connected player to the room state's players also, when a player exits the room, onleave() is called the server script will remove the information of the player who left from the room state's players import {sandbox, sandboxoptions, sandboxplayer} from "zepeto multiplay"; import {player} from "zepeto multiplay schema"; export default class extends sandbox { oncreate(options sandboxoptions) { } async onjoin(client sandboxplayer) { const player = new player(); player sessionid = client sessionid; if (client userid) { player zepetouserid = client userid; } // 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); } async onleave(client sandboxplayer, consented? boolean) { this state players delete(client sessionid); } } step 2 2 basic client script when creating a multiplay world, a client script is needed to communicate with the server below is an example of a fundamental client script for multiplayer play on the client side, we manage the player data to be displayed in our client using the currentplayers map data structure the pivotal line of code is illustrated below zepetoplayers instance createplayerwithuserid(sessionid, player zepetouserid, spawninfo, islocal); when the client receives player information from the server's room state and a new player joins the room, a session id is assigned if the session id of the player being created matches our own session id, the player is considered local in this case, the player will be instantiated with islocal = true , indicating that it's the local player subsequently, players who aren't local are created with islocal = false this ensures that the appearances of all players, both local and non local, are rendered on the screen import {zepetoscriptbehaviour} from 'zepeto script' import {zepetoworldmultiplay} from 'zepeto world' import {room, roomdata} from 'zepeto multiplay' import {player, state, vector3} from 'zepeto multiplay schema' import {characterstate, spawninfo, zepetoplayers, zepetoplayer, characterjumpstate} from 'zepeto character controller' import as unityengine from "unityengine"; export default class multiplayclientcode extends zepetoscriptbehaviour { public multiplay zepetoworldmultiplay; private room room; private currentplayers map\<string, player> = new map\<string, player>(); private zepetoplayer zepetoplayer; private start() { this multiplay roomcreated += (room room) => { this room = room; }; this multiplay roomjoined += (room room) => { room onstatechange += this onstatechange; }; } private onstatechange(state state, isfirst boolean) { // when the first onstatechange event is received, a full state snapshot is recorded if (isfirst) { // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedlocalplayer addlistener(() => { const myplayer = zepetoplayers instance localplayer zepetoplayer; this zepetoplayer = myplayer; }); // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedplayer addlistener((sessionid string) => { const islocal = this room sessionid === sessionid; if (!islocal) { const player player = this currentplayers get(sessionid); } }); } let join = new map\<string, player>(); let leave = new map\<string, player>(this currentplayers); state players foreach((sessionid string, player player) => { if (!this currentplayers has(sessionid)) { join set(sessionid, player); } leave delete(sessionid); }); // \[roomstate] create a player instance for players that enter the room join foreach((player player, sessionid string) => this onjoinplayer(sessionid, player)); // \[roomstate] remove the player instance for players that exit the room leave foreach((player player, sessionid string) => this onleaveplayer(sessionid, player)); } private onjoinplayer(sessionid string, player player) { console log(`\[onjoinplayer] players sessionid ${sessionid}`); this currentplayers set(sessionid, player); // create player const islocal = this room sessionid === player sessionid; zepetoplayers instance createplayerwithuserid(sessionid, player zepetouserid, new spawninfo(), islocal); } private onleaveplayer(sessionid string, player player) { console log(`\[onremove] players sessionid ${sessionid}`); this currentplayers delete(sessionid); zepetoplayers instance removeplayer(sessionid); } } now, when a player enters, you can confirm that the zepeto character is created on your screen but, the movement of the player isn't yet reflected on the screen let's move on to synchronizing the position next step 3 synchronizing by fetching other player's information for synchronization, every time a player moves or takes some action, they must send their status change to the server sending a message containing their status change to the server is done through room message communication when the server receives a message about a player's status change, it updates the room state please refer to the following guide \[ multiplay room message docid\ a04weva7 xyk k al0kzk ] for instance, let's consider that your local player is named b when a network player a joins the room, they are instantiated at the coordinates x 0, y 0, z 0 if player a moves to the position x 10, y 0, z 0, b has no actual way of knowing that a is moving this is because both are being operated locally on separate devices, hence on separate clients thus, the person controlling a needs to communicate their movement to the server via a room message once the server receives this information, it informs everyone present in the room about a's real time position this way, b is finally aware that a is moving for the server to notify other players, there are two methods using room message broadcast updating the room state, then having clients fetch and apply the room state this guide utilizes the second method of updating the room state given that a zepeto player loaded into the scene possesses zepeto character attributes, you can employ zepeto character functions to command movements to specific locations or initiate jumps for b's client to visualize a's movement to x 10, y 0, z 0, the most intuitive approach is to use movetoposition() this function will move the player to a's most recent position as received from the server not just position changes, but gestures, skill usage, item collection, and all state changes necessitate server client communication for synchronization you'll need to implement synchronization to keep every action in harmony across the network 👍 synchronization concept summary when a local player has a status change, they send it to the server using room message the server notifies all other players except the local player about the status change upon receiving the status change message, the client code updates the status of the player who sent the message step 3 1 server script with completed position synchronization in the basic server script, additional implementation is needed to update the room state every time a message about a status change from the local player's client is received import {sandbox, sandboxoptions, sandboxplayer} from "zepeto multiplay"; import {player, transform, vector3} from "zepeto multiplay schema"; export default class extends sandbox { 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) => { 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; // character controller v2 } }); } async onjoin(client sandboxplayer) { // create the player object defined in schemas json and set the initial value console log(`\[onjoin] sessionid ${client sessionid}, userid ${client userid}`) const player = new player(); player sessionid = client sessionid; if (client userid) { player zepetouserid = client userid; } // 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); } 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); } } step 3 2 client script with completed position synchronization key implementations in the basic client script are automatically call onstatechange when the server's room state changes using the sendmessageloop(0 04) function, send the local player's position and character jump status information to the server every 0 04 seconds import {zepetoscriptbehaviour} from 'zepeto script' import {zepetoworldmultiplay} from 'zepeto world' import {room, roomdata} from 'zepeto multiplay' import {player, state, vector3} from 'zepeto multiplay schema' import {characterstate, spawninfo, zepetoplayers, zepetoplayer, characterjumpstate} from 'zepeto character controller' import as unityengine from "unityengine"; export default class clientstarterv2 extends zepetoscriptbehaviour { public multiplay zepetoworldmultiplay; private room room; private currentplayers map\<string, player> = new map\<string, player>(); private zepetoplayer zepetoplayer; private start() { this multiplay roomcreated += (room room) => { this room = room; }; this multiplay roomjoined += (room room) => { room onstatechange += this onstatechange; }; this startcoroutine(this sendmessageloop(0 04)); } // send the local character transform to the server at the scheduled interval time private sendmessageloop(tick number) { while (true) { yield new unityengine waitforseconds(tick); if (this room != null && this room isconnected) { const hasplayer = zepetoplayers instance hasplayer(this room sessionid); if (hasplayer) { const character = zepetoplayers instance getplayer(this room sessionid) character; this sendtransform(character transform); this sendstate(character currentstate); } } } } private onstatechange(state state, isfirst boolean) { // when the first onstatechange event is received, a full state snapshot is recorded if (isfirst) { // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedlocalplayer addlistener(() => { const myplayer = zepetoplayers instance localplayer zepetoplayer; this zepetoplayer = myplayer; }); // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedplayer addlistener((sessionid string) => { const islocal = this room sessionid === sessionid; if (!islocal) { const player player = this currentplayers get(sessionid); // \[roomstate] called whenever the state of the player instance is updated player onchange += (changevalues) => this onupdateplayer(sessionid, player); } }); } let join = new map\<string, player>(); let leave = new map\<string, player>(this currentplayers); state players foreach((sessionid string, player player) => { if (!this currentplayers has(sessionid)) { join set(sessionid, player); } leave delete(sessionid); }); // \[roomstate] create a player instance for players that enter the room join foreach((player player, sessionid string) => this onjoinplayer(sessionid, player)); // \[roomstate] remove the player instance for players that exit the room leave foreach((player player, sessionid string) => this onleaveplayer(sessionid, player)); } private onjoinplayer(sessionid string, player player) { console log(`\[onjoinplayer] players sessionid ${sessionid}`); this currentplayers set(sessionid, player); const spawninfo = new spawninfo(); const position = this parsevector3(player transform position); const rotation = this parsevector3(player transform rotation); spawninfo position = position; spawninfo rotation = unityengine quaternion euler(rotation); const islocal = this room sessionid === player sessionid; zepetoplayers instance createplayerwithuserid(sessionid, player zepetouserid, spawninfo, islocal); } private onleaveplayer(sessionid string, player player) { console log(`\[onremove] players sessionid ${sessionid}`); this currentplayers delete(sessionid); zepetoplayers instance removeplayer(sessionid); } private onupdateplayer(sessionid string, player player) { const position = this parsevector3(player transform position); const zepetoplayer = zepetoplayers instance getplayer(sessionid); var movedir = unityengine vector3 op subtraction(position, zepetoplayer character transform position); movedir = new unityengine vector3(movedir x, 0, movedir z); if (movedir magnitude < 0 05) { if (player state === characterstate moveturn) return; zepetoplayer character stopmoving(); } else { zepetoplayer character movecontinuously(movedir); } if (player state === characterstate jump) { if (zepetoplayer character currentstate !== characterstate jump) { zepetoplayer character jump(); } if (player substate === characterjumpstate jumpdouble) { zepetoplayer character doublejump(); } } } private sendtransform(transform unityengine transform) { const data = new roomdata(); const pos = new roomdata(); pos add("x", transform localposition x); pos add("y", transform localposition y); pos add("z", transform localposition z); data add("position", pos getobject()); const rot = new roomdata(); rot add("x", transform localeulerangles x); rot add("y", transform localeulerangles y); rot add("z", transform localeulerangles z); data add("rotation", rot getobject()); this room send("onchangedtransform", data getobject()); } private sendstate(state characterstate) { const data = new roomdata(); data add("state", state); if(state === characterstate jump) { data add("substate", this zepetoplayer character motionv2 currentjumpstate); } this room send("onchangedstate", data getobject()); } private parsevector3(vector3 vector3) unityengine vector3 { return new unityengine vector3 ( vector3 x, vector3 y, vector3 z ); } } 👍 tips this guide only implements position synchronization gesture synchronization, object synchronization, etc , haven't been implemented the principle is the same for all, but the process of sending and receiving room messages at every required moment is necessary if you want to implement synchronization more conveniently, consider using a multiplay synchronization module