I am trying to create a multiplayer TPS where I instantiate a bullet locally (in my editor) and apply force to it. Once it hits other player I would want to call that players TakeDamage RPC.
Sadly I am encountering this weird error message that I can't fix (already taking me days).
my projectile script:
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
[SerializeField] float timeToDestroy;
[SerializeField] ParticleSystem hitEffect;
[SerializeField] TrailRenderer trailRenderer;
float timer;
private Rigidbody rb;
private Collider col;
private void Awake()
{
rb = GetComponent<Rigidbody>();
col = GetComponent<Collider>();
}
private void Update()
{
timer = Time.deltaTime;
if (timer > timeToDestroy) Destroy(gameObject);
}
private void OnCollisionEnter(Collision collision)
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
ShowHitEffect(collision.GetContact(0));
col.enabled = false;
if (collision.gameObject.CompareTag("Player"))
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
PhotonView pv = collision.gameObject.GetPhotonView();
Debug.Log("hit " pv.Controller.NickName);
pv.RPC("DealDamage", RpcTarget.All, PhotonNetwork.LocalPlayer.NickName, .5f, PhotonNetwork.LocalPlayer.ActorNumber);
}
Destroy(gameObject, 2f);
}
private void ShowHitEffect(ContactPoint cp)
{
hitEffect.transform.position = cp.point;
hitEffect.transform.forward = cp.normal;
hitEffect.Emit(1);
}
}
weapon controller script
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponController : MonoBehaviourPunCallbacks
{
[Header("Fire Rate")]
[SerializeField] float fireRate;
float fireRateTimer;
[SerializeField] bool semiAuto;
[Header("Bullet Property")]
[SerializeField] GameObject bullet;
[SerializeField] Transform barrelPos;
[SerializeField] float bulletVelocity;
[SerializeField] byte bulletPerShot;
public AimController aim;
[SerializeField] AudioClip gunshot;
public AudioSource audioSource;
public WeaponAmmo ammo;
public ParticleSystem muzzleFlash;
public ParticleSystem hitEffect;
// Start is called before the first frame update
void Start()
{
fireRateTimer = fireRate;
}
private void Update()
{
if (!photonView.IsMine) return;
if (ShouldFire()) Fire();
}
bool ShouldFire()
{
fireRateTimer = Time.deltaTime;
if (fireRateTimer < fireRate) return false;
if (ammo.currentAmmo == 0) return false;
if (semiAuto && Input.GetKeyDown(KeyCode.Mouse0)) return true;
if (!semiAuto && Input.GetKey(KeyCode.Mouse0)) return true;
return false;
}
[PunRPC]
private void EmitMuzzleFlash()
{
muzzleFlash.Emit(1);
}
void Fire()
{
fireRateTimer = 0;
barrelPos.LookAt(aim.actualAimPos);
audioSource.PlayOneShot(gunshot);
EmitMuzzleFlash();
//photonView.RPC("EmitMuzzleFlash", RpcTarget.All);
ammo.currentAmmo--;
for (int i = 0; i < bulletPerShot; i )
{
GameObject currentBullet = Instantiate(bullet, barrelPos.position, barrelPos.rotation);
Rigidbody rigidbody = currentBullet.GetComponent<Rigidbody>();
rigidbody.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
// Projectile Instantiate
/*{
GameObject currentProjectile = (GameObject)PhotonNetwork.Instantiate(bullet.name, barrelPos.position, barrelPos.rotation);
Rigidbody rb = currentProjectile.GetComponent<Rigidbody>();
rb.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
}*/
}
}
}
player controller script (where rpc is located)
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviourPunCallbacks
{
private PlayerStats stats = new PlayerStats();
void Start()
{
if (photonView.IsMine)
{
UIController.instance.healthSlider.maxValue = stats.maxHealth;
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
FocusWindows();
}
void FocusWindows()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
}
else if (Cursor.lockState == CursorLockMode.None)
{
if (Input.GetMouseButton(0))
{
Cursor.lockState = CursorLockMode.Locked;
}
}
}
#region
[PunRPC]
public void DealDamage(string damager, float damageAmount, int actor)
{
Debug.Log("called rpc deal damage");
Debug.Log("damager " damager " damageAmount " damageAmount " actor " actor);
TakeDamage(damager, damageAmount, actor);
}
public void TakeDamage(string damager, float damageAmount, int actor)
{
if (photonView.IsMine)
{
stats.ReduceHealth(damageAmount);
if (stats.GetCurrentHealth() == 0)
{
PlayerSpawner.Instance.Die(damager);
MatchManager.instance.UpdateStatSend(actor, 0, 1);
}
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
}
#endregion
}
Projectile Prefab(resource) enter image description here
Player prefab enter image description here
Weird thing is if I go with "Instantiate Arrow in the network" the rpc is getting called. But this is not ideal since it will because it will send the transform of the projectile every time it is flying. So I just want to check in the local (arrow with no photonView) if it hits an enemy then call the rpc of that enemy to make him take damage and possibly display a fake project coming from the damager. If my approach is naive / wrong please tell me a better approach please.
CodePudding user response:
I transfered the rpc call on the same script where the photonView is located as mentioned by @derHugo. I think the main problem was my understanding of RPC. I thought rpc is like a public method where you can call it outside. I think I need to reread the documentations about rpc and raise events.