Groundwork for multiplayer

- Add IsLocal property to Player
- Disable some functionality if local
- Tweaks to movement and camera controller
- Let players push each other
- Add a fake "remote" player for testing
- Undo the IInitalizable silliness
main
copygirl 5 months ago
parent aad2484b66
commit c21e4db3ea
  1. 121
      player/AnimationController.cs
  2. 18
      player/CameraController.cs
  3. 48
      player/MovementController.cs
  4. 10
      player/PickupController.cs
  5. 13
      player/Player.cs
  6. 23
      player/PushbackArea.cs
  7. 67
      player/player.tscn
  8. 4
      scenes/warehouse.tscn

@ -1,4 +1,4 @@
public partial class AnimationController : Node3D, IInitalizable<Player>
public partial class AnimationController : Node3D
{
[Export] public Skeleton3D Skeleton { get; set; }
[Export] public BoneAttachment3D RootBone { get; set; }
@ -17,11 +17,9 @@ public partial class AnimationController : Node3D, IInitalizable<Player>
AnimationTree _animTree;
Animation _walkForwardAnim;
Animation _walkBackwardAnim;
public void Initialize(Player player)
public override void _Ready()
{
_player = player;
_cameraDefaultTransform = _player.Camera.Camera.Transform;
_player = GetParent<Player>();
_animTree = GetNode<AnimationTree>("AnimationTree");
_walkForwardAnim = _animTree.GetAnimation("walk_forward");
_walkBackwardAnim = _animTree.GetAnimation("walk_backward");
@ -45,7 +43,8 @@ public partial class AnimationController : Node3D, IInitalizable<Player>
{
foreach (var bone in _bones.Values)
bone.Transform = Skeleton.GetBonePose(bone.BoneIdx);
_player.Camera.Camera.Transform = _cameraDefaultTransform;
if (_player.Camera.Camera is Camera3D camera)
camera.Transform = _player.Camera.DefaultTransform;
}
void HandleTurning(double delta)
@ -55,8 +54,10 @@ public partial class AnimationController : Node3D, IInitalizable<Player>
const float TurnSpeed = 6.0f;
var yaw = _player.Camera.CurrentYaw; // Camera yaw relative to player yaw.
var isMoving = _player.Movement.RealMoveSpeed > 0.01f;
_isTurning = isMoving || (Abs(yaw) > DegToRad(TurnBegin));
var movement = _player.Movement;
var isWalking = movement.LocalMoveVector.Length() > movement.MaxSpeed / 4;
_isTurning = isWalking || (Abs(yaw) > DegToRad(TurnBegin));
if (_isTurning) {
var yawDelta = Sign(yaw) * Min(Abs(yaw), Abs(yaw) * TurnSpeed * (float)delta);
@ -70,56 +71,62 @@ public partial class AnimationController : Node3D, IInitalizable<Player>
void HandleLookingAnimation(double delta)
{
var camera = _player.Camera.Camera;
var pitch = _player.Camera.CurrentPitch;
var yaw = _player.Camera.CurrentYaw;
const float PitchFactorLowerBody = 0.05f;
const float PitchFactorUpperBody = 0.20f;
const float PitchFactorNeck = 0.25f;
const float PitchFactorHead = 0.35f;
var pitch = _player.Camera.CurrentPitch;
_bones["LowerBody"].RotateX(pitch * PitchFactorLowerBody);
_bones["UpperBody"].RotateX(-pitch * PitchFactorUpperBody);
_bones["Neck"].RotateX(-pitch * PitchFactorNeck);
_bones["Head"].RotateX(-pitch * PitchFactorHead);
_bones["UpperArm_L"].RotateX(pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2);
_bones["UpperArm_R"].RotateX(pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2);
_player.Camera.Camera.RotateX(pitch * (1 - PitchFactorLowerBody - PitchFactorUpperBody - PitchFactorNeck - PitchFactorHead));
const float PitchFactorNeck = 0.25f;
const float PitchFactorHead = 0.35f;
_bones["LowerBody" ].RotateX( pitch * PitchFactorLowerBody);
_bones["UpperBody" ].RotateX(-pitch * PitchFactorUpperBody);
_bones["Neck" ].RotateX(-pitch * PitchFactorNeck);
_bones["Head" ].RotateX(-pitch * PitchFactorHead);
_bones["UpperArm_L"].RotateX( pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2);
_bones["UpperArm_R"].RotateX( pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2);
camera?.RotateX(pitch * (1 - PitchFactorLowerBody - PitchFactorUpperBody - PitchFactorNeck - PitchFactorHead));
const float YawFactorLowerBody = 0.06f;
const float YawFactorUpperBody = 0.18f;
const float YawFactorNeck = 0.2f;
const float YawFactorHead = 0.3f;
const float YawFactorNeck = 0.2f;
const float YawFactorHead = 0.3f;
var yaw = _player.Camera.CurrentYaw;
_bones["LowerBody"].GlobalRotate(Vector3.Up, yaw * YawFactorLowerBody);
_bones["UpperBody"].GlobalRotate(Vector3.Up, yaw * YawFactorUpperBody);
_bones["Neck"].GlobalRotate(Vector3.Up, yaw * YawFactorNeck);
_bones["Head"].GlobalRotate(Vector3.Up, yaw * YawFactorHead);
_player.Camera.Camera.GlobalRotate(Vector3.Up, yaw * (1 - YawFactorLowerBody - YawFactorUpperBody - YawFactorNeck - YawFactorHead));
// How much of the "ideal" camera rotation (rather than animation rotation) should be applied.
const float CameraFactorIdealPitch = 0.7f;
const float CameraFactorIdealYaw = 0.8f;
const float CameraFactorIdealRoll = 0.9f;
var global_yaw = _player.Rotation.Y + yaw;
var cameraRotation = _player.Camera.Camera.GlobalRotation;
cameraRotation.X = LerpAngle(cameraRotation.X, pitch, CameraFactorIdealPitch);
cameraRotation.Y = LerpAngle(cameraRotation.Y, global_yaw, CameraFactorIdealYaw);
cameraRotation.Z = LerpAngle(cameraRotation.Z, 0, CameraFactorIdealRoll);
_player.Camera.Camera.GlobalRotation = cameraRotation;
_bones["Neck" ].GlobalRotate(Vector3.Up, yaw * YawFactorNeck);
_bones["Head" ].GlobalRotate(Vector3.Up, yaw * YawFactorHead);
camera?.GlobalRotate(Vector3.Up, yaw * (1 - YawFactorLowerBody - YawFactorUpperBody - YawFactorNeck - YawFactorHead));
if (camera != null) {
// How much of the "ideal" camera rotation (rather than animation rotation) should be applied.
const float CameraFactorIdealPitch = 0.7f;
const float CameraFactorIdealYaw = 0.8f;
const float CameraFactorIdealRoll = 0.9f;
var globalYaw = yaw + _player.Rotation.Y;
var rot = camera.GlobalRotation;
// FIXME: This doesn't apply correctly when looking up or down.
rot.X = LerpAngle(rot.X, pitch, CameraFactorIdealPitch);
rot.Y = LerpAngle(rot.Y, globalYaw, CameraFactorIdealYaw);
rot.Z = LerpAngle(rot.Z, 0, CameraFactorIdealRoll);
camera.GlobalRotation = rot;
}
}
void HandleWalkingAnimation(double delta)
{
var input = Input.GetVector("move_strafe_left", "move_strafe_right", "move_forward", "move_back");
var isOnFloor = _player.Movement.TimeSinceOnFloor < 0.25f;
var isMoving = _player.Movement.RealMoveSpeed > 0.01f;
var isMovingForward = input.Y <= 0;
const float ForwardAngle = 95.0f;
var movement = _player.Movement;
var localAngle = movement.LocalMoveAngle;
var isOnFloor = movement.TimeSinceOnFloor < 0.25f;
var isMovingForward = Abs(localAngle) <= DegToRad(ForwardAngle);
var walkState = (isOnFloor && isMoving) ? "move" : "idle";
var walkState = (isOnFloor && movement.IsMoving) ? "move" : "idle";
var walkDirection = isMovingForward ? "forward" : "backward";
var walkSpeed = _player.Movement.RealMoveSpeed / _player.Movement.MaxSpeed;
var targetBodyYaw = -(isMovingForward ? Vector2.Up : Vector2.Down).AngleTo(input);
var walkSpeed = movement.LocalMoveVector.Length() / movement.MaxSpeed;
_animTree.Set("parameters/walk_state/transition_request", walkState);
_animTree.Set("parameters/walk_direction/transition_request", walkDirection);
@ -127,15 +134,21 @@ public partial class AnimationController : Node3D, IInitalizable<Player>
var prevWalkSpeed = (float)_animTree.Get("parameters/walk_speed/blend_amount");
_animTree.Set("parameters/walk_speed/blend_amount", Lerp(prevWalkSpeed, walkSpeed, 10 * (float)delta));
const float YAW_FACTOR_LOWER_BODY = 0.25f;
const float YAW_FACTOR_UPPER_BODY = 0.25f;
const float YAW_FACTOR_NECK = 0.50f;
_bodyYaw += (targetBodyYaw - _bodyYaw) * (float)delta * 6;
_bones["Root"].GlobalRotate(Vector3.Up, _bodyYaw);
_bones["LowerBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_LOWER_BODY);
_bones["UpperBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_UPPER_BODY);
_bones["Neck"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_NECK);
const float YawFactorLowerBody = 0.15f;
const float YawFactorUpperBody = 0.20f;
const float YawFactorNeck = 0.45f;
if (movement.IsMoving) {
var targetBodyYaw = localAngle;
if (!isMovingForward) targetBodyYaw -= Sign(localAngle) * Tau / 2;
_bodyYaw += (targetBodyYaw - _bodyYaw) * (float)delta * 6;
} else
_bodyYaw -= _bodyYaw * (float)delta * 2;
// FIXME: Something is causing `_bodyYaw` to jitter when a player is pushed against an object.
_bones["Root" ].GlobalRotate(Vector3.Up, _bodyYaw * (YawFactorLowerBody + YawFactorUpperBody + YawFactorNeck));
_bones["LowerBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YawFactorLowerBody);
_bones["UpperBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YawFactorUpperBody);
_bones["Neck" ].GlobalRotate(Vector3.Up, -_bodyYaw * YawFactorNeck);
}
}

@ -1,18 +1,34 @@
public partial class CameraController : Node
{
[Export] public Camera3D Camera { get; set; }
[Export] public Camera3D Camera { get; set; } // Will be `null` for remote players.
[Export] public Vector2 MouseSensitivity { get; set; } = new(0.2f, 0.2f); // Degrees per pixel.
[Export] public float PitchMinimum { get; set; } = -85;
[Export] public float PitchMaximum { get; set; } = 85;
public Transform3D DefaultTransform { get; private set; }
public float CurrentPitch { get; set; }
public float CurrentYaw { get; set; }
public static bool IsMouseCaptured
=> Input.MouseMode == Input.MouseModeEnum.Captured;
Player _player;
public override void _Ready()
{
_player = GetParent<Player>();
if (_player.IsLocal) {
DefaultTransform = Camera.Transform;
} else {
Camera.QueueFree();
Camera = null;
}
}
public override void _UnhandledInput(InputEvent @event)
{
if (!_player.IsLocal) return;
if (@event.IsActionPressed("ui_cancel") && IsMouseCaptured) {
// When escape is pressed, release the mouse.
Input.MouseMode = Input.MouseModeEnum.Visible;

@ -1,4 +1,4 @@
public partial class MovementController : Node, IInitalizable<Player>
public partial class MovementController : Node
{
[ExportGroup("Movement")]
[Export] public float Acceleration { get; set; } = 4.0f;
@ -8,19 +8,30 @@ public partial class MovementController : Node, IInitalizable<Player>
public float Gravity { get; } = (float)ProjectSettings.GetSetting("physics/3d/default_gravity");
[ExportGroup("Jumping")]
[Export] public float JumpVelocity { get; set; } = 4.0f;
[Export] public float JumpEarlyTime { get; set; } = 0.0f; // Time (in seconds) after pressing the jump button a jump may occur late.
[Export] public float JumpCoyoteTime { get; set; } = 0.0f; // Time (in seconds) after leaving a jumpable surface when a jump may still occur.
[Export] public float JumpVelocity { get; set; } = 4.0f;
/// <summary> Time (in seconds) after pressing the jump button a jump may occur late. </summary>
[Export] public float JumpEarlyTime { get; set; } = 0.0f;
/// <summary> Time (in seconds) after leaving a jumpable surface when a jump may still occur. </summary>
[Export] public float JumpCoyoteTime { get; set; } = 0.0f;
public float RealMoveSpeed { get; private set; }
public bool IsSprinting { get; private set; }
/// <summary> The raw input movement vector with a maximum length of 1. </summary>
public Vector2 InputVector { get; private set; }
public bool IsMoving => LocalMoveVector.Length() > 0.01f;
/// <summary> The actual amount the player is moving, relative to the world. Y is always 0. </summary>
public Vector3 GlobalMoveVector { get; private set; }
/// <summary> The actual amount the player is moving, relative to the player's viewpoint. Y is always 0. </summary>
public Vector3 LocalMoveVector { get; private set; }
/// <summary> </summary>
public float LocalMoveAngle { get; private set; }
public float TimeSinceJumpPressed { get; private set; } = float.PositiveInfinity;
public float TimeSinceOnFloor { get; private set; } = float.PositiveInfinity;
Player _player;
public void Initialize(Player player)
=> _player = player;
public override void _Ready()
=> _player = GetParent<Player>();
public override void _UnhandledInput(InputEvent @event)
{
@ -30,23 +41,23 @@ public partial class MovementController : Node, IInitalizable<Player>
public override void _PhysicsProcess(double delta)
{
var velocity = _player.Velocity;
// velocity.Y -= Gravity * (float)delta; // TODO: Gravity.
// Get the (normalized) movement vector from the current input.
var input = Input.GetVector("move_strafe_left", "move_strafe_right", "move_forward", "move_back");
InputVector = _player.IsLocal
? Input.GetVector("move_strafe_left", "move_strafe_right", "move_forward", "move_back")
: Vector2.Zero;
var velocity = _player.Velocity;
var horVelocity = velocity with { Y = 0 };
// TODO: Gravity.
// velocity.Y -= Gravity * (float)delta;
var basis = _player.Basis.Rotated(Vector3.Up, _player.Camera.CurrentYaw);
var target = basis * new Vector3(input.X, 0, input.Y) * MaxSpeed;
var target = basis * new Vector3(InputVector.X, 0, InputVector.Y) * MaxSpeed;
var isMoving = target.Dot(horVelocity) > 0.0f;
var isOnFloor = true; // _player.IsOnFloor();
var accel = isMoving ? Acceleration
: isOnFloor ? FrictionFloor
: FrictionAir;
: isOnFloor ? FrictionFloor
: FrictionAir;
if (IsSprinting) {
target *= 5;
@ -68,6 +79,9 @@ public partial class MovementController : Node, IInitalizable<Player>
_player.Velocity = velocity;
_player.MoveAndSlide();
RealMoveSpeed = (_player.Velocity with { Y = 0 }).Length();
// TODO: Very simplified, but works for now.
GlobalMoveVector = _player.Velocity with { Y = 0 };
LocalMoveVector = _player.Basis.Inverse() * GlobalMoveVector;
LocalMoveAngle = Vector3.Forward.SignedAngleTo(LocalMoveVector, Vector3.Up);
}
}

@ -1,4 +1,4 @@
public partial class PickupController : Node3D, IInitalizable<Player>
public partial class PickupController : Node3D
{
public Item CurrentItem { get; private set; }
public bool IsCurrentItemHeld { get; private set; }
@ -7,16 +7,19 @@ public partial class PickupController : Node3D, IInitalizable<Player>
[Export] public Camera3D Camera { get; set; }
[Export] public float PickupDistance { get; set; } = 2.0f;
Player _player;
Node3D _world;
public void Initialize(Player player)
public override void _Ready()
{
_player = GetParent<Player>();
// TODO: Find a better way to find the world.
// For now we just use the parent of the `Player` object.
_world = player.GetParent<Node3D>();
_world = _player.GetParent<Node3D>();
}
public override void _UnhandledInput(InputEvent @event)
{
if (!_player.IsLocal) return;
EnsureCurrentItemValid();
if (CurrentItem == null) return;
@ -55,6 +58,7 @@ public partial class PickupController : Node3D, IInitalizable<Player>
public override void _PhysicsProcess(double delta)
{
if (!_player.IsLocal) return;
EnsureCurrentItemValid();
if (IsCurrentItemHeld) {

@ -1,24 +1,17 @@
public partial class Player : CharacterBody3D
{
[Export] public bool IsLocal { get; set; } = true;
public MovementController Movement { get; private set; }
public CameraController Camera { get; private set; }
public AnimationController Animation { get; private set; }
public PickupController Pickup { get; private set; }
public override void _Ready()
public override void _EnterTree()
{
Movement = GetNode<MovementController>("MovementController");
Camera = GetNode<CameraController>("CameraController");
Animation = GetNode<AnimationController>("AnimationController");
Pickup = GetNode<PickupController>("PickupController");
foreach (var child in GetChildren())
if (child is IInitalizable<Player> init)
init.Initialize(this);
}
}
public interface IInitalizable<T>
{
void Initialize(T param);
}

@ -0,0 +1,23 @@
public partial class PushbackArea : Area3D
{
[Export] public float PushForce { get; set; } = 24.0f;
Player _player;
float _radius;
public override void _Ready()
{
_player = GetParent<Player>();
_radius = ((CapsuleShape3D)GetNode<CollisionShape3D>("CollisionShape3D").Shape).Radius;
}
public override void _PhysicsProcess(double delta)
{
foreach (var area in GetOverlappingAreas()) {
var offset = (GlobalPosition - area.GlobalPosition) with { Y = 0 };
var directions = offset.Normalized();
var distance = offset.Length() / (_radius * 2);
var force = (1 - distance) * PushForce * (float)delta;
_player.Velocity += directions * force;
}
}
}

@ -1,14 +1,19 @@
[gd_scene load_steps=22 format=3 uid="uid://dmd7w2r8s0x6y"]
[gd_scene load_steps=24 format=3 uid="uid://dmd7w2r8s0x6y"]
[ext_resource type="PackedScene" uid="uid://bfh3eqgywr0ul" path="res://assets/models/character.blend" id="1_3qh37"]
[ext_resource type="Script" path="res://player/Player.cs" id="1_a0mas"]
[ext_resource type="Script" path="res://player/MovementController.cs" id="2_1pst4"]
[ext_resource type="Script" path="res://player/PushbackArea.cs" id="2_almik"]
[ext_resource type="Script" path="res://player/PickupController.cs" id="2_ns2pe"]
[ext_resource type="Script" path="res://player/CameraController.cs" id="2_r3gna"]
[ext_resource type="Script" path="res://player/AnimationController.cs" id="3_5rlwc"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_h1mfd"]
radius = 0.3
radius = 0.24
height = 1.5
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_l8s0f"]
radius = 0.28
height = 1.5
[sub_resource type="Animation" id="Animation_arrr6"]
@ -806,39 +811,47 @@ script = ExtResource("1_a0mas")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_h1mfd")
[node name="PushbackArea" type="Area3D" parent="."]
collision_layer = 4
collision_mask = 4
script = ExtResource("2_almik")
[node name="CollisionShape3D" type="CollisionShape3D" parent="PushbackArea"]
shape = SubResource("CapsuleShape3D_l8s0f")
[node name="Model" parent="." instance=ExtResource("1_3qh37")]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, -0.75, 0)
[node name="Root" type="BoneAttachment3D" parent="Model/Skeleton" index="0"]
transform = Transform3D(-1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0.199954, 0)
transform = Transform3D(-1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0.198674, 0)
bone_name = "Root"
bone_idx = 2
use_external_skeleton = true
external_skeleton = NodePath("../Skeleton3D")
[node name="LowerBody" type="BoneAttachment3D" parent="Model/Skeleton/Root"]
transform = Transform3D(-1, -1.45235e-11, 8.74228e-08, 8.71645e-08, 0.0766475, 0.997058, -6.71523e-09, 0.997058, -0.0766476, 0, 0, -0.199593)
transform = Transform3D(-1, -1.80478e-09, 8.74042e-08, 8.71645e-08, 0.0562133, 0.998419, -6.71521e-09, 0.998419, -0.0562134, 0, 0, -0.199593)
bone_name = "LowerBody"
bone_idx = 3
use_external_skeleton = true
external_skeleton = NodePath("../../Skeleton3D")
[node name="UpperBody" type="BoneAttachment3D" parent="Model/Skeleton/Root/LowerBody"]
transform = Transform3D(1, -1.0796e-08, 8.67536e-08, 0, 0.992346, 0.123492, -8.74228e-08, -0.123492, 0.992346, 8.88178e-16, 0.154362, 7.45058e-09)
transform = Transform3D(1, -7.15076e-09, 8.71298e-08, 0, 0.996649, 0.0817951, -8.74228e-08, -0.0817951, 0.996649, 0, 0.154362, 0)
bone_name = "UpperBody"
bone_idx = 4
use_external_skeleton = true
external_skeleton = NodePath("../../../Skeleton3D")
[node name="Neck" type="BoneAttachment3D" parent="Model/Skeleton/Root/LowerBody/UpperBody"]
transform = Transform3D(1, -8.30499e-17, 1.42109e-14, -1.33227e-15, 0.998891, -0.0470728, 7.10543e-15, 0.0470728, 0.998891, 2.22045e-16, 0.251888, -1.11759e-08)
transform = Transform3D(1, 2.22045e-16, 0, 8.88178e-16, 0.998891, -0.0470728, -7.10543e-15, 0.0470728, 0.998892, 6.66134e-16, 0.251888, 0)
bone_name = "Neck"
bone_idx = 5
use_external_skeleton = true
external_skeleton = NodePath("../../../../Skeleton3D")
[node name="Head" type="BoneAttachment3D" parent="Model/Skeleton/Root/LowerBody/UpperBody/Neck"]
transform = Transform3D(-1, 1.13687e-12, 8.74228e-08, 8.74228e-08, 1.31093e-05, 1, -7.10543e-15, 1, -1.32285e-05, -2.22045e-16, 0.101598, 1.86265e-09)
transform = Transform3D(-1, 4.67566e-10, 8.74215e-08, 8.74228e-08, 0.0053482, 0.999986, 0, 0.999986, -0.00534832, 1.11022e-16, 0.101598, 3.72529e-09)
bone_name = "Head"
bone_idx = 6
use_external_skeleton = true
@ -849,38 +862,38 @@ transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.0
cull_mask = 1
[node name="UpperArm_L" type="BoneAttachment3D" parent="Model/Skeleton/Root/LowerBody/UpperBody"]
transform = Transform3D(-0.939275, 0.343167, -1.43629e-05, -0.342785, -0.938234, -0.0470729, -0.0161673, -0.0442095, 0.998891, 0.0873834, 0.213866, -0.00179178)
transform = Transform3D(-0.949823, 0.312787, -0.000684065, -0.31241, -0.948781, -0.0470616, -0.0153693, -0.0444865, 0.998892, 0.0873834, 0.213866, -0.00179177)
bone_name = "UpperArm_L"
bone_idx = 7
use_external_skeleton = true
external_skeleton = NodePath("../../../../Skeleton3D")
[node name="UpperArm_R" type="BoneAttachment3D" parent="Model/Skeleton/Root/LowerBody/UpperBody"]
transform = Transform3D(-0.939275, -0.343167, 1.43629e-05, 0.342785, -0.938234, -0.0470729, 0.0161673, -0.0442095, 0.998891, -0.0873834, 0.213866, -0.00179178)
transform = Transform3D(-0.949823, -0.312787, 0.000684064, 0.31241, -0.948781, -0.0470616, 0.0153693, -0.0444865, 0.998892, -0.0873834, 0.213866, -0.00179177)
bone_name = "UpperArm_R"
bone_idx = 14
use_external_skeleton = true
external_skeleton = NodePath("../../../../Skeleton3D")
[node name="Skeleton3D" parent="Model/Skeleton" index="1"]
bones/1/rotation = Quaternion(-0.707263, 2.19513e-18, -2.07659e-18, 0.706951)
bones/2/position = Vector3(0, 0.199954, 0)
bones/3/rotation = Quaternion(2.96951e-08, 0.733706, 0.679468, 3.20762e-08)
bones/4/rotation = Quaternion(-0.0618643, 4.36277e-08, 2.70417e-09, 0.998085)
bones/6/rotation = Quaternion(3.09088e-08, 0.707111, 0.707102, 3.09084e-08)
bones/7/rotation = Quaternion(-0.00410941, -0.0231815, 0.984429, -0.174201)
bones/8/rotation = Quaternion(2.06571e-06, 7.0899e-06, -0.0625704, 0.998041)
bones/9/rotation = Quaternion(-1.49484e-06, -6.92559e-06, -0.0178983, 0.99984)
bones/14/rotation = Quaternion(0.00410941, -0.0231815, 0.984429, 0.174201)
bones/15/rotation = Quaternion(2.06571e-06, -7.08988e-06, 0.0625704, 0.998041)
bones/16/rotation = Quaternion(-1.49484e-06, 6.92559e-06, 0.0178983, 0.99984)
bones/21/rotation = Quaternion(0.00988475, -0.701685, 0.712355, 0.00956142)
bones/22/rotation = Quaternion(0.0133306, 0.00254896, 0.000813956, 0.999908)
bones/23/rotation = Quaternion(-0.000983995, -0.692252, 0.721401, -0.019142)
bones/24/rotation = Quaternion(-0.00988476, -0.701685, 0.712355, -0.00956141)
bones/25/rotation = Quaternion(0.0133306, -0.00254896, -0.000813955, 0.999908)
bones/26/rotation = Quaternion(0.000983995, -0.692252, 0.721401, 0.019142)
bones/28/rotation = Quaternion(-0.707263, 2.19513e-18, -2.07659e-18, 0.706951)
bones/1/rotation = Quaternion(-0.725527, 1.06167e-18, -1.00434e-18, 0.688194)
bones/2/position = Vector3(0, 0.198675, 0)
bones/3/rotation = Quaternion(2.93651e-08, 0.72671, 0.686945, 3.23786e-08)
bones/4/rotation = Quaternion(-0.0409319, 4.36748e-08, 1.78919e-09, 0.999162)
bones/6/rotation = Quaternion(3.09912e-08, 0.708995, 0.705213, 3.08259e-08)
bones/7/rotation = Quaternion(-0.00406577, -0.0231861, 0.987104, -0.158341)
bones/8/rotation = Quaternion(9.74191e-05, 0.000328126, -0.0786104, 0.996905)
bones/9/rotation = Quaternion(-7.20592e-05, -0.0003409, -0.00150931, 0.999999)
bones/14/rotation = Quaternion(0.00406577, -0.0231861, 0.987104, 0.158341)
bones/15/rotation = Quaternion(9.74189e-05, -0.000328126, 0.0786104, 0.996905)
bones/16/rotation = Quaternion(-7.20589e-05, 0.0003409, 0.00150931, 0.999999)
bones/21/rotation = Quaternion(0.0107169, -0.719663, 0.694155, 0.0108845)
bones/22/rotation = Quaternion(0.0628015, 0.00254414, 0.0038346, 0.998015)
bones/23/rotation = Quaternion(-0.00149249, -0.672831, 0.739548, -0.0191091)
bones/24/rotation = Quaternion(-0.0107169, -0.719663, 0.694155, -0.0108845)
bones/25/rotation = Quaternion(0.0628015, -0.00254414, -0.0038346, 0.998015)
bones/26/rotation = Quaternion(0.00149248, -0.672831, 0.739548, 0.0191091)
bones/28/rotation = Quaternion(-0.725527, 1.06167e-18, -1.00434e-18, 0.688194)
[node name="MovementController" type="Node" parent="."]
script = ExtResource("2_1pst4")

@ -31,6 +31,10 @@ transform = Transform3D(0.866025, 0, -0.5, 0.25, 0.866025, 0.433013, 0.433013, -
[node name="Player" parent="." instance=ExtResource("1_cxvln")]
[node name="OtherPlayer" parent="." instance=ExtResource("1_cxvln")]
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, 2, 0.75, -4)
IsLocal = false
[node name="Crates" type="Node3D" parent="."]
[node name="Crate1" parent="Crates" instance=ExtResource("2_j6a20")]

Loading…
Cancel
Save