[SOLVED] Multiplayer animation with PlayCanvas and Photon

@Tirk182 I sort of understand what is going on but not fully.
For the animations, we were using an animstategraph and a script attached to the player model to activate the scripts but if we do that we get the error I first mentioned. The enemy shows the current players animation instead of the action that the enemy is carrying out.

What do you mean by passing a state number in game-room.js?
If you take a look at the current state, I have two animations, for the enemy model, which I want it to show it to current player. I could declare them both in an animstategraph, and a script with it, but I don’t understand how it translates over to current player.

In your code you say

player.set // activate state playerAnim

What do you mean by this? How do you access the animation and set it without like referencing the animstategraph?

@Alexis_Shaju I see several ways you handle animation state changes in your code. This was just a placeholder to show you where to set it. You can use one of your methods.

this.entity.anim.setBoolean('jump', true);

this.entity.anim.setBoolean('run', false);

Or you could execute them like this with some changes.

this.entity.anim.baseLayer.play(animation**);

Keep in mind that the instantiated player in the room handled by game-room.js are referenced by player.anim.setBoolean. Because of this const player = this.entity.findByName(actorNr);

1 Like

@Tirk182 This is what I am wondering.
I have the methods I want defined in a script.

this.entity.anim.setBoolean('jump', true);
this.entity.anim.setBoolean('run', false);

For example this is already written in one of the scripts. To what entity do I attach this script to then?
And do I attach this through game-room.js or how does it work?

You need to use this inside of your game-room.js like player.setPosition below.

@Tirk182 So do I add a script component to the player, which is the script I have with the setting to true and false of the animations, through the game-room.js, and add the animstategraph to the enemy template?

@Tirk182
There is one script I found regarding these animations, but the person uses socket.io instead of photon.

var PlayerAnimationHandler = pc.createScript('playerAnimationHandler');

PlayerAnimationHandler.attributes.add('blendTime', { type: 'number', default: 0.2 });

PlayerAnimationHandler.attributes.add('playerEntity', { type: 'entity' });



PlayerAnimationHandler.prototype.initialize = function () {
    
  this.temp=null;
    
    var app = this.app;
   
    
    app.keyboard.on(pc.EVENT_KEYDOWN, this.keyChange, this);
    app.keyboard.on(pc.EVENT_KEYUP, this.keyChange, this);

    this.direction = 'Idle';
    this.setDirection('Idle');
};

PlayerAnimationHandler.prototype.checkButtons = function () {
    var app = this.app;
    
    var w = app.keyboard.isPressed(pc.KEY_W);
    var a = app.keyboard.isPressed(pc.KEY_A);
    var s = app.keyboard.isPressed(pc.KEY_S);
    var d = app.keyboard.isPressed(pc.KEY_D);

    if (w && !s) {
        if (a && !d) {
            this.direction = 'Run Forward Left';
        } else if (d && !a) {
            this.direction = 'Run Forward Right';
        } else {
            this.direction = 'Run Forward';
        }
    } else if (s && !w) {
        if (a && !d) {
            this.direction = 'Run Backward Left';
        } else if (d && !a) {
            this.direction = 'Run Backward Right';
        } else {
            this.direction = 'Run Backward';
        }
    } else if (a && !d) {
        this.direction = 'Run Left';
    } else if (d && !a) {
        this.direction = 'Run Right';
    } else {
        this.direction = 'Idle';
    }
   
    
};

PlayerAnimationHandler.prototype.keyChange = function (e) {
  //  console.log("Pressed");
    if(this.playerEntity.script.playerManager.isControlling!=undefined)
        {
            if(this.playerEntity.script.playerManager.isControlling)
    {
       this. tempDirection = this.direction;

         this.checkButtons();
 this.playerEntity.script.playerManager.direction= this.direction;
     if (this.tempDirection !== this.direction) {
             this.setDirection(this.direction);
         }
    }
  
        }
    
  
};
PlayerAnimationHandler.prototype.update = function (dt) {
    
 if(this.playerEntity.script.playerManager.isControlling)
    {// console.log(this.playerEntity.script.playerManager);
    }
    else{
     // console.log(this.playerEntity.script.playerManager);
             this.direction=this.playerEntity.script.playerManager.Otherdirection;
            
            if (this.temp !== this.direction) {
               this. temp= this.direction;
            this.setDirection(this.direction);
         }
    
    }
    
    
};

PlayerAnimationHandler.prototype.setDirection = function (direction) {
    this.direction = direction;
    this.entity.animation.play(direction, this.blendTime);
    
};

Here is the script. But I don’t understand how he uses direction and setDirection and sets the animation using this.

@Alexis_Shaju Here is my latest game-room function.

GameRoom.prototype.updatePlayerPosition = function (content, actorNr) {

    const { x, y, z } = content.position;
    const playerData = content.player;
    const player = this.entity.findByName(actorNr);
    const playerMat = this.app.assets.find(playerData.playerMat);

    // Display Actor
    this.playerName = player.findByName('State').element;
    this.playerName.text = playerData.name;

    // Map Color material
    player.render.material = playerMat.resource;

    // Set the position
    player.setPosition(x, y, z);

};

From what I described in my description above this is what is happening here. This script is called every time a remote player is moving and updates their position. All this is handled by the Photon networking and you get passed content along with the actor number. Most important is that one of the things you get passed to you in the function is the remote actors position in all three axis.

In the gaming screen you will have to keep track of in your mind is that x and z translate to the horizontal axis. i.e. your player will go back, forward, left, and right based on these two variables alone.

So if x or z are changing every update your remote player is running or walking. If you detect this in the update then you must play the player.anim.setBoolean(‘run’, true); or set to false if not moving.

y directly relates to vertical movement. i.e. your remote player just jumped. player.anim.setBoolean(‘jump’, true); or false if not.

Other thing I noticed is that your player is a pistol and not actually a character.
image

You are going to want to put the player template in here. Also your player template should include your anim state graph etc. Hope this helps

I think this information helps, I will try it out asap. The Pistol Idle is just the name that the model ended up with when I downloaded it from mixamo with the idle animation.

I have created an animstategraph for the enemy model template which is attached to the game-room.js file and attached it to this model.

What is the best way to detect change in player position?

I see it is first gotten by content.player.

Would something like:

if(x)//then do something

be sufficient to set the animation for when X value changes?

This is a quick answer but I think this should give you more information.

Wouldn’t it be easier to send the correct animation from the other player and just apply this animation?

1 Like

@Albertos Yes this also could be another route. This attribute could be broadcast from player.js script and added to the data structure passed.

1 Like

I’m still having difficulty with this.
If I try something like this, I get an error.

const { x, y, z } = content.position;
    const player = this.entity.findByName(actorNr);

    let curPosition = player.getPosition().clone();

    if(content.position != curPosition){
        if(content.position.x != curPosition.x){
            this.player.anim.setBoolean('walk', true);
        } else{
            this.player.anim.setBoolean("walk", false);
        }
    }

    player.setPosition(x, y, z);

I can’t set the boolean of player, it gives me an error.
Do I need to add an anim component to player in this game-room.js or what is the best way.

“Yes this also could be another route. This attribute could be broadcast from player.js script and added to the data structure passed.”
Would this be the easier method? If so how would I go about it?

Yes, you try to set a boolean of the anim component so you have to make sure this exist.

You send the animation like you send for example the new position and then you apply this animation.

How would I send the animation like I am sending position, what would the code look like?

Is it applied then in game-room so it is broadcasted to all players?

There a different ways to do this. You can send for example an integer like 1 and 2, where 1 is your idle animation and 2 is your move animation. I didn’t do this myself before, so you have to find out the exact way yourself.

Another option is to apply the animation without transitions. Then you can do something like my post below.

1 Like

How would I set the animation to an integer. What is the code you use to declare that. My animations are now in glb format and not json.

I suggest to try my last option first, because this is easier to achieve.

@Albertos Is this the suggestion? I can try to show the Photon version.