The [SyncVar] attribute is not working for me in my game. I have made sure that:
I changed the variable with a command function
I correctly added the syncvar attribute and the hook
The client can update the variables on the server, but the server is not updating the variable on the client
Here are my scripts:
Player Shooting Script:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class PlayerShoot : NetworkBehaviour {
public GameObject shootPosition;
public float shootRange = 100;
public float shootRate = 0.2f;
float nextCheck;
public int damage = 10;
// Use this for initialization
void Start () {
}
void DetectShooting(){
if (Time.time > nextCheck && Input.GetMouseButton(0)) {
nextCheck = Time.time + shootRate;
CmdShoot ();
}
}
[Command]
void CmdShoot(){
RaycastHit hit;
Ray bulletDirection = new Ray (shootPosition.transform.position, transform.forward * shootRange);
Debug.DrawRay (shootPosition.transform.position, transform.forward * shootRange, Color.blue, 10.0f);
if (Physics.Raycast (bulletDirection, out hit, 100)) {
print (hit.transform.name);
if (hit.transform.CompareTag ("Player")) {
hit.transform.GetComponent<PlayerHealth> ().DeductHealth (damage);
}
}
}
// Update is called once per frame
void Update () {
print (isLocalPlayer);
if (isLocalPlayer)
DetectShooting ();
}
}
Player Health Script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Networking;
public class PlayerHealth : NetworkBehaviour {
public static int maxHealth = 100;
[SyncVar (hook ="UpdateUI")]
public int currentHealth = maxHealth;
public Slider healthBar;
void UpdateUI(int hp){
healthBar.value = currentHealth;
}
public void DeductHealth(int damage){
if (isServer)
currentHealth -= damage;
}
// Use this for initialization
void Start () {
//InvokeRepeating ("DeductHealth", 0, 2);
SetInitialReferences ();
}
void SetInitialReferences(){
}
// Update is called once per frame
void Update () {
}
}
Here are some Screen Shots:
Since you are hooking the SyncVar with function, you need to pass the variable manually (and do other stuff you wish to do with the new value like checking if hp <= 0).
void UpdateUI(int hp){
currentHealth = hp;
healthBar.value = currentHealth;
}
Related
I want to add 1 to a variable meters when ever 1 seconds passed. Task.Delay wont work for some reason.
Here is all my code. Unfortunely im only a beginner at csharp so if you want make you can give me feedback on how to make it better.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public int movementSpeed = 6;
private Rigidbody2D rb;
//the variable i want to add 1 to:
public int meters;
public double speeding = 5;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
Ymovement();
void Ymovement()
{
var movement = Input.GetAxis("Vertical");
transform.position += new Vector3(0, movement, 0) * Time.deltaTime * movementSpeed;
}
}
}
This is a pretty typical use case for InvokeRepeating:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public int movementSpeed = 6;
private Rigidbody2D rb;
//the variable i want to add 1 to:
public int meters;
public double speeding = 5;
void Start()
{
rb = GetComponent<Rigidbody2D>();
InvokeRepeating("IncreaseMeters", 1f, 1f);
}
void Update()
{
Ymovement();
}
void Ymovement()
{
var movement = Input.GetAxis("Vertical");
transform.position += new Vector3(0, movement, 0) * Time.deltaTime * movementSpeed;
}
void IncreaseMeters()
{
meters += 1;
}
}
I'm new to Unity and together with a few friends, I try to make a game. I was trying to connect the healthbar I made to the damage u can deal by shooting knifes. First to test this I used:
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
TakeDamage(25);
}
}
Everything worked fine and when I pressed Mouse1 the healthbar worked.My goal was, that when a knife hits the enemy 25 damage is dealt and the healthbar shows that the enemy lost health. However, when the knifes hit the enemy nothing happens. Can you please help me because I tried fixing this for like 3 hours and I'm getting kinda frustrated. Thank you.
Here's the code for the healthbar:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class healthbar : MonoBehaviour
{
public Slider slider;
public void SetMaxHealth(int health)
{
slider.maxValue = health;
slider.value = health;
}
public void SetHealth(int health)
{
slider.value = health;
}
}
And here's the code for the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy_Follow : MonoBehaviour
{
public float speed;
public Transform target;
public int damage = 25;
public int maxHealth = 100;
public int currentHealth;
public healthbar healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
TakeDamage(25);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Knife")
{
TakeDamage(25);
}
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
healthBar.SetHealth(currentHealth);
}
}
After finding out that your colliders are not triggers it should rather be OnCollisionEnter2D like e.g.
public void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Knife"))
{
TakeDamage(25);
}
}
See also Colliders -> Collision Action Matrix
You may try this code to look if the slider works at all. If this code does work (You can change things with the inspector) then it should be an error with the collision/trigger detection and nothing else.
public class SliderTest : MonoBehaviour {
public Slider slider;
public int maxHealth = 100;
private int currentHealth = 100;
public bool resetHealth = false;
public bool damage = false;
void Start() {
slider = GetComponent<Slider>();
SetMaxHealth(maxHealth);
}
void Update() {
if(resetHealth) {
resetHealth = false;
SetHealth(maxHealth);
}
if(damage) {
damage = false;
SetHealth(currentHealth-10);
}
}
public void SetMaxHealth(int health) {
slider.maxValue = health;
slider.value = 100;
}
public void SetHealth(int health) {
currentHealth = health;
slider.value = currentHealth;
}
}
}
I have followed this tutorial multiplayer fps serie from Expressed Unity especially this episode "https://youtu.be/j9PC9RhurRI?list=PLD4OdGjxbaByCEOH3fOJ4MgOdROHHBKUo" and i need some help with it.
I have followed the video till 23:30 and then all sort of things are broken. I get error saying "Can not Instantiate before client joined/created a room. State: Joining." and i dont know what i should to do.
I have checked all the codes and everything but for nothing. Do you have solution? I don't which code have the problem so i copy all three of the codes i have edited following this video.
MpManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.SceneManagement;
public class MPManager : MonoBehaviourPunCallbacks
{
public GameObject[] EnableObjectsOnConnect;
public GameObject[] DisableObjectsOnConnect;
// Start is called before the first frame update
void Start()
{
PhotonNetwork.ConnectUsingSettings();
//PhotonNetwork.ConnectToRegion("eu");
}
public override void OnConnectedToMaster()
{
foreach(GameObject obj in EnableObjectsOnConnect)
{
obj.SetActive(true);
}
foreach(GameObject obj in DisableObjectsOnConnect)
{
obj.SetActive(false);
}
Debug.Log("Connected to photon");
}
public void JoinFFA()
{
PhotonNetwork.AutomaticallySyncScene = true;
PhotonNetwork.JoinRandomRoom();
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
CreateFFA();
}
public void CreateFFA()
{
PhotonNetwork.AutomaticallySyncScene = true;
RoomOptions ro = new RoomOptions { MaxPlayers = 10, IsOpen = true, IsVisible = true };
PhotonNetwork.CreateRoom("defaultFFA", ro, TypedLobby.Default);
SceneManager.LoadScene("FFA");
}
}
Movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon;
using Photon.Pun;
public class Movement : MonoBehaviourPun
{
public KeyCode Left;
public KeyCode Right;
public KeyCode Forward;
public KeyCode Backward;
[SerializeField]
private float MoveSpeed = 50;
private Rigidbody body;
private GameObject cam;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody>();
cam = gameObject.transform.GetChild(0).gameObject;
if (photonView.IsMine)
{
cam.SetActive(true);
}
}
// Update is called once per frame
void Update()
{
if (photonView.IsMine)
{
float x = Input.GetAxis("Mouse X");
float y = Input.GetAxis("Mouse Y");
if (Input.GetKey(Left))
{
body.AddRelativeForce(Vector3.left * MoveSpeed, ForceMode.Impulse);
}
if (Input.GetKey(Right))
{
body.AddRelativeForce(Vector3.left * -MoveSpeed, ForceMode.Impulse);
}
if (Input.GetKey(Forward))
{
body.AddRelativeForce(Vector3.forward * MoveSpeed, ForceMode.Impulse);
}
if (Input.GetKey(Backward))
{
body.AddRelativeForce(Vector3.forward * -MoveSpeed, ForceMode.Impulse);
}
gameObject.transform.Rotate(new Vector3(0, x, 0));
cam.transform.Rotate(new Vector3(-y, 0, 0));
}
}
}
FFa script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon;
using Photon.Pun;
public class FFA : MonoBehaviourPun, IPunObservable
{
public float SpawnTime;
float timer;
bool HasPlayerSpawned = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if(timer >= SpawnTime)
{
if (!HasPlayerSpawned)
{
PhotonNetwork.Instantiate("Player", Vector3.zero, Quaternion.identity, 0);
HasPlayerSpawned = true;
}
timer = 0;
}
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if(stream.IsWriting)
{
}else if (stream.IsReading)
{
}
}
}
Sorry if I had typos my english not good.
Solution found! i just made the spawntime to 1 second instead of 0 so the player had time to join room before instantiating.
How can I edit the c# code to show that player 1 or 2 won when the other player dies. And show the dead player that they lost?
PlayerController Script
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace S3
{
public class PlayerController : NetworkBehaviour {
public GameObject bulletPrefab;
public Transform bulletSpawn;
// Update is called once per frame
void Update ()
{
if (!isLocalPlayer) {
return;
}
float x = Input.GetAxis ("Horizontal") * Time.deltaTime * 150.0f;
float z = Input.GetAxis ("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate (0, x, 0);
transform.Translate (0, 0, z);
if (Input.GetKeyDown (KeyCode.Space))
{
CmdFire();
}
}
[Command]
void CmdFire()
{
GameObject bullet = (GameObject) Instantiate(bulletPrefab, bulletSpawn.position, bulletSpawn.rotation);
bullet.GetComponent<Rigidbody> ().velocity = bullet.transform.forward * 6.0f;
NetworkServer.Spawn(bullet);
Destroy (bullet, 2);
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer> ().material.color = Color.blue;
}
}
}
Health Script
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
namespace S3
{
public class Health : NetworkBehaviour {
public const int maxHealth = 100;
[SyncVar (hook = "OnChangeHealth")]public int currentHealth = maxHealth;
public RectTransform healthbar;
public void TakeDamage(int amount)
{
if (!isServer)
{
return;
}
currentHealth -= amount;
if (currentHealth <= 0)
{
currentHealth = maxHealth;
RpcRespawn();
}
}
void OnChangeHealth(int health)
{
healthbar.sizeDelta = new Vector2(health * 2, healthbar.sizeDelta.y);
}
[ClientRpc]
void RpcRespawn()
{
if(isLocalPlayer)
{
transform.position = Vector3.zero;
}
}
}
}
This is the codeaspğlasdlişsadlşisadlşiadsilşdslaişdlasişlişdsacdl işsadilşaLDİŞaslişÖDASİÖŞLDÖİLSAŞDöliasödilascöildaiölşsdöiaşsdöilasödilasiöldasöildasöildöilasdöilaöildöildasöildaöilsdöilasdölasdöliasölidasöildsaöildsöiladiösladöilsadöilsadöilasdiölsadiölsaöidlsaöildsöidiösladiölsadiölsadöilasöild
You can send a Command to the server with netID of the player who have won and check in RPC if the netID matches.
If netID matches for the local player then, he is the winner. Otherwise, he loses. Haven't tested the code below but should work:
[Command]
public void CmdGameWon()
{
RpcGameEnd(this.netId);
}
[ClientRpc]
public void RpcGameEnd(NetworkInstanceId nid)
{
if(this.isLocalPlayer && this.netId==nid){
//Process win here
}else{
//Process lose here
}
}
im having a problem from my enemyDamage script in unity5 when i play it and stick to the enemy i died instantly even the enemy damage is 10 and my health was 100
well this is my first time to make this things on unity hope you helps me :(
heres my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemydmg : MonoBehaviour {
public float damage;
public float damagerate;
public float pushbackforce;
float nextdamage;
bool playerInRange = false;
GameObject theplayer;
playerHealth theplayerhealth;
// Use this for initialization
void Start () {
nextdamage = Time.time;
theplayer = GameObject.FindGameObjectWithTag ("Player");
theplayerhealth = theplayer.GetComponent<playerHealth> ();
}
// Update is called once per frame
void Update () {
if (playerInRange)
Attack ();
}
void OnTriggerEnter (Collider other)
{
if (other.tag == "Player")
{
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
if (other.tag == "Player")
{
playerInRange = false;
}
}
void Attack()
{
if (nextdamage <= Time.time)
{
theplayerhealth.addDamage(damage);
nextdamage = Time.time + damagerate;
pushback (theplayer.transform);
}
}
void pushback(Transform pushObject)
{
Vector3 pushDirection = new Vector3 (0, (pushObject.position.y - transform.position.y), 0).normalized;
pushDirection *= pushbackforce;
Rigidbody pushedRB = pushObject.GetComponent<Rigidbody> ();
pushedRB.velocity = Vector3.zero;
pushedRB.AddForce (pushDirection, ForceMode.Impulse);
}
}
and this was my playerhealth
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerHealth : MonoBehaviour {
public float fullhealth;
float currentHealth;
// Use this for initialization
void Start () {
currentHealth = fullhealth;
}
// Update is called once per frame
void Update () {
}
public void addDamage(float damage)
{
currentHealth -= damage;
if (currentHealth <= 0) {
makeDead ();
}
}
public void makeDead()
{
Destroy (gameObject);
}
}
theplayerhealth = theplayer.GetComponent<playerHealth> ();
I think this line of code fails you because the player is a GameObject. theplayerhealth is or should already be initialized in your other script. I think you could approach polymorphism in a better way.
public class enemydmg : playerHealth{
}
This will allow you to directly inherit everything you need from the playerHealth script without having to grab extra components. You can also use this technique for may other scripts in the future.
Another approach that you could use is calling your class directly:
playerHealth.addDamage(damage);
From now on when you name your scripts use capitalization. PlayerHealth, EnemyDamage, etc... That's just a pro-tip to make your code look a bit cleaner when you're doing things like this. (Optional)