RESOLVED - Difficulty with calling functions on peers in Coop fighting game

I’ve been playing around with making my own coop game fighting game.
I have 2 players in the game, when one of the players grabs the second player I need the player who is being grabbed to call an animation, however I cannot get this to work.
I’ve been trying to use @rpc to call a function on the peer which will change the animation but it isn’t working.

To test the basics, in my rpc function I am only printing out the owner_id so I can see which peer is being called, but so far it’s only printing out the server id, that is player 1. So the player who is performing the grapple is being called, not the player who is actually being grappled

Any advice? Thanks in advance

Hi Stephen,

As this is beyond the course a bit my help will be fairly limited but i will try my best to help.
If you can post the code you are using it might help to figure out why its only printing the host id rather than the player being grabbed.

Thanks

1 Like

Thanks very much, Marc.
Apologies the block code hasn’t worked properly, maybe because of the @?

I have 2 players. They each have an Area2d on them.
When one player walks into the other, the below code is run.
What I can see happening is that only the host is running the code that prints “My ID with rpc” Because it’s printing 1 instead of 1006263358. I can see what the code is doing, printing the Host’s Id out in both instances of the game. I just don’t know enough to get it to run code only for the peer who is being grappled.

What I’d like to be able to do is get the second player to print their id, which is 1006263358.
If I can do that I should be able to call the grapple code on the second player (because I need them to play an animation when they are being grappled)

For grappling

func _on_body_area_2d_area_entered(area):

# Players should only run their own grapple code
if owner_id != multiplayer.get_unique_id(): 
	return	
	
var me = global_position.y
var target = area.global_position.y
var result = abs(me-target)

if area.name == "PlayerBodyArea2D" && result <= reachDistance:
	if velocity.x != 0:
		enemy_being_grappled = area.get_parent().get_parent()
		#
		isGrappling = true
		velocity = Vector2(0,0)
		print("My ID " + str(owner_id) + " is grappling player " + str(enemy_being_grappled.owner_id))
		print_id.rpc()

@rpc(“call_local”, “authority”, “reliable”)
func print_id():
print("My ID with rpc " + str(owner_id))

And the output is
image

Hi Stephen,

Apologies its taken a few days to get back to you as i had some time away due to school holidays starting.
I’ve spoken to Nathan and he has said that its possible that the owner_id is not being set correctly or something like that so can you print the owner_id when it initially calls the area_entered function and see if the owner_id is correct there.

Thanks for your patience.

1 Like

Thanks for your reply, don’t worry about the time.

I’ve added the print statement to the top of the function, directly below the return statement, so it only gets printed once for each user. If I don’t use it the statement gets printed twice. I’m still trying to get my head around how this works.
image

This is the outcome
image

I’ve passed this onto Nathan as it appears it is printing the host (1) and the client (long number) outside of the area.name if statement which is correct as it should only be printed once.
I am not sure when inside that later if statement it is calling the host id twice however so hoping that Nathan can shed some light on it.

It is a bit beyond the scope of the course but i would like to stick with it to see if i can find a solution as its a nice alternative to using a triple jump and throw player to get the mechanic instead.

1 Like

Thanks for your help.

Haha yes that’s almost what I’m trying to do, grapple the player and then throw them, but more in a Streets of Rage style.

So if I, as the person who grappled the peer, call enemy_being_grappled.queue_free() then the peer is correctly removed from the game. However, if I, as the person who grappled the peer, try to call any functions on the peer then they just get ignored.

At least I know it is the correct enemy, but something in Godot is preventing the server calling functions or changing any values on the connecting peer. The functions don’t have an if owner_id != multiplayer.get_unique_id(): in them, so maybe it’s just something inbuilt to Godot that’s preventing it.

I’ll keep trying and report back if I work it out.

Thanks again.

I’ve tried a different tactic with this, but still no luck.
I’ve got a variable “is_grappled” And when the host grabs the other player, it sets is_grappled to true on that player (only on the host machine) I’ve set is_grappled_ to sync on change in the MultiplayerSynchroniser for the players, however it is not syncing across to the peer.

I’ve been doing a bit of research into this and found a not entirely helpful video but it may give us a thread to pull on using a statemachine.
It is probably a bit overkill for what you need but the code used may give you some ideas on how to achieve this.

I also had a chat with our production manager and mention the transfer of ownership of the player object to prevent movement when grabbed and transfer it back once released much like the block we use in the game

Anyways here is the link so hope it gives some direction

1 Like

Thanks for your help.
Unfortunately that video does not help in this case.
The idea for the statemachine is fine, and I do use one, but the problem is getting player 1 to affect values on player 2, and it doesn’t seem possible.
The function is_multiplayer_authority() seems to only be callable on a node with no arguments, so it can be called on the pushable object which isn’t a player. I don’t know how I can call that on a player node (player 2) by player 1. Since both players will be the authority of their own node.
I don’t know how to check if I have authority of a particular node on a given game instance.

I might just need to code it so that player 2 can set their own values when they are grappled, rather than player 1 telling them that they have been grappled.
That just leaves player 1 to decide accurately when they are grappling or when they are being grappled. Which is easily done if one player walks into another, but what if they walk into each other? How can they decided? That’s why I wanted Player 1 to decide all of that and then inform player 2 of the result.

I’ll keep at it and report back if I find a solution.

The only thing i can really add to this is that in most games a button push activates the grapple so that could be a solution around something on WHO pressed the button to grapple to dictate who is grappled and who is doing the grappling.

At least that is the way i see it

1 Like

Thanks, yes thats one solution.
I did have another idea that I’ve not tried yet.
Have an object in the level that, when both players collide, they can query and that object can decide who grappled first. The values of the object should be able to sync between the 2 players, and that way player 1 doesn’t have to directly influence any values on player 2.

I can see why I can’t do it directly, it must be a security thing, not lettering a player directly influence another, I just thought there would be an easier way.

Thanks for your help. I’ll let you know what solution I end up with.

I’ve managed to do it. And it was all my own dumb fault from the start.

In the grapple code I was checking if velocity.x != 0. This way I could tell which player was walking and which was stationary, so the walking player would initiate the grapple.
The problem with this was, and it took me so long to realise it as I’m still getting used to multiplayer, is that on Player2s machine, his velocity does change when walking, so it will not be 0 and so he can grapple. However, the players POSITION is what gets synced with MultiplayerSynchroniser, and so on Player1’s machine P2s velocity is ALWAYS 0, and so the code never gets ran there.

I got around this by checking what animation the player is in, rather than the velocity, as the animation is already being synced. And now it’s working! Both players can grapple each other and the code is running fine on both machines. I don’t have everything to do with grapple working, but so far it’s looking good.

Thanks again for all of your help and sorry if it’s been a waste of time due to my mistake.

1 Like

Awesome work,
Glad to hear you managed to solve the issue, I guess we went down the rabbit hole of multiplayer and overlooked the checks first :slight_smile:
Never a waste of time as we are all always still learning!

Good luck and hope you enjoy working on your game

1 Like

Thanks. It’s not working perfectly, I’m still getting used to 2 instances of the game running the same code twice, so it’s a lot of trail and error. But it seems the main problem is sorted for now :slight_smile:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms