Godot 4でマルチプレイを実装してみました!Part 1

2024/06/07
どうもおはこんばんにちは!ギルガメです!

ギルガメが一番ゲームに実装したいもの・・それはマルチプレイ!どんなゲームでもマルチプレイがあると友達や他のユーザーを遊べてしまう・・そんなものをいつか実装してみたいといつも思っていました。

Godot 4を触り始めてまだまだ新人ですが、私が好きなゲーム開発者がGodot 4のマルチプレイについて解説していたのでギルガメも実装してました。

実際に実装してみると下記のようになります!



ちょっと画質が悪いですね・・すみません。

実装方法としては、最初のユーザーがホストになって、それに他のユーザーが入るという実装です。

ギルガメ用のメモとしてやってみことをざっくりですはありますが、下記になります。

まずはmultiplayer_manager.gdを作成します。このスクリプトは自動でロードされるように設定します。
  • Project -> Project Setting... -> Autoload
上記をメニュー画面からいっていただいて、先ほどのmultiplayer_manager.gdを追加します。

multiplayer_manager.gd
extends Node

const SERVER_PORT = 8080
const SERVER_IP = "XXX.XXX.XX.XX"

var multiplayer_scene = preload("res://scenes/multiplayer_player.tscn")

var _player_spawn_node
var host_mode_enabled = false
var mutiplayer_mode_enabled = false
var respawn_point = Vector2(30, 20)

var chat_content = []

func become_host():
print("Become")
_player_spawn_node = get_tree().get_current_scene().get_node("Players")
host_mode_enabled = true
mutiplayer_mode_enabled = true
var server_peer = WebSocketMultiplayerPeer.new()
server_peer.create_server(SERVER_PORT)
multiplayer.multiplayer_peer = server_peer
multiplayer.peer_connected.connect(_add_player_to_game)
multiplayer.peer_disconnected.connect(_del_player)
_remove_single_player()

if not OS.has_feature("dedicated_server"):
_add_player_to_game(1)
func join_game():
print("Join")
mutiplayer_mode_enabled = true
var client_peer = WebSocketMultiplayerPeer.new()
client_peer.create_client("ws://" + SERVER_IP + ":" + str(SERVER_PORT))
multiplayer.multiplayer_peer = client_peer
_remove_single_player()

func _add_player_to_game(id: int):
print("Player %s joined the game!" % id)
var player_to_add = multiplayer_scene.instantiate()
player_to_add.player_id = id
player_to_add.name = str(id)
_player_spawn_node.add_child(player_to_add, true)
func _del_player(id: int):
print("Player %s left the game!" % id)
if not _player_spawn_node.has_node(str(id)):
return
_player_spawn_node.get_node(str(id)).queue_free()

func _remove_single_player():
print("Remove single player")
var player_to_remove = get_tree().get_current_scene().get_node("Player")
player_to_remove.queue_free()

今回はWeb上でマルチプレイを実装したいのでWebSocketMultiplayerPeerで実装しています。もしDesktopのために実装するのであればENetMultiplayerPeerでいいと思います。

シーンの実装は下記のようになります。



MultiplayerSpawnerの設定になります。



MultiplayerSpawnerのためにマルチプレイ用のプレイヤーを生成するためのシーンを作ります。
プレイヤーは下記のようになります。

multiplayer_player.gd
extends CharacterBody2D


const SPEED = 130.0
const JUMP_VELOCITY = -300.0

@onready var animated_sprite = $AnimatedSprite2D

var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

var direction = 1
var do_jump = false
var _is_on_floor = true
var alive = true

@export var player_id = 1:
set(id):
player_id = id
%InputSynchronizer.set_multiplayer_authority(id)
func _ready():
if multiplayer.get_unique_id() == player_id:
$Camera2D.make_current()
else:
$AnimatedSprite2D.set_modulate(Color(1,1,1,0.3))
$Camera2D.enabled = false

func _apply_animations(delta):
# Flip the Sprite
if direction > 0:
animated_sprite.flip_h = false
elif direction < 0:
animated_sprite.flip_h = true
# Play animations
if _is_on_floor:
if direction == 0:
animated_sprite.play("idle")
else:
animated_sprite.play("run")
else:
animated_sprite.play("jump")

func _apply_movement_from_input(delta):
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta

# Handle jump.
if do_jump and is_on_floor():
velocity.y = JUMP_VELOCITY
do_jump = false

# Get the input direction: -1, 0, 1
direction = %InputSynchronizer.input_direction
# Apply movement
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)

move_and_slide()

func _physics_process(delta):
if multiplayer.is_server():
if not alive && is_on_floor():
_set_alive()
_is_on_floor = is_on_floor()
_apply_movement_from_input(delta)

if not multiplayer.is_server() || MultiplayerManager.host_mode_enabled:
_apply_animations(delta)

func mark_dead():
alive = false
$CollisionShape2D.set_deferred("disabled", true)
$RespawnTimer.start()
func _respawn():
position = MultiplayerManager.respawn_point
$CollisionShape2D.set_deferred("disabled", false)
func _set_alive():
alive = true
Engine.time_scale = 1.0

PlayerSynchronizerを追加してシンクロしたいものを設定していきます。

  • player_id
  • position
  • do_jump
  • _is_on_floor
  • direction

次にInputSynchronizer追加してシンクロしたいものを設定していきます。

  • input_direction

次にプレイヤーの入力(移動、ジャンプなど)のイベントを受け取るスクリプトをつくって、先ほどのInputSynchronizerに追加します。

multiplayer_input.gd
extends MultiplayerSynchronizer

@onready var player = $".."

var input_direction

func _ready():
if get_multiplayer_authority() != multiplayer.get_unique_id():
set_process(false)
set_physics_process(false)
input_direction = Input.get_axis("move_left", "move_right")

func _process(delta):
if Input.is_action_just_pressed("jump"):
jump.rpc()

func _physics_process(delta):
input_direction = Input.get_axis("move_left", "move_right")

@rpc("call_local")
func jump():
if multiplayer.is_server() && player._is_on_floor:
player.do_jump = true

長くなってきたので一旦はここまでにします。
© Copyright 2024 YOSAPPS. Powered with by YOSAPPS