Created C# networked Pong
|
Before Width: | Height: | Size: 104 B |
BIN
2d/pong/paddle.png
Normal file
|
After Width: | Height: | Size: 84 B |
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="StreamTexture"
|
type="StreamTexture"
|
||||||
path="res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex"
|
path="res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://left_pallete.png"
|
source_file="res://paddle.png"
|
||||||
dest_files=[ "res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex" ]
|
dest_files=[ "res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
[gd_scene load_steps=13 format=2]
|
[gd_scene load_steps=12 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://logic/paddle.gd" type="Script" id=1]
|
[ext_resource path="res://logic/paddle.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://left_pallete.png" type="Texture" id=2]
|
[ext_resource path="res://paddle.png" type="Texture" id=2]
|
||||||
[ext_resource path="res://right_pallete.png" type="Texture" id=3]
|
|
||||||
[ext_resource path="res://logic/ball.gd" type="Script" id=4]
|
[ext_resource path="res://logic/ball.gd" type="Script" id=4]
|
||||||
[ext_resource path="res://ball.png" type="Texture" id=5]
|
[ext_resource path="res://ball.png" type="Texture" id=5]
|
||||||
[ext_resource path="res://separator.png" type="Texture" id=6]
|
[ext_resource path="res://separator.png" type="Texture" id=6]
|
||||||
@@ -32,6 +31,7 @@ __meta__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[node name="Left" type="Area2D" parent="."]
|
[node name="Left" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 0, 1, 1, 1 )
|
||||||
position = Vector2( 67.6285, 192.594 )
|
position = Vector2( 67.6285, 192.594 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
@@ -42,11 +42,12 @@ texture = ExtResource( 2 )
|
|||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
[node name="Right" type="Area2D" parent="."]
|
[node name="Right" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 1, 0, 1, 1 )
|
||||||
position = Vector2( 563.815, 188.919 )
|
position = Vector2( 563.815, 188.919 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="Right"]
|
[node name="Sprite" type="Sprite" parent="Right"]
|
||||||
texture = ExtResource( 3 )
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 104 B |
@@ -1,34 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="StreamTexture"
|
|
||||||
path="res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex"
|
|
||||||
metadata={
|
|
||||||
"vram_texture": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://right_pallete.png"
|
|
||||||
dest_files=[ "res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex" ]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=0
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_mode=0
|
|
||||||
compress/bptc_ldr=0
|
|
||||||
compress/normal_map=0
|
|
||||||
flags/repeat=0
|
|
||||||
flags/filter=false
|
|
||||||
flags/mipmaps=false
|
|
||||||
flags/anisotropic=false
|
|
||||||
flags/srgb=2
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/HDR_as_SRGB=false
|
|
||||||
process/invert_color=false
|
|
||||||
stream=false
|
|
||||||
size_limit=0
|
|
||||||
detect_3d=true
|
|
||||||
svg/scale=1.0
|
|
||||||
6
mono/multiplayer_pong/Pong Multiplayer with C#.csproj
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<Project Sdk="Godot.NET.Sdk/3.2.3">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<RootNamespace>PongMultiplayer</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
19
mono/multiplayer_pong/Pong Multiplayer with C#.sln
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2012
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pong Multiplayer with C#", "Pong Multiplayer with C#.csproj", "{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||||
|
ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
|
||||||
|
{4BB6C2D0-FC11-466E-8C73-8DAD689F135A}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
13
mono/multiplayer_pong/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Pong Multiplayer with C#
|
||||||
|
|
||||||
|
A multiplayer demo of Pong. One player presses "host". The other presses "join". This only works locally.
|
||||||
|
|
||||||
|
Language: [C#](https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html)
|
||||||
|
|
||||||
|
Renderer: GLES 2
|
||||||
|
|
||||||
|
Note: There is a GDScript version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/networking/multiplayer_pong).
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
BIN
mono/multiplayer_pong/ball.png
Normal file
|
After Width: | Height: | Size: 115 B |
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="StreamTexture"
|
type="StreamTexture"
|
||||||
path="res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex"
|
path="res://.import/ball.png-9a4ca347acb7532f6ae347744a6b04f7.stex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://left_pallete.png"
|
source_file="res://ball.png"
|
||||||
dest_files=[ "res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex" ]
|
dest_files=[ "res://.import/ball.png-9a4ca347acb7532f6ae347744a6b04f7.stex" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
16
mono/multiplayer_pong/ball.tscn
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://ball.png" type="Texture" id=1]
|
||||||
|
[ext_resource path="res://logic/Ball.cs" type="Script" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id=1]
|
||||||
|
radius = 4.65663
|
||||||
|
|
||||||
|
[node name="Ball" type="Area2D"]
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite" parent="."]
|
||||||
|
texture = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource( 1 )
|
||||||
BIN
mono/multiplayer_pong/icon.png
Normal file
|
After Width: | Height: | Size: 549 B |
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="StreamTexture"
|
type="StreamTexture"
|
||||||
path="res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex"
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://right_pallete.png"
|
source_file="res://icon.png"
|
||||||
dest_files=[ "res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex" ]
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
102
mono/multiplayer_pong/lobby.tscn
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://logic/Lobby.cs" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="Lobby" type="Control"]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = -320.0
|
||||||
|
margin_top = -200.0
|
||||||
|
margin_right = 320.0
|
||||||
|
margin_bottom = 200.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="."]
|
||||||
|
margin_left = 210.0
|
||||||
|
margin_top = 40.0
|
||||||
|
margin_right = 430.0
|
||||||
|
margin_bottom = 80.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "Multiplayer Pong"
|
||||||
|
align = 1
|
||||||
|
valign = 1
|
||||||
|
|
||||||
|
[node name="LobbyPanel" type="Panel" parent="."]
|
||||||
|
margin_left = 210.0
|
||||||
|
margin_top = 160.0
|
||||||
|
margin_right = 430.0
|
||||||
|
margin_bottom = 270.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="AddressLabel" type="Label" parent="LobbyPanel"]
|
||||||
|
margin_left = 10.0
|
||||||
|
margin_top = 10.0
|
||||||
|
margin_right = 62.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "Address"
|
||||||
|
|
||||||
|
[node name="Address" type="LineEdit" parent="LobbyPanel"]
|
||||||
|
margin_left = 10.0
|
||||||
|
margin_top = 30.0
|
||||||
|
margin_right = 210.0
|
||||||
|
margin_bottom = 54.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
text = "127.0.0.1"
|
||||||
|
|
||||||
|
[node name="HostButton" type="Button" parent="LobbyPanel"]
|
||||||
|
margin_left = 10.0
|
||||||
|
margin_top = 60.0
|
||||||
|
margin_right = 90.0
|
||||||
|
margin_bottom = 80.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
text = "Host"
|
||||||
|
|
||||||
|
[node name="JoinButton" type="Button" parent="LobbyPanel"]
|
||||||
|
margin_left = 130.0
|
||||||
|
margin_top = 60.0
|
||||||
|
margin_right = 210.0
|
||||||
|
margin_bottom = 80.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
text = "Join"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="StatusOk" type="Label" parent="LobbyPanel"]
|
||||||
|
margin_left = 10.0
|
||||||
|
margin_top = 90.0
|
||||||
|
margin_right = 210.0
|
||||||
|
margin_bottom = 104.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
custom_colors/font_color = Color( 0, 1, 0.015625, 1 )
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="StatusFail" type="Label" parent="LobbyPanel"]
|
||||||
|
margin_left = 10.0
|
||||||
|
margin_top = 90.0
|
||||||
|
margin_right = 210.0
|
||||||
|
margin_bottom = 104.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
custom_colors/font_color = Color( 1, 0, 0, 1 )
|
||||||
|
align = 1
|
||||||
|
[connection signal="pressed" from="LobbyPanel/HostButton" to="LobbyPanel" method="OnHostPressed"]
|
||||||
|
[connection signal="pressed" from="LobbyPanel/JoinButton" to="LobbyPanel" method="OnJoinPressed"]
|
||||||
97
mono/multiplayer_pong/logic/Ball.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class Ball : Area2D
|
||||||
|
{
|
||||||
|
private const int DefaultSpeed = 100;
|
||||||
|
|
||||||
|
private Vector2 _direction = Vector2.Left;
|
||||||
|
private bool _stopped = false;
|
||||||
|
private float _speed = DefaultSpeed;
|
||||||
|
private Vector2 _screenSize;
|
||||||
|
|
||||||
|
// Called when the node enters the scene tree for the first time.
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
_screenSize = GetViewportRect().Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
public override void _Process(float delta)
|
||||||
|
{
|
||||||
|
_speed += delta;
|
||||||
|
// Ball will move normally for both players,
|
||||||
|
// even if it's slightly out of sync between them,
|
||||||
|
// so each player sees the motion as smooth and not jerky.
|
||||||
|
if (!_stopped)
|
||||||
|
{
|
||||||
|
Translate(_speed * delta * _direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check screen bounds to make ball bounce.
|
||||||
|
var ballPosition = Position;
|
||||||
|
if ((ballPosition.y < 0 && _direction.y < 0) || (ballPosition.y > _screenSize.y && _direction.y > 0))
|
||||||
|
{
|
||||||
|
_direction.y = -_direction.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsNetworkMaster())
|
||||||
|
{
|
||||||
|
// Only the master will decide when the ball is out in
|
||||||
|
// the left side (it's own side). This makes the game
|
||||||
|
// playable even if latency is high and ball is going
|
||||||
|
// fast. Otherwise ball might be out in the other
|
||||||
|
// player's screen but not this one.
|
||||||
|
if (ballPosition.x < 0)
|
||||||
|
{
|
||||||
|
GetParent().Rpc("UpdateScore", false);
|
||||||
|
Rpc("ResetBall", false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only the puppet will decide when the ball is out in
|
||||||
|
// the right side, which is it's own side. This makes
|
||||||
|
// the game playable even if latency is high and ball
|
||||||
|
// is going fast. Otherwise ball might be out in the
|
||||||
|
// other player's screen but not this one.
|
||||||
|
if (ballPosition.x > _screenSize.x)
|
||||||
|
{
|
||||||
|
GetParent().Rpc("UpdateScore", true);
|
||||||
|
Rpc("ResetBall", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Sync]
|
||||||
|
private void Bounce(bool left, float random)
|
||||||
|
{
|
||||||
|
// Using sync because both players can make it bounce.
|
||||||
|
if (left)
|
||||||
|
{
|
||||||
|
_direction.x = Mathf.Abs(_direction.x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_direction.x = -Mathf.Abs(_direction.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
_speed *= 1.1f;
|
||||||
|
_direction.y = random * 2.0f - 1;
|
||||||
|
_direction = _direction.Normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Sync]
|
||||||
|
private void Stop()
|
||||||
|
{
|
||||||
|
_stopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Sync]
|
||||||
|
private void ResetBall(bool forLeft)
|
||||||
|
{
|
||||||
|
Position = _screenSize / 2;
|
||||||
|
_direction = forLeft ? Vector2.Left : Vector2.Right;
|
||||||
|
_speed = DefaultSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
143
mono/multiplayer_pong/logic/Lobby.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
using Godot.Collections;
|
||||||
|
|
||||||
|
public class Lobby : Control
|
||||||
|
{
|
||||||
|
private const int DefaultPort = 8910; // An arbitrary number.
|
||||||
|
private const int MaxNumberOfPeers = 1; // How many people we want to have in a game
|
||||||
|
|
||||||
|
private LineEdit _address;
|
||||||
|
private Button _hostButton;
|
||||||
|
private Button _joinButton;
|
||||||
|
private Label _statusOk;
|
||||||
|
private Label _statusFail;
|
||||||
|
private NetworkedMultiplayerENet _peer;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
// Get nodes - the generic is a class, argument is node path.
|
||||||
|
_address = GetNode<LineEdit>("Address");
|
||||||
|
_hostButton = GetNode<Button>("HostButton");
|
||||||
|
_joinButton = GetNode<Button>("JoinButton");
|
||||||
|
_statusOk = GetNode<Label>("StatusOk");
|
||||||
|
_statusFail = GetNode<Label>("StatusFail");
|
||||||
|
|
||||||
|
// Connect all callbacks related to networking.
|
||||||
|
// Note: Use snake_case when talking to engine API.
|
||||||
|
GetTree().Connect("network_peer_connected", this, nameof(PlayerConnected));
|
||||||
|
GetTree().Connect("network_peer_disconnected", this, nameof(PlayerDisconnected));
|
||||||
|
GetTree().Connect("connected_to_server", this, nameof(ConnectedOk));
|
||||||
|
GetTree().Connect("connection_failed", this, nameof(ConnectedFail));
|
||||||
|
GetTree().Connect("server_disconnected", this, nameof(ServerDisconnected));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network callbacks from SceneTree
|
||||||
|
|
||||||
|
// Callback from SceneTree.
|
||||||
|
private void PlayerConnected(int id)
|
||||||
|
{
|
||||||
|
// Someone connected, start the game!
|
||||||
|
var pong = ResourceLoader.Load<PackedScene>("res://pong.tscn").Instance();
|
||||||
|
|
||||||
|
// Connect deferred so we can safely erase it from the callback.
|
||||||
|
pong.Connect("GameFinished", this, nameof(EndGame), new Godot.Collections.Array(), (int) ConnectFlags.Deferred);
|
||||||
|
|
||||||
|
GetTree().Root.AddChild(pong);
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerDisconnected(int id)
|
||||||
|
{
|
||||||
|
EndGame(GetTree().IsNetworkServer() ? "Client disconnected" : "Server disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from SceneTree, only for clients (not server).
|
||||||
|
private void ConnectedOk()
|
||||||
|
{
|
||||||
|
// This function is not needed for this project.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from SceneTree, only for clients (not server).
|
||||||
|
private void ConnectedFail()
|
||||||
|
{
|
||||||
|
SetStatus("Couldn't connect", false);
|
||||||
|
|
||||||
|
GetTree().NetworkPeer = null; // Remove peer.
|
||||||
|
_hostButton.Disabled = false;
|
||||||
|
_joinButton.Disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ServerDisconnected()
|
||||||
|
{
|
||||||
|
EndGame("Server disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game creation functions
|
||||||
|
|
||||||
|
private void EndGame(string withError = "")
|
||||||
|
{
|
||||||
|
if (HasNode("/root/Pong"))
|
||||||
|
{
|
||||||
|
// Erase immediately, otherwise network might show
|
||||||
|
// errors (this is why we connected deferred above).
|
||||||
|
GetNode("/root/Pong").Free();
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
GetTree().NetworkPeer = null; // Remove peer.
|
||||||
|
_hostButton.Disabled = false;
|
||||||
|
_joinButton.Disabled = false;
|
||||||
|
|
||||||
|
SetStatus(withError, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetStatus(string text, bool isOk)
|
||||||
|
{
|
||||||
|
// Simple way to show status.
|
||||||
|
if (isOk)
|
||||||
|
{
|
||||||
|
_statusOk.Text = text;
|
||||||
|
_statusFail.Text = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_statusOk.Text = "";
|
||||||
|
_statusFail.Text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHostPressed()
|
||||||
|
{
|
||||||
|
_peer = new NetworkedMultiplayerENet();
|
||||||
|
_peer.CompressionMode = NetworkedMultiplayerENet.CompressionModeEnum.RangeCoder;
|
||||||
|
Error err = _peer.CreateServer(DefaultPort, MaxNumberOfPeers);
|
||||||
|
if (err != Error.Ok)
|
||||||
|
{
|
||||||
|
// Is another server running?
|
||||||
|
SetStatus("Can't host, address in use.", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetTree().NetworkPeer = _peer;
|
||||||
|
_hostButton.Disabled = true;
|
||||||
|
_joinButton.Disabled = true;
|
||||||
|
SetStatus("Waiting for player...", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnJoinPressed()
|
||||||
|
{
|
||||||
|
string ip = _address.Text;
|
||||||
|
if (!ip.IsValidIPAddress())
|
||||||
|
{
|
||||||
|
SetStatus("IP address is invalid", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_peer = new NetworkedMultiplayerENet();
|
||||||
|
_peer.CompressionMode = NetworkedMultiplayerENet.CompressionModeEnum.RangeCoder;
|
||||||
|
_peer.CreateClient(ip, DefaultPort);
|
||||||
|
GetTree().NetworkPeer = _peer;
|
||||||
|
SetStatus("Connecting...", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
70
mono/multiplayer_pong/logic/Paddle.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class Paddle : Area2D
|
||||||
|
{
|
||||||
|
private const int MotionSpeed = 150;
|
||||||
|
|
||||||
|
[Export] private bool _left = false;
|
||||||
|
|
||||||
|
private float _motion = 0.0f;
|
||||||
|
private bool _youHidden = false;
|
||||||
|
private float _screenSizeY = 0.0f;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
_screenSizeY = GetViewportRect().Size.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(float delta)
|
||||||
|
{
|
||||||
|
// Is the master of the paddle.
|
||||||
|
if (IsNetworkMaster())
|
||||||
|
{
|
||||||
|
_motion = Input.GetActionStrength("move_down") - Input.GetActionStrength("move_up");
|
||||||
|
|
||||||
|
if (!_youHidden && _motion != 0)
|
||||||
|
{
|
||||||
|
HideYouLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
_motion *= MotionSpeed;
|
||||||
|
|
||||||
|
// Using unreliable to make sure position is updated as fast as possible,
|
||||||
|
// even if one of the calls is dropped
|
||||||
|
RpcUnreliable(nameof(SetPosAndMotion), Position, _motion);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_youHidden)
|
||||||
|
{
|
||||||
|
HideYouLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Translate(new Vector2(0, _motion * delta));
|
||||||
|
|
||||||
|
// Set screen limits. Can't modify structs directly, so we create a new one.
|
||||||
|
Position = new Vector2(Position.x, Mathf.Clamp(Position.y, 16, _screenSizeY - 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Puppet]
|
||||||
|
private void SetPosAndMotion(Vector2 pos, float motion)
|
||||||
|
{
|
||||||
|
Position = pos;
|
||||||
|
_motion = motion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideYouLabel()
|
||||||
|
{
|
||||||
|
_youHidden = true;
|
||||||
|
GetNode<Label>("You").Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPaddleAreaEnter(Area2D area)
|
||||||
|
{
|
||||||
|
if (IsNetworkMaster())
|
||||||
|
{
|
||||||
|
area.Rpc("Bounce", _left, GD.Randf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
mono/multiplayer_pong/logic/Pong.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using Godot;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class Pong : Node2D
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
private delegate void GameFinished(string withError);
|
||||||
|
|
||||||
|
private const int ScoreToWin = 10;
|
||||||
|
|
||||||
|
private int _scoreLeft = 0;
|
||||||
|
private int _scoreRight = 0;
|
||||||
|
private Paddle _playerTwo;
|
||||||
|
private Label _scoreLeftNode;
|
||||||
|
private Label _scoreRightNode;
|
||||||
|
private Label _winnerLeft;
|
||||||
|
private Label _winnerRight;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
// Get nodes. The generic is the class, argument is path to the node.
|
||||||
|
_playerTwo = GetNode<Paddle>("Player2");
|
||||||
|
_scoreLeftNode = GetNode<Label>("ScoreLeft");
|
||||||
|
_scoreRightNode = GetNode<Label>("ScoreRight");
|
||||||
|
_winnerLeft = GetNode<Label>("WinnerLeft");
|
||||||
|
_winnerRight = GetNode<Label>("WinnerRight");
|
||||||
|
|
||||||
|
// By default, all nodes in server inherit from master,
|
||||||
|
// while all nodes in clients inherit from puppet.
|
||||||
|
// SetNetworkMaster is tree-recursive by default.
|
||||||
|
if (GetTree().IsNetworkServer())
|
||||||
|
{
|
||||||
|
_playerTwo.SetNetworkMaster(GetTree().GetNetworkConnectedPeers()[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_playerTwo.SetNetworkMaster(GetTree().GetNetworkUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
GD.Print("Unique id: ", GetTree().GetNetworkUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Sync]
|
||||||
|
private void UpdateScore(bool addToLeft)
|
||||||
|
{
|
||||||
|
if (addToLeft)
|
||||||
|
{
|
||||||
|
_scoreLeft += 1;
|
||||||
|
_scoreLeftNode.Text = _scoreLeft.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_scoreRight += 1;
|
||||||
|
_scoreRightNode.Text = _scoreRight.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameEnded = false;
|
||||||
|
|
||||||
|
if (_scoreLeft == ScoreToWin)
|
||||||
|
{
|
||||||
|
_winnerLeft.Show();
|
||||||
|
gameEnded = true;
|
||||||
|
}
|
||||||
|
else if (_scoreRight == ScoreToWin)
|
||||||
|
{
|
||||||
|
_winnerRight.Show();
|
||||||
|
gameEnded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameEnded)
|
||||||
|
{
|
||||||
|
GetNode<Button>("ExitGame").Show();
|
||||||
|
GetNode<Ball>("Ball").Rpc("Stop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExitGamePressed()
|
||||||
|
{
|
||||||
|
EmitSignal(nameof(GameFinished), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
mono/multiplayer_pong/paddle.png
Normal file
|
After Width: | Height: | Size: 84 B |
34
mono/multiplayer_pong/paddle.png.import
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://paddle.png"
|
||||||
|
dest_files=[ "res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
||||||
31
mono/multiplayer_pong/paddle.tscn
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://logic/Paddle.cs" type="Script" id=1]
|
||||||
|
[ext_resource path="res://paddle.png" type="Texture" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape2D" id=1]
|
||||||
|
radius = 4.78568
|
||||||
|
height = 23.6064
|
||||||
|
|
||||||
|
[node name="Paddle" type="Area2D"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite" parent="."]
|
||||||
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Shape" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="You" type="Label" parent="."]
|
||||||
|
margin_left = -26.0
|
||||||
|
margin_top = -33.0
|
||||||
|
margin_right = 27.0
|
||||||
|
margin_bottom = -19.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "You"
|
||||||
|
align = 1
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
[connection signal="area_entered" from="." to="." method="OnPaddleAreaEnter"]
|
||||||
92
mono/multiplayer_pong/pong.tscn
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://logic/Pong.cs" type="Script" id=1]
|
||||||
|
[ext_resource path="res://separator.png" type="Texture" id=2]
|
||||||
|
[ext_resource path="res://paddle.tscn" type="PackedScene" id=3]
|
||||||
|
[ext_resource path="res://ball.tscn" type="PackedScene" id=4]
|
||||||
|
|
||||||
|
[node name="Pong" type="Node2D"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="."]
|
||||||
|
margin_right = 640.0
|
||||||
|
margin_bottom = 400.0
|
||||||
|
color = Color( 0.141176, 0.152941, 0.164706, 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Separator" type="Sprite" parent="."]
|
||||||
|
position = Vector2( 320, 200 )
|
||||||
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Player1" parent="." instance=ExtResource( 3 )]
|
||||||
|
modulate = Color( 0, 1, 1, 1 )
|
||||||
|
position = Vector2( 32.49, 188.622 )
|
||||||
|
_left = true
|
||||||
|
|
||||||
|
[node name="Player2" parent="." instance=ExtResource( 3 )]
|
||||||
|
modulate = Color( 1, 0, 1, 1 )
|
||||||
|
position = Vector2( 608.88, 188.622 )
|
||||||
|
|
||||||
|
[node name="Ball" parent="." instance=ExtResource( 4 )]
|
||||||
|
position = Vector2( 320.206, 184 )
|
||||||
|
|
||||||
|
[node name="ScoreLeft" type="Label" parent="."]
|
||||||
|
margin_left = 240.0
|
||||||
|
margin_top = 10.0
|
||||||
|
margin_right = 280.0
|
||||||
|
margin_bottom = 30.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "0"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="ScoreRight" type="Label" parent="."]
|
||||||
|
margin_left = 360.0
|
||||||
|
margin_top = 10.0
|
||||||
|
margin_right = 400.0
|
||||||
|
margin_bottom = 30.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "0"
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="WinnerLeft" type="Label" parent="."]
|
||||||
|
visible = false
|
||||||
|
margin_left = 190.0
|
||||||
|
margin_top = 170.0
|
||||||
|
margin_right = 267.0
|
||||||
|
margin_bottom = 184.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "The Winner!"
|
||||||
|
|
||||||
|
[node name="WinnerRight" type="Label" parent="."]
|
||||||
|
visible = false
|
||||||
|
margin_left = 380.0
|
||||||
|
margin_top = 170.0
|
||||||
|
margin_right = 457.0
|
||||||
|
margin_bottom = 184.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "The Winner!"
|
||||||
|
|
||||||
|
[node name="ExitGame" type="Button" parent="."]
|
||||||
|
visible = false
|
||||||
|
margin_left = 280.0
|
||||||
|
margin_top = 340.0
|
||||||
|
margin_right = 360.0
|
||||||
|
margin_bottom = 360.0
|
||||||
|
size_flags_horizontal = 2
|
||||||
|
size_flags_vertical = 2
|
||||||
|
text = "Exit Game"
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
|
offset = Vector2( 320, 200 )
|
||||||
|
current = true
|
||||||
|
[connection signal="pressed" from="ExitGame" to="." method="OnExitGamePressed"]
|
||||||
|
|
||||||
|
[editable path="Player1"]
|
||||||
|
|
||||||
|
[editable path="Player2"]
|
||||||
56
mono/multiplayer_pong/project.godot
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Pong Multiplayer with C#"
|
||||||
|
config/description="A multiplayer demo of the classical pong game.
|
||||||
|
One of the players should press 'host', while the
|
||||||
|
other should select the address and press 'join'."
|
||||||
|
run/main_scene="res://lobby.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/width=640
|
||||||
|
window/size/height=400
|
||||||
|
window/stretch/mode="2d"
|
||||||
|
window/stretch/aspect="expand"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
move_down={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":90,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move_up={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||||
|
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
quality/driver/driver_name="GLES2"
|
||||||
|
quality/2d/use_pixel_snap=true
|
||||||
BIN
mono/multiplayer_pong/separator.png
Normal file
|
After Width: | Height: | Size: 108 B |
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="StreamTexture"
|
type="StreamTexture"
|
||||||
path="res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex"
|
path="res://.import/separator.png-f981c8489b9148e2e1dc63398273da74.stex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://left_pallete.png"
|
source_file="res://separator.png"
|
||||||
dest_files=[ "res://.import/left_pallete.png-bc33611074a0f886142e37c77bd2545a.stex" ]
|
dest_files=[ "res://.import/separator.png-f981c8489b9148e2e1dc63398273da74.stex" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 104 B |
BIN
mono/pong/paddle.png
Normal file
|
After Width: | Height: | Size: 84 B |
34
mono/pong/paddle.png.import
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://paddle.png"
|
||||||
|
dest_files=[ "res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
[gd_scene load_steps=13 format=2]
|
[gd_scene load_steps=12 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://Logic/Paddle.cs" type="Script" id=1]
|
[ext_resource path="res://Logic/Paddle.cs" type="Script" id=1]
|
||||||
[ext_resource path="res://left_pallete.png" type="Texture" id=2]
|
[ext_resource path="res://paddle.png" type="Texture" id=2]
|
||||||
[ext_resource path="res://right_pallete.png" type="Texture" id=3]
|
|
||||||
[ext_resource path="res://Logic/Ball.cs" type="Script" id=4]
|
[ext_resource path="res://Logic/Ball.cs" type="Script" id=4]
|
||||||
[ext_resource path="res://ball.png" type="Texture" id=5]
|
[ext_resource path="res://ball.png" type="Texture" id=5]
|
||||||
[ext_resource path="res://separator.png" type="Texture" id=6]
|
[ext_resource path="res://separator.png" type="Texture" id=6]
|
||||||
@@ -29,6 +28,7 @@ margin_bottom = 400.0
|
|||||||
color = Color( 0.141176, 0.152941, 0.164706, 1 )
|
color = Color( 0.141176, 0.152941, 0.164706, 1 )
|
||||||
|
|
||||||
[node name="Left" type="Area2D" parent="."]
|
[node name="Left" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 0, 1, 1, 1 )
|
||||||
position = Vector2( 67.6285, 192.594 )
|
position = Vector2( 67.6285, 192.594 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
@@ -39,11 +39,12 @@ texture = ExtResource( 2 )
|
|||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
[node name="Right" type="Area2D" parent="."]
|
[node name="Right" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 1, 0, 1, 1 )
|
||||||
position = Vector2( 563.815, 188.919 )
|
position = Vector2( 563.815, 188.919 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="Right"]
|
[node name="Sprite" type="Sprite" parent="Right"]
|
||||||
texture = ExtResource( 3 )
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 104 B |
@@ -22,16 +22,20 @@ func _process(delta):
|
|||||||
direction.y = -direction.y
|
direction.y = -direction.y
|
||||||
|
|
||||||
if is_network_master():
|
if is_network_master():
|
||||||
# Only master will decide when the ball is out in the left side (it's own side).
|
# Only the master will decide when the ball is out in
|
||||||
# This makes the game playable even if latency is high and ball is going fast.
|
# the left side (it's own side). This makes the game
|
||||||
# Otherwise ball might be out in the other player's screen but not this one.
|
# playable even if latency is high and ball is going
|
||||||
|
# fast. Otherwise ball might be out in the other
|
||||||
|
# player's screen but not this one.
|
||||||
if ball_pos.x < 0:
|
if ball_pos.x < 0:
|
||||||
get_parent().rpc("update_score", false)
|
get_parent().rpc("update_score", false)
|
||||||
rpc("_reset_ball", false)
|
rpc("_reset_ball", false)
|
||||||
else:
|
else:
|
||||||
# Only the puppet will decide when the ball is out in the right side (it's own side).
|
# Only the puppet will decide when the ball is out in
|
||||||
# This makes the game playable even if latency is high and ball is going fast.
|
# the right side, which is it's own side. This makes
|
||||||
# Otherwise ball might be out in the other player's screen but not this one.
|
# the game playable even if latency is high and ball
|
||||||
|
# is going fast. Otherwise ball might be out in the
|
||||||
|
# other player's screen but not this one.
|
||||||
if ball_pos.x > _screen_size.x:
|
if ball_pos.x > _screen_size.x:
|
||||||
get_parent().rpc("update_score", true)
|
get_parent().rpc("update_score", true)
|
||||||
rpc("_reset_ball", true)
|
rpc("_reset_ball", true)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func _player_disconnected(_id):
|
|||||||
|
|
||||||
# Callback from SceneTree, only for clients (not server).
|
# Callback from SceneTree, only for clients (not server).
|
||||||
func _connected_ok():
|
func _connected_ok():
|
||||||
pass # We don't need this function.
|
pass # This function is not needed for this project.
|
||||||
|
|
||||||
|
|
||||||
# Callback from SceneTree, only for clients (not server).
|
# Callback from SceneTree, only for clients (not server).
|
||||||
@@ -59,7 +59,8 @@ func _server_disconnected():
|
|||||||
|
|
||||||
func _end_game(with_error = ""):
|
func _end_game(with_error = ""):
|
||||||
if has_node("/root/Pong"):
|
if has_node("/root/Pong"):
|
||||||
# Erase immediately, otherwise network might show errors (this is why we connected deferred above).
|
# Erase immediately, otherwise network might show
|
||||||
|
# errors (this is why we connected deferred above).
|
||||||
get_node("/root/Pong").free()
|
get_node("/root/Pong").free()
|
||||||
show()
|
show()
|
||||||
|
|
||||||
|
|||||||
@@ -4,42 +4,42 @@ const MOTION_SPEED = 150
|
|||||||
|
|
||||||
export var left = false
|
export var left = false
|
||||||
|
|
||||||
var motion = 0
|
var _motion = 0
|
||||||
var you_hidden = false
|
var _you_hidden = false
|
||||||
|
|
||||||
onready var _screen_size_y = get_viewport_rect().size.y
|
onready var _screen_size_y = get_viewport_rect().size.y
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
# Is the master of the paddle.
|
# Is the master of the paddle.
|
||||||
if is_network_master():
|
if is_network_master():
|
||||||
motion = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
|
_motion = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
|
||||||
|
|
||||||
if not you_hidden and motion != 0:
|
if not _you_hidden and _motion != 0:
|
||||||
_hide_you_label()
|
_hide_you_label()
|
||||||
|
|
||||||
motion *= MOTION_SPEED
|
_motion *= MOTION_SPEED
|
||||||
|
|
||||||
# Using unreliable to make sure position is updated as fast
|
# Using unreliable to make sure position is updated as fast
|
||||||
# as possible, even if one of the calls is dropped.
|
# as possible, even if one of the calls is dropped.
|
||||||
rpc_unreliable("set_pos_and_motion", position, motion)
|
rpc_unreliable("set_pos_and_motion", position, _motion)
|
||||||
else:
|
else:
|
||||||
if not you_hidden:
|
if not _you_hidden:
|
||||||
_hide_you_label()
|
_hide_you_label()
|
||||||
|
|
||||||
translate(Vector2(0, motion * delta))
|
translate(Vector2(0, _motion * delta))
|
||||||
|
|
||||||
# Set screen limits.
|
# Set screen limits.
|
||||||
position.y = clamp(position.y, 16, _screen_size_y - 16)
|
position.y = clamp(position.y, 16, _screen_size_y - 16)
|
||||||
|
|
||||||
|
|
||||||
# Synchronize position and speed to the other peers.
|
# Synchronize position and speed to the other peers.
|
||||||
puppet func set_pos_and_motion(p_pos, p_motion):
|
puppet func set_pos_and_motion(pos, motion):
|
||||||
position = p_pos
|
position = pos
|
||||||
motion = p_motion
|
_motion = motion
|
||||||
|
|
||||||
|
|
||||||
func _hide_you_label():
|
func _hide_you_label():
|
||||||
you_hidden = true
|
_you_hidden = true
|
||||||
get_node("You").hide()
|
get_node("You").hide()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
|
signal game_finished()
|
||||||
|
|
||||||
const SCORE_TO_WIN = 10
|
const SCORE_TO_WIN = 10
|
||||||
|
|
||||||
var score_left = 0
|
var score_left = 0
|
||||||
var score_right = 0
|
var score_right = 0
|
||||||
|
|
||||||
signal game_finished()
|
|
||||||
|
|
||||||
onready var player2 = $Player2
|
onready var player2 = $Player2
|
||||||
onready var score_left_node = $ScoreLeft
|
onready var score_left_node = $ScoreLeft
|
||||||
onready var score_right_node = $ScoreRight
|
onready var score_right_node = $ScoreRight
|
||||||
@@ -23,7 +23,8 @@ func _ready():
|
|||||||
else:
|
else:
|
||||||
# For the client, give control of player 2 to itself.
|
# For the client, give control of player 2 to itself.
|
||||||
player2.set_network_master(get_tree().get_network_unique_id())
|
player2.set_network_master(get_tree().get_network_unique_id())
|
||||||
print("unique id: ", get_tree().get_network_unique_id())
|
|
||||||
|
print("Unique id: ", get_tree().get_network_unique_id())
|
||||||
|
|
||||||
|
|
||||||
sync func update_score(add_to_left):
|
sync func update_score(add_to_left):
|
||||||
|
|||||||
@@ -21,19 +21,14 @@ position = Vector2( 320, 200 )
|
|||||||
texture = ExtResource( 2 )
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
[node name="Player1" parent="." instance=ExtResource( 3 )]
|
[node name="Player1" parent="." instance=ExtResource( 3 )]
|
||||||
|
modulate = Color( 0, 1, 1, 1 )
|
||||||
position = Vector2( 32.49, 188.622 )
|
position = Vector2( 32.49, 188.622 )
|
||||||
left = true
|
left = true
|
||||||
|
|
||||||
[node name="Sprite" parent="Player1" index="0"]
|
|
||||||
self_modulate = Color( 0, 1, 1, 1 )
|
|
||||||
|
|
||||||
[node name="Player2" parent="." instance=ExtResource( 3 )]
|
[node name="Player2" parent="." instance=ExtResource( 3 )]
|
||||||
self_modulate = Color( 1, 0, 1, 1 )
|
modulate = Color( 1, 0, 1, 1 )
|
||||||
position = Vector2( 608.88, 188.622 )
|
position = Vector2( 608.88, 188.622 )
|
||||||
|
|
||||||
[node name="Sprite" parent="Player2" index="0"]
|
|
||||||
self_modulate = Color( 1, 0, 1, 1 )
|
|
||||||
|
|
||||||
[node name="Ball" parent="." instance=ExtResource( 4 )]
|
[node name="Ball" parent="." instance=ExtResource( 4 )]
|
||||||
position = Vector2( 320.387, 189.525 )
|
position = Vector2( 320.387, 189.525 )
|
||||||
|
|
||||||
|
|||||||
@@ -64,4 +64,3 @@ move_up={
|
|||||||
|
|
||||||
quality/driver/driver_name="GLES2"
|
quality/driver/driver_name="GLES2"
|
||||||
quality/2d/use_pixel_snap=true
|
quality/2d/use_pixel_snap=true
|
||||||
viewport/default_clear_color=Color( 0, 0, 0, 1 )
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 104 B |
BIN
visual_script/pong/paddle.png
Normal file
|
After Width: | Height: | Size: 84 B |
34
visual_script/pong/paddle.png.import
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://paddle.png"
|
||||||
|
dest_files=[ "res://.import/paddle.png-0e798fb0912613386507c9904d5cc01a.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
[gd_scene load_steps=13 format=2]
|
[gd_scene load_steps=12 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://scripts/paddle.vs" type="Script" id=1]
|
[ext_resource path="res://scripts/paddle.vs" type="Script" id=1]
|
||||||
[ext_resource path="res://left_pallete.png" type="Texture" id=2]
|
[ext_resource path="res://paddle.png" type="Texture" id=2]
|
||||||
[ext_resource path="res://right_pallete.png" type="Texture" id=3]
|
|
||||||
[ext_resource path="res://scripts/ball.vs" type="Script" id=4]
|
[ext_resource path="res://scripts/ball.vs" type="Script" id=4]
|
||||||
[ext_resource path="res://ball.png" type="Texture" id=5]
|
[ext_resource path="res://ball.png" type="Texture" id=5]
|
||||||
[ext_resource path="res://separator.png" type="Texture" id=6]
|
[ext_resource path="res://separator.png" type="Texture" id=6]
|
||||||
@@ -32,6 +31,7 @@ __meta__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[node name="Left" type="Area2D" parent="."]
|
[node name="Left" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 0, 1, 1, 1 )
|
||||||
position = Vector2( 67.6285, 192.594 )
|
position = Vector2( 67.6285, 192.594 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
@@ -42,12 +42,13 @@ texture = ExtResource( 2 )
|
|||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
[node name="Right" type="Area2D" parent="."]
|
[node name="Right" type="Area2D" parent="."]
|
||||||
|
modulate = Color( 1, 0, 1, 1 )
|
||||||
position = Vector2( 563.815, 188.919 )
|
position = Vector2( 563.815, 188.919 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
ball_dir = -1.0
|
ball_dir = -1.0
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="Right"]
|
[node name="Sprite" type="Sprite" parent="Right"]
|
||||||
texture = ExtResource( 3 )
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
[node name="Collision" type="CollisionShape2D" parent="Right"]
|
||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 104 B |
@@ -1,34 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="StreamTexture"
|
|
||||||
path="res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex"
|
|
||||||
metadata={
|
|
||||||
"vram_texture": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://right_pallete.png"
|
|
||||||
dest_files=[ "res://.import/right_pallete.png-fc6e4a6a7c8197834656482b94708e47.stex" ]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=0
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_mode=0
|
|
||||||
compress/bptc_ldr=0
|
|
||||||
compress/normal_map=0
|
|
||||||
flags/repeat=0
|
|
||||||
flags/filter=false
|
|
||||||
flags/mipmaps=false
|
|
||||||
flags/anisotropic=false
|
|
||||||
flags/srgb=2
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/HDR_as_SRGB=false
|
|
||||||
process/invert_color=false
|
|
||||||
stream=false
|
|
||||||
size_limit=0
|
|
||||||
detect_3d=true
|
|
||||||
svg/scale=1.0
|
|
||||||