제페토 월드 만들기 (회전 동기화)

Zepeto 2022. 4. 11. 17:20
반응형

 

 

 

 

이동중 회전하기

 

 

 

 

https://github.com/smilejsu82/ZepetoMultiTest

 

GitHub - smilejsu82/ZepetoMultiTest: ZepetoMultiTest

ZepetoMultiTest. Contribute to smilejsu82/ZepetoMultiTest development by creating an account on GitHub.

github.com

 

 

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} from 'ZEPETO.Character.Controller'
import * as UnityEngine from "UnityEngine";
import PlayerController from './PlayerController'
import res_OnLookAtTarget from './res_OnLookAtTarget'

export default class Starter extends ZepetoScriptBehaviour {

    public multiplay: ZepetoWorldMultiplay;

    private room: Room;
    private currentPlayers: Map<string, Player> = new Map<string, Player>();

    private Start() {

        this.multiplay.RoomCreated += (room: Room) => {
            this.room = room;
            
            this.room.AddMessageHandler('onLookAtTarget', (message)=>{

                var res = message as res_OnLookAtTarget;

                var fromId : string = res.fromId;
                var toId : string = res.toId;

                console.log(fromId, toId);

            });


        };

        this.multiplay.RoomJoined += (room: Room) => {
            room.OnStateChange += this.OnStateChange;
        };

        this.StartCoroutine(this.SendMessageLoop(0.1));
    }

    // 일정 Interval Time으로 내(local)캐릭터 transform을 server로 전송합니다.
    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 myPlayer = ZepetoPlayers.instance.GetPlayer(this.room.SessionId);
                    if (myPlayer.character.CurrentState != CharacterState.Idle)
                    {
                        this.SendTransform(myPlayer.character.transform);

                        //this.SendLookAt(fromId, toId);
                    }
                        
                }
            }
        }
    }

    private localZepetoPlayer : ZepetoPlayer;

    private OnStateChange(state: State, isFirst: boolean) {

        // 첫 OnStateChange 이벤트 수신 시, State 전체 스냅샷을 수신합니다.
        if (isFirst) {

            // [CharacterController] (Local)Player 인스턴스가 Scene에 완전히 로드되었을 때 호출
            ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
                this.localZepetoPlayer = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer;

                var playerController = this.localZepetoPlayer.character.gameObject.AddComponent<PlayerController>();
                playerController.Init(this.room.SessionId, this.room);

                playerController.findTargetAction = (fromId, toId)=>{

                    ZepetoPlayers.instance.GetPlayer(fromId).character.gameObject.GetComponent<PlayerController>().SetTarget(toId);

                };

                this.localZepetoPlayer.character.OnChangedState.AddListener((cur, prev) => {
                    this.SendState(cur);
                });
            });

            // [CharacterController] Player 인스턴스가 Scene에 완전히 로드되었을 때 호출
            ZepetoPlayers.instance.OnAddedPlayer.AddListener((sessionId: string) => {
                const isLocal = this.room.SessionId === sessionId;
                if (!isLocal) {
                    const player: Player = this.currentPlayers.get(sessionId);
                    
                    var zepetoPlayer = ZepetoPlayers.instance.GetPlayer(sessionId);
                    var playerController = zepetoPlayer.character.gameObject.AddComponent<PlayerController>();
                    playerController.Init(sessionId, null);

                    playerController.findTargetAction = (fromId, toId)=>{


                        ZepetoPlayers.instance.GetPlayer(fromId).character.gameObject.GetComponent<PlayerController>().SetTarget(toId);

                        // ZepetoPlayers.instance.GetPlayer(fromId).character.transform.LookAt(
                        //     ZepetoPlayers.instance.GetPlayer(toId).character.transform
                        // );
                    };

                    // [RoomState] player 인스턴스의 state가 갱신될 때마다 호출됩니다.
                    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] Room에 입장한 player 인스턴스 생성
        join.forEach((player: Player, sessionId: string) => this.OnJoinPlayer(sessionId, player));

        // [RoomState] Room에서 퇴장한 player 인스턴스 제거
        leave.forEach((player: Player, sessionId: string) => this.OnLeavePlayer(sessionId, player));
    }

    private * WaitForLoadLocalPlayer(callback){
        while(true){
            if(this.localZepetoPlayer){
                break;
            }
            yield null;
        }
        callback();
    }

    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) {

        console.log('OnUpdatePlayer');

        const position = this.ParseVector3(player.transform.position);

        const zepetoPlayer = ZepetoPlayers.instance.GetPlayer(sessionId);
        zepetoPlayer.character.MoveToPosition(position);

        if (player.state === CharacterState.JumpIdle || player.state === CharacterState.JumpMove)
            zepetoPlayer.character.Jump();
    }

    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 SendLookAt(fromId:string, toId:string){
        const data = new RoomData();
        data.Add("fromId", fromId);
        data.Add("toId", toId);
        this.room.Send("onLookAtTarget", data.GetObject());
    }

    private SendState(state: CharacterState) {
        const data = new RoomData();
        data.Add("state", state);
        this.room.Send("onChangedState", data.GetObject());
    }

    private ParseVector3(vector3: Vector3): UnityEngine.Vector3 {
        return new UnityEngine.Vector3
        (
            vector3.x,
            vector3.y,
            vector3.z
        );
    }
}
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import {Room, RoomData} from 'ZEPETO.Multiplay'
import { CharacterController, GameObject, Physics, Vector3, LayerMask } from 'UnityEngine';
import { ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Action$2 } from 'System'

export default class PlayerController extends ZepetoScriptBehaviour {

    private room : Room;
    private sessionId: string;

    private targetSessionId : string;
    private targetGo : GameObject;

    private center : Vector3;

    public findTargetAction :  Action$2<string, string>;


    public Init(sessionId: string, room : Room){
        
        this.sessionId = sessionId;
        this.room = room;

        this.center = this.GetComponent<CharacterController>().bounds.center;

        this.gameObject.layer = LayerMask.NameToLayer("Player");
    }

    public IsLocal(){
        return this.room != null;
    }

    public GetSetssionId()
    {
        return this.sessionId;
    }

    public SetTarget(targetSessionId : string){
        this.targetSessionId = targetSessionId;
        var targetZepetoPlayer = ZepetoPlayers.instance.GetPlayer(this.targetSessionId);
        this.targetGo = targetZepetoPlayer.character.gameObject;
    }

    Update(){
        
        var colliders = Physics.OverlapSphere(this.center, 3.0, 1 << 21);
        
        for(var i = 0; i<colliders.length; i++){
            if( colliders[i]!= null && colliders[i].gameObject != this.gameObject){

                this.findTargetAction(this.sessionId, colliders[i].gameObject.GetComponent<PlayerController>().GetSetssionId());

                break;
            }
        }
    }

    LateUpdate(){
        if(this.targetGo){
            this.transform.LookAt(this.targetGo.transform);
        }
    }

}
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'

export default class res_OnLookAtTarget{
    public sessionId : string;
    public fromId : string;
    public toId : string;
}
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>();
    
    constructor() {
        super();
    }

    onCreate(options: SandboxOptions) {

        // Room 객체가 생성될 때 호출됩니다.
        // Room 객체의 상태나 데이터 초기화를 처리 한다.

        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;

            player.transform = transform;
        });

        this.onMessage("onLookAtTarget", (client, message) => {
            //const player = this.state.players.get(client.sessionId);
            //player.state = message.state;
            var res = {
                sessionId : client.sessionId,
                fromId : message.fromId,
                toId : message.toId
            };

            this.broadcast('onLookAtTarget', res);
            
        });

        this.onMessage("onChangedState", (client, message) => {
            const player = this.state.players.get(client.sessionId);
            player.state = message.state;
        });
    }
    
   
    
    async onJoin(client: SandboxPlayer) {

        // schemas.json 에서 정의한 player 객체를 생성 후 초기값 설정.
        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] 입장한 Player의 DataStorage Load
        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] Player의 방문 횟수를 갱신한다음 Storage Save
        await storage.set("VisitCount", ++visit_cnt);

        // client 객체의 고유 키값인 sessionId 를 사용해서 Player 객체를 관리.
        // set 으로 추가된 player 객체에 대한 정보를 클라이언트에서는 players 객체에 add_OnAdd 이벤트를 추가하여 확인 할 수 있음.
        this.state.players.set(client.sessionId, player);
    }

    onTick(deltaTime: number): void {
        //  서버에서 설정된 타임마다 반복적으로 호출되며 deltaTime 을 이용하여 일정한 interval 이벤트를 관리할 수 있음.
    }

    async onLeave(client: SandboxPlayer, consented?: boolean) {

        // allowReconnection 설정을 통해 순단에 대한 connection 유지 처리등을 할 수 있으나 기본 가이드에서는 즉시 정리.
        // delete 된 player 객체에 대한 정보를 클라이언트에서는 players 객체에 add_OnRemove 이벤트를 추가하여 확인 할 수 있음.
        this.state.players.delete(client.sessionId);
    }
}

반응형

'Zepeto' 카테고리의 다른 글

제페토 월드 모바일 접속 안될때 방화벽 해제  (0) 2022.04.14
유니티로 만드는 제페토 월드 (회전 동기화)  (0) 2022.04.13
찰칵  (0) 2022.03.31
Zombie.ts  (0) 2022.03.31
zepeto world orientation horizontal  (0) 2022.03.25
: