I'm trying to disable a light component from another component on a player.
I've tried a couple of methods, mostly the same.
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
Debug.Log("light");
transform.GetComponent<PhotonView>().RPC("EnableFlash", RpcTarget.All, gameObject.name);
}
}
[PunRPC]
void EnableFlash(string name)
{
Light light = GetComponent<Light>();
light.enabled = !light.enabled;
}
This is turning my light off, this cannot be seen on other clients for some reason and there are no errors for this piece of code.
Second try:
void Update()
{
// Torch on//off
if (Input.GetKeyDown(KeyCode.F))
{
pv.RPC("LightToggled", RpcTarget.All, gameObject.name, torchActive);
torchActive = !torchActive;
}
}
[PunRPC]
public void LightToggled(string name, bool active)
{
GameObject g = GameObject.Find(name);
GameObject light = g.GetComponent<PlayerExtras>().torch.gameObject;
light.SetActive(active);
}
This does not work either.
As #DigvijaysinhGohil said in the comment under my question said I needed to make sure that both clients had the same name.
They did not so to fix this i had to change the name of the player with the script below:
void Start()
{
string name_ = pv.Owner.ToString();
name_ = name_.Split()[1];
gameObject.name = name_;
}
this script changes it from #01 'jerry' to 'jerry'. this changed on all clients and made sure that they are the same name.
:)
Related
so here is the scenario,
i want the player to be able to perform a trick, and then be able to hold the trick for a longer duration if they want to, but if they don't hold the input then they instead just continue the animation until completion as i haven't actually tried implementing too much and its not giving me the desired result i figured i'd just ask if people have already done it so i don't spend the next 2 hours down a rabbit hole, any and all help is appreciated thanks! :D
(Unity Script)
{
[Header("Trick Attributes")]
public string GroundTagName; // Tag used for all the platforms
public KeyCode stuntKey;
public float AnimationFreezeTime = 0.75f;
public SpriteAnimator anim; // Put the Sprite animator here
public Animator spriteAnimator; // Put the Animator here
private bool isGrounded;
public bool stunting = false;
private void Start()
{
}
private void Update()
{
if (Input.GetKeyDown(stuntKey) && !isGrounded)
{
anim.StartAnimation("FlyingSquirrel");
stunting = true;
Invoke("FreezeAnimation", AnimationFreezeTime);
}
if (Input.GetKeyUp(stuntKey))
{
stunting = false;
spriteAnimator.speed = 1;
}
}
void FreezeAnimation() {
spriteAnimator.speed = 0;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == GroundTagName)
{
isGrounded = true;
}
else
{
isGrounded = false;
}
if (stunting && collision.gameObject.tag == GroundTagName)
{
Destroy(gameObject);
}
}
private void OnCollisionExit(Collision collision)
{
isGrounded = false;
}
}
FlyingSquirrel needs to be broken up into 3 different animations. This can be done in Maya, Blender, uMotion, or even Unity's animation importer:
You need 3 Animator states:
Start_FlyingSquirrel // Player moves into position
Idle_FlyingSquirrel // Player is "holding" the trick
End_FlyingSquirrel // Player let go, return to normal
When the player presses button to start the trick, play the Start animation. For the transition, use "has exit time" to proceed to the Idle State. The Idle state will be true (use a boolean Animator parameter) while the trick is "held". Uncheck "has exit time" for the transition to the End state- you want this to happen instantly.
Some part of the code works (hp1 -= damage1;), but the second part doesn't work.
Where did I make a mistake?
Here are parts of two scripts:
Player1.cs
private Bullet1 b1;
void Start()
{
b1 = FindObjectOfType<Bullet1>();
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
hp1 -= damage1; // it works, my player loses hp
Destroy1(); // doesn't work
}
}
void Destroy1()
{
b1.hit1 = true; // hit for bullet1.cs
}
Bullet1.cs
public bool hit1;
void Update()
{
if (hit1)
{
hit1 = false;
Destroy(gameObject);
}
}
If I switch bool hit = true in real time in Unity, destroying works. It means that Bullet1.cs can't recieve hit = true;
If I swap lines hp1 -= damage1; and Destroy1();, my player can't get damage. So, Destroy1(); stops my code and then can't activate other lines. Also if I change Destroy1(); to b1.hit1 = true; nothing new happens.
Just destroy the bullet through the collision instead of using the boolean. It's creating unnecessary resource usage. Of the given code, this is all you need to do to destroy the bullet using the player script. The parts of the bullet script shown are unnecessary. If you want additional logic handled inside the bullet when destroyed then use a OnDestroy function to handle it.
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
hp1 -= damage1;
Destroy(col.gameobject);
}
}
New to unity.
So I created a simple a simple muzzle flash particle animation that is supposed to be displayed on enemies gun when the player gets close to him, simulating a shot without the actual bullet. However I get a null reference exception in this part muzzleFlash.Play(); I believe it's because I am not actually getting the muzzle flash component in the start function with the code I have, actually I know that is it after going to in to debug mode I found out. I am having a really hard time figuring out how to access that component. Below is my code and I'm also posting a picture of my hierarchy. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StaticShootingEnemy : MonoBehaviour
{
[SerializeField] private float _range = 12f;
private Transform _player;
private bool _alive;
private float _distance;
private ParticleSystem muzzleFlash;
// Use this for initialization
void Start()
{
_player = GameObject.Find("Player").transform;
_alive = true;
muzzleFlash = (ParticleSystem)this.gameObject.GetComponent("muzzleFLash");
}
// Update is called once per frame
void Update()
{
_distance = Vector3.Distance(this.transform.position, _player.transform.position);
if (_alive && _distance < _range)
AttackPlayer();
}
private void AttackPlayer()
{
//Turning enemy to look at player
transform.LookAt(_player);
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
if (Physics.SphereCast(ray, 0.75f, out hit))
{
//TODO: Fix enemy shooting fast when gettting close to him.
GameObject hitObject = hit.transform.gameObject;
if (hitObject.GetComponent<PlayerController>())
{
muzzleFlash.Play();
Debug.Log("Player Hit!");
}
else
muzzleFlash.Stop();
}
}
public void SetAlive(bool alive)
{
_alive = alive;
}
}
You probably have an object "muzzleFlash" as child to object your script attached to. So, in this case you'd better have a reference to your ParticleSystem object that is called muzzleFlash.
[SerializeField] private ParticleSystem muzzleFlash; // drag and drop your ParticleSystem muzzleFlash in inspector
or at least you could find that muzzleFlash like this
GameObject muzzleFlashObj = GameObject.Find("muzzleFlash");
ParticleSystem muzzleFlash = muzzleFlashObj.GetComponent<ParticleSystem>();
In your case it's null because there is probably no component that is called MuzzleFlash on that object. The component you want to get is ParticleSystem.
What component is the staticshootingenemy script on? if it is not on the same component as the particle system then its not finding it because this.gameObject.GetComponent("muzzleFLash") does not exist on that component. You can use GameObject.Find("muzzleFLash") to search for the particle system.
So back to your comment, you could implement something like a pool for your muzzle flashes.
public class MuzzleFlashEffect : MonoBehaviour
{
[SerializeField] private ParticleSystem particleEffect;
private Queue<MuzzleFlashEffect> poolQueue;
public void SetPoolQueue(Queue<MuzzleFlashEffect> queue)
{
poolQueue = queue;
}
public void Play()
{
StartCoroutine(Playing());
}
private IEnumerator Playing()
{
particleEffect.Play();
while (particleEffect.isPlaying)
{
yield return null; // wait until particle animation is done, then recycle effect
}
particleEffect.Stop();
poolQueue.Enqueue(this); // recycle this effect
}
// you can do the same thing for Animation as well, or even write some abstract PoolableVFX class that would be usefull for Animation , ParticleSystems etc..
}
//assume you have some game controller that manage what is going on in the scene
public class GameController : MonoBehaviour
{
[SerializeField] private MuzzleFlashEffect muzzleFlashPrefab;
private Queue<MuzzleFlashEffect> poolQueue = new Queue<MuzzleFlashEffect>(10); // 10 is enough i guess and it's good to set it at instantiation to avoid memory fragmentation
private MuzzleFlashEffect GetMuzzleFlash(Vector3 pos, Quaternion rot)
{
MuzzleFlashEffect muzzleFlash;
// if we already have some effects, then play them, otherwise make a new one and recycle it then
if (poolQueue.Count > 0)
{
muzzleFlash = poolQueue.Dequeue();
}
else
{
muzzleFlash = Instantiate(muzzleFlashPrefab);
muzzleFlash.SetPoolQueue(poolQueue);
}
muzzleFlash.transform.position = pos;
muzzleFlash.transform.rotation = rot;
return muzzleFlash;
}
void Update()
{
// your fancy logic ...
GameObject mutantGunEnd = new GameObject("mutant");
//assume that here you want your muzzle flash effect, so you do:
var muzzleFlash = GetMuzzleFlash(mutantGunEnd.transform.position, mutantGunEnd.transform.rotation); // or you might want to pass mutantGunEnd.transform.forward instead, it depends...
muzzleFlash.Play();
// your fancy logic ...
}
}
So, in this case you have only as many instance of ParticleEffect as you need and saving some resources. You could also create a universal generic pool for any type of object you want to recycle. (you want to recycle instead of instantiation, cuz Instantiation is cpu expensive).
M.b this is a bit overkill here, but i just wanted to share how would i think about this here
I am using Unet in Unity and I am trying to basically pick up an object and move it around the scene and show it to everyone on the server. I can successfully spawn the object with the host and both the client and host can see the object.
However, as the client I can spawn the object but, it does not show up for the host. As far as moving the object the host is able to move the object and the client sees that the host is moving the object. I do this using Assign and Remove Authority method. However, when the client tries to move the host's object it does not appear on the server either. But when the host tries to move the object again after the client has "moved" it the object basically jumps repeatedly back and forth between where the host is moving it too and where the client placed it last.
I really hoped that made sense and someone can help me out please. I have listed some code from the player controller script.
[Command]
public void CmdSpawnCapsule()
{
RpcSpawnCapsule();
}
[ClientRpc]
public void RpcSpawnCapsule()
{
if (isLocalPlayer)
{
//Debug.Log("You are in the cmd");
Vector3 capDir = transform.forward;
Vector3 capPos = transform.position + capDir * 1.5f;
GameObject capsuleToSpawn = (GameObject)Instantiate(capsule, sharedWorldAnchorTransform.InverseTransformPoint(capPos), Quaternion.Euler(capDir));
//capsuleToSpawn.GetComponentInChildren<Rigidbody>().velocity = capDir;
NetworkServer.SpawnWithClientAuthority(capsuleToSpawn, connectionToClient);
//Debug.Log("Exiting cmd");
}
}
public void OnInputClicked(InputClickedEventData eventData)
{
if (isLocalPlayer)
{
if (Physics.Raycast(transform.position, direction: transform.forward, hitInfo: out hit, maxDistance: range))
{
objectID = GameObject.Find(hit.transform.name);
CmdAssignAuthority(objectID);
}
}
}
public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
{
if (isLocalPlayer)
{
String keyword = eventData.RecognizedText;
//Debug.Log(keyword);
switch (keyword)
{
case "Spawn":
CmdSpawnCapsule();
break;
}
}
}
[Command]
void CmdAssignAuthority(GameObject obj)
{
if (control == 0)
{
objNetId = obj.GetComponent<NetworkIdentity>();
objNetId.AssignClientAuthority(connectionToClient);
control = 1;
}
else
{
objNetId.RemoveClientAuthority(connectionToClient);
control = 0;
}
}
Solved: The problem was in my GameObject.Find function where I was looking for an object name. I gave a unique name to each object and it solved the problem I was having.
I'm somewhat new to PUN and Unity so hopefully, I am making some kind of beginner mistake.
void Update(){
if(launch == true){
Debug.Log("launched");
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
//myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
When I run the code above, I can see launched in the console but I get
"NullReferenceException: Object reference not set to an instance of an
object" on this line: myPhotonView.RPC("ChangeScene",
PhotonTargets.All);
When I run it with that line commented out and the line that's outside the if statement uncommented, there is no null reference exception and the method executes. Is there a mistake in the above code, or is this a bug in Photon?
Any help at all is much appreciated. I can post the full code or error messages if anyone thinks it's necessary.
Also, this is less important, but myPhotonView is null in any methods I create that aren't regular MonoBehaviour methods like Start or Update even though I set it as a global variable and filled it in Start before I try to access it. This seems like it might be tied to the other problems I'm having, and it's the only reason I'm using Update for this.
Edit: Here's the entire file:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class NetworkedPlayer : Photon.MonoBehaviour{
public GameObject avatar;
public PhotonView myPhotonView;
public bool launch = false;
public string destination = "";
//Responsible for avatar movements on the plane
public Transform playerGlobal;
//Responsible for headmovements
public Transform playerLocal;
public Transform playerRotation;
void Start (){
//launch is successfuly set to false
//if(!launch) Debug.LogError("banana");
Debug.Log("Instantiated");
//Necessary for photon voive to work
var temp1 = PhotonVoiceNetwork.Client;
myPhotonView = this.photonView;
//this ensures that only you can control your player
if (photonView.isMine){
Debug.Log("Controlling my avatar");
playerGlobal = GameObject.Find("OVRPlayerController").transform;
playerLocal = playerGlobal.Find("OVRCameraRig/TrackingSpace/CenterEyeAnchor/Pivot");
playerRotation = playerGlobal.Find("OVRCameraRig/TrackingSpace/CenterEyeAnchor");
this.transform.SetParent(playerLocal);
this.transform.localPosition = Vector3.zero;
this.transform.rotation = playerRotation.transform.rotation;
// avatar.SetActive(false);
//Throws null
//GetComponent<PhotonVoiceRecorder> ().enabled = true;
}
}
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info){
//This sends your data to the other players in the same room
if (stream.isWriting){
stream.SendNext(playerGlobal.position);
stream.SendNext(playerGlobal.rotation);
stream.SendNext(playerLocal.localPosition);
stream.SendNext(playerLocal.localRotation);
}
//This recieves information from other players in the same room
else{
this.transform.position = (Vector3)stream.ReceiveNext();
this.transform.rotation = (Quaternion)stream.ReceiveNext();
avatar.transform.localPosition = (Vector3)stream.ReceiveNext();
avatar.transform.localRotation = (Quaternion)stream.ReceiveNext();
}
}
public void ChangeAndSyncScene(string dest){
Debug.LogError("Dest selected: " + dest);
launch = true;
destination = dest;
Update();
}
void Update(){
if(launch == true){
Debug.LogError("launched");
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
ChangeScene();
}
myPhotonView.RPC("ChangeScene", PhotonTargets.All);
}
[PunRPC]
void ChangeScene(){
Debug.LogError("scene changed");
Application.LoadLevel (destination);
}
}
Edit: I never managed to fix this, but I did get around it. I created gameobjects to give values to other players in the game. PM me for more info