Skip to content

Instantly share code, notes, and snippets.

@ElliotWood
Created March 28, 2013 02:23
Show Gist options
  • Save ElliotWood/5260019 to your computer and use it in GitHub Desktop.
Save ElliotWood/5260019 to your computer and use it in GitHub Desktop.
Fast Data Sync - Technical Specification
First you define some data. This will be the data that will define how one player differs to another.
class PlayerDetails {
var TotalHP : float = 100.0;
var HP : float = 100.0;
var EXP : int = 0;
var jumpSpeed:float = 8.0;
var runSpeed:float = 5.0;
var attackSpeed: float = 1.0;
var currentSpell: int = 0;
var selectedTarget : NetworkViewID = NetworkViewID.unassigned ;
}
Next create a script that we can add to a Network Player Prefab. I called mine NetworkSyncPlayer.js
public var localPlayer : PlayerDetails;
function Start()
{
//Create the Player Details
localPlayer = new PlayerDetails();
}
function OnSerializeNetworkView(stream : BitStream, info : NetworkMessageInfo)
{
if(stream.isWriting) //Am I server
{
stream.Serialize(localPlayer.HP);
stream.Serialize(localPlayer.TotalHP);
stream.Serialize(localPlayer.EXP);
stream.Serialize(localPlayer.jumpSpeed);
stream.Serialize(localPlayer.runSpeed);
stream.Serialize(localPlayer.attackSpeed);
stream.Serialize(localPlayer.currentSpell);
stream.Serialize(localPlayer.selectedTarget);
}
else //or client
{
localPlayer = new PlayerDetails();
stream.Serialize(localPlayer.HP);
stream.Serialize(localPlayer.TotalHP);
stream.Serialize(localPlayer.EXP);
stream.Serialize(localPlayer.jumpSpeed);
stream.Serialize(localPlayer.runSpeed);
stream.Serialize(localPlayer.attackSpeed);
stream.Serialize(localPlayer.currentSpell);
stream.Serialize(localPlayer.selectedTarget);
}
}
This will keep clients up to date with the server.
If your properties affect other scripts you can pass them or read them in the Late Update function.
function LateUpdate()
{
//Dont let Hp exceed the total.
if(localPlayer.HP > localPlayer.TotalHP)
{
localPlayer.HP = localPlayer.TotalHP;
}
//Check if we dead.
else if (localPlayer.HP <= 0)
{
//Detonate();
}
//Out Values
characterController.jumpSpeed = localPlayer.jumpSpeed;
characterController.runSpeed = localPlayer.runSpeed;
characterController.attackSpeed = localPlayer.attackSpeed;
//In Values
localPlayer.currentSpell = characterController.currentSpell;
localPlayer.selectedTarget = characterController.selectedTarget;
}
And last but not least this script is where you declare methods that will modify the data; you can wrap these methods with Network.isServer to ensure the server modifies the data and not the clients.
function ApplyDamage (damage : float) {
if(Network.isServer)
{
// We already have less than 0 HP, maybe we got killed already?
if (localPlayer.HP <= 0)
return;
//Take the damage
localPlayer.HP -= damage;
//Animate getting hit
animation.CrossFade("gothit");
//Tell the NetworkSyncAnimation
SendMessage("SyncAnimation", "gothit");
}
}
function ApplyHeal (heal : float) {
if(Network.isServer)
{
// We already have less than 0 HP, maybe we got killed already?
if (localPlayer.HP <= 0)
return;
if(localPlayer.HP < localPlayer.TotalHP)
{
localPlayer.HP += heal;
}
//Animate getting healed
animation.CrossFade("gothealed");
//Tell the NetworkSyncAnimation
SendMessage("SyncAnimation", " gothealed ");
}
}
Conclusion:
Give this script a network view and add it to each local spawned player on the server and the clients.
First we declare our base stats and values for movement
public var jumpSpeed:float;
public var runSpeed:float;
public var attackSpeed: float;
public var currentSpell: int;
public var selectedTarget: NetworkViewID;
public var rotationAngle: int;
private var gravity = 20.0;
private var rotateSpeed =150.0;
private var walkSpeed = 1.0;
private var moveSpeed = 0.0;
private var moveDirection:Vector3 = Vector3.zero;
private var isWalking:boolean = false;
Next we declare our input variables.
public var verticalInput : float;
public var horizontalInput : float;
public var mouseLeft : boolean;
public var mouseRight: boolean;
public var jumpButton : boolean;
public var fireButton : boolean;
And a flag to enable/disable them
public var getUserInput : boolean = false;
Now for our update function, this is the section that will consume the variables.
function Update ()
{
//************CLIENT****************//
if(getUserInput)
{
// Sample user input
verticalInput = Input.GetAxisRaw("Vertical");
horizontalInput = Input.GetAxisRaw("Horizontal");
jumpButton = Input.GetButton("Jump");
mouseLeft = Input.GetMouseButton(0);
mouseRight = Input.GetMouseButton(1);
fireButton = Input.GetButton("Fire1");
rotationAngle = Camera.main.transform.eulerAngles.y;
// Toggle walking/running with the T key
if(Input.GetKeyDown("t"))
isWalking = !isWalking;
}
}
The code above will be the responsibility of the client to compute and set these variables so the rest of the controller can move your character around.
We only want player to be able to move when on the ground so add the following variables to our declarations
private var grounded:boolean = false;
private var groundedTimeout = 0.25;
private var lastGroundedTime = 0.0;
Now add the following to the bottom of the update function.
//************CLIENT AND SERVER****************//
// Only allow movement and jumps while grounded
if(grounded)
{
lastGroundedTime = Time.time;
moveDirection = new Vector3((mouseRight ? horizontalInput : 0),0, ((mouseRight && mouseLeft) ? (verticalInput == 0 ? 1 : verticalInput) : verticalInput));
// if moving forward and to the side at the same time, compensate for distance
if(mouseRight && horizontalInput && verticalInput) {
moveDirection *= .7;
}
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= isWalking ? walkSpeed : runSpeed;
// Jump!
if(jumpButton)
{
moveDirection.y = jumpSpeed;
lastJumpButtonTime = Time.time;
}
}
At this point your character will be able to move backwards/forwards/Left/Right but will not be able to rotate.
So next we add.
// Allow turning at anytime. Keep the character facing in the same direction as the Camera if the right mouse button is down.
if(mouseRight) {
transform.rotation = Quaternion.Euler(0,rotationAngle,0);
}else {
transform.Rotate(0,horizontalInput * rotateSpeed * Time.deltaTime, 0);
}
This will facilitate the rotating with mouse (rotation angle) or with keys(horizontalInput * rotateSpeed)
Next we add gravity.
//Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
Last but not least we update the base unity character controller and set the grounded flag.
//Move controller
var controller:CharacterController = GetComponent(CharacterController);
var flags = controller.Move(moveDirection * Time.deltaTime);
grounded = (flags & CollisionFlags.Below) != 0;
First we declare our base stats and values for movement
public var jumpSpeed:float;
public var runSpeed:float;
public var attackSpeed: float;
public var currentSpell: int;
public var selectedTarget: NetworkViewID;
public var rotationAngle: int;
private var gravity = 20.0;
private var rotateSpeed =150.0;
private var walkSpeed = 1.0;
private var moveSpeed = 0.0;
private var moveDirection:Vector3 = Vector3.zero;
private var isWalking:boolean = false;
Next we declare our input variables.
public var verticalInput : float;
public var horizontalInput : float;
public var mouseLeft : boolean;
public var mouseRight: boolean;
public var jumpButton : boolean;
public var fireButton : boolean;
And a flag to enable/disable them
public var getUserInput : boolean = false;
Now for our update function, this is the section that will consume the variables.
function Update ()
{
//************CLIENT****************//
if(getUserInput)
{
// Sample user input
verticalInput = Input.GetAxisRaw("Vertical");
horizontalInput = Input.GetAxisRaw("Horizontal");
jumpButton = Input.GetButton("Jump");
mouseLeft = Input.GetMouseButton(0);
mouseRight = Input.GetMouseButton(1);
fireButton = Input.GetButton("Fire1");
rotationAngle = Camera.main.transform.eulerAngles.y;
// Toggle walking/running with the T key
if(Input.GetKeyDown("t"))
isWalking = !isWalking;
}
}
The code above will be the responsibility of the client to compute and set these variables so the rest of the controller can move your character around.
We only want player to be able to move when on the ground so add the following variables to our declarations
private var grounded:boolean = false;
private var groundedTimeout = 0.25;
private var lastGroundedTime = 0.0;
Now add the following to the bottom of the update function.
//************CLIENT AND SERVER****************//
// Only allow movement and jumps while grounded
if(grounded)
{
lastGroundedTime = Time.time;
moveDirection = new Vector3((mouseRight ? horizontalInput : 0),0, ((mouseRight && mouseLeft) ? (verticalInput == 0 ? 1 : verticalInput) : verticalInput));
// if moving forward and to the side at the same time, compensate for distance
if(mouseRight && horizontalInput && verticalInput) {
moveDirection *= .7;
}
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= isWalking ? walkSpeed : runSpeed;
// Jump!
if(jumpButton)
{
moveDirection.y = jumpSpeed;
lastJumpButtonTime = Time.time;
}
}
At this point your character will be able to move backwards/forwards/Left/Right but will not be able to rotate.
So next we add.
// Allow turning at anytime. Keep the character facing in the same direction as the Camera if the right mouse button is down.
if(mouseRight) {
transform.rotation = Quaternion.Euler(0,rotationAngle,0);
}else {
transform.Rotate(0,horizontalInput * rotateSpeed * Time.deltaTime, 0);
}
This will facilitate the rotating with mouse (rotation angle) or with keys(horizontalInput * rotateSpeed)
Next we add gravity.
//Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
Last but not least we update the base unity character controller and set the grounded flag.
//Move controller
var controller:CharacterController = GetComponent(CharacterController);
var flags = controller.Move(moveDirection * Time.deltaTime);
grounded = (flags & CollisionFlags.Below) != 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment