Created
March 28, 2013 02:23
-
-
Save ElliotWood/5260019 to your computer and use it in GitHub Desktop.
Fast Data Sync - Technical Specification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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