using UnityEngine;
public class PlayerLoad : MonoBehaviour
{
[SerializeField]
private Sprite pSprite;
private void Start()
{
LoadSprite(this.gameObject, pSprite);
}
void LoadSprite(GameObject p1, Sprite pSprite = null) // p1 = the player's gameobject
{
var sr = p1.GetComponent<SpriteRenderer>();
if (sr == null)// If no sprite renderer exist
{
sr = p1.AddComponent<SpriteRenderer>();
}
if (sr != null && !sr.enabled)// If sprite renderer exist but isn't active
{
sr.enabled = true;
}
if (sr.sprite == null)// If no sprite exist, adds one
{
p1.GetComponent<SpriteRenderer>().sprite = pSprite;
}
}
}
Ok, so I'm having an issue to where sometimes my player's sprite seems to be invisible. As of now, I can build the project onto my mobile device and everything works fine. However, when the second level is completed (Right now I only have two levels I'm using for testing) the game goes to the Death scene. Then it ask's the user to continue or quit. If continue, the player is taken to the last level reached. Code works, but the sprite is now invisible. Sometimes I can pause the game, quit and return to the main menu, click play again and start over and the player appears again. Other times it makes it worse because the bullets even fail to render. I have no clue as to what could cause such a thing. SO I have this code in hopes of forcing the sprite to render whether it wants to or not.
Here's a screenshot of the mobile screen:
To the right you can see the bullets firing but the player cannot be seen. You can tell the player is moving by the offset in the bullet trajectory. (If you look close)
I'm using Unity 2019.0.1a Beta
Related
I'm working on a multiplayer game and I'm encountering a issue when 2 players are loading the same level using PhotonNetwork.LoadLevel().
When I start the game alone, I can control my player and everything is fine. But when we are 2 players, Player A is controlling Player B and vice-versa.
I check a lot of links on the internet these past few days, and I learned the concept of PhotonNetwork.IsMine which I thought would solve all of my problem but it seems to not working with me. Also, I'm using the new input system of Unity but I don't think the issue come from here.
Basically, what I'm doing is:
Instantiate a player (this happened twice since I have 2 players) which have a PlayerManager
Player Manager Get Instance of the local player and synchronize camera with the local player only if isMine = true
CameraManager creates input manager if the script is linked to the local player by using isMine
Link the main camera to this script when the gamemanager request it
Update camera rotation only when isMine is true (second protection)
Here is a piece of my code:
GameManager.cs (Holding by a Scene Object, so it is initially instantiated for everyone with the scene)
void Start()
{
if(PlayerManager.LocalPlayerInstance == null)
{
//Get player's team
string team = (string)PhotonNetwork.LocalPlayer.CustomProperties["Team"];
int indexPlayer = GetSpawnPosition();
//Spawn player depending on its team and its index in the players pool
if (team.Equals("Spy"))
{
PhotonNetwork.Instantiate(this.spyPrefab.name, SpySpawns[indexPlayer].position, SpySpawns[indexPlayer].rotation);
}
else if (team.Equals("Defender"))
{
PhotonNetwork.Instantiate(this.defenderPrefab.name, SpySpawns[indexPlayer].position, SpySpawns[indexPlayer].rotation);
}
}
}
PlayerManager.cs (Holding by the player, so not initially instantiated with the scene)
void Awake()
{
//Keep track of the localPlayer to prevent instanciation when levels are synchronized
if (photonView.IsMine)
{
LocalPlayerInstance = gameObject;
}
//Don't destroy this gameobject so it can survives level synchronization
DontDestroyOnLoad(gameObject);
}
private void Start()
{
//Get Manager of the camera of the player and attach to the local player
CameraLookFPS cameraFPSManager = gameObject.GetComponent<CameraLookFPS>();
if (cameraFPSManager != null)
{
//Ensure that we the local player is controlling its own camera
if(photonView.IsMine == true)
{
cameraFPSManager.SynchronizeWithLocalPlayer();
}
}
else
Debug.Log("This player is missing the CameraLookFPS component");
}
CameraManager.cs (Holding by the player, so not initially instantiated with the scene)
private void Start()
{
//Synchronize camera with local player on start for debug
if(SynchronizeOnStart)
{
SynchronizeWithLocalPlayer();
}
//Bind input for controlling the camera
BindingInput();
}
private void BindingInput()
{
// Prevent control is connected to Photon and represent the localPlayer
if (photonView.IsMine == false && PhotonNetwork.IsConnected == true)
{
return;
}
else
{
//Get Components
Input_Master = new InputMaster();
//Enable
Input_Master.Enable();
//Input binding
Input_Master.Player.Look.performed += context => MoveCamera(context);
Input_Master.Player.Look.Enable();
}
}
public void SynchronizeWithLocalPlayer()
{
if (photonView.IsMine == false && PhotonNetwork.IsConnected == true)
{
return;
}
Player_Camera = Camera.main.transform;
isSynchronized = true;
}
I tried to be clear enough, tell me if something is bad explained. I'll continue my research on my side and I'll keep you in touch if I find something.
Thanks in advance for your help!
Adrien
I finally found my solution. It appears that I already read about it but I have failed when trying to solve it.
So, like a lot of people, it is a Camera issue.
What I did is:
Create a game object holding the camera and put it as a child of the player gameobject
Deactivate the game object holding the camera
When instantiating the player, check if the player is the local player, using PhotonNetwork.IsMine. If yes, activate the gameobject holding the camera through script
If you have questions, send me a message!
Adrien
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteAlways]
public class SkyBox : MonoBehaviour
{
public Material[] skyboxes;
public Camera skyboxCamera;
public float skyboxMoveSpeed = 2f;
private int index = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
SwitchSkybox();
}
if (RenderSettings.skybox == skyboxes[1])
{
RenderSettings.skybox.SetFloat("_Rotation", Time.time * skyboxMoveSpeed);
}
}
public void SwitchSkybox()
{
index++;
if (index == skyboxes.Length)
{
index = 0;
}
RenderSettings.skybox = skyboxes[index];
if (RenderSettings.skybox == skyboxes[1])
{
skyboxCamera.enabled = true;
Camera.current.enabled = false;
Time.timeScale = 1.0f;
}
else
{
skyboxCamera.enabled = false;
Camera.current.enabled = true;
Time.timeScale = 0.0f;
}
}
}
The script switch between skyboxes the default and my skybox and also switch between the currently active camera and the sky box camera.
But when I'm hitting the escape key it's throwing null exception in the editor on the line number 46 :
Camera.current.enabled = false;
The current of the Camera is null
I want to make that when I press the escape key it will switch to my skybox and to the skybox camera and also will pause the game (Later I will make a main menu when the game is paused).
This is the Camera.current, from the manual.
The camera we are currently rendering with.
Also worth noting the comment from Ruzihm.
The Unity engine typically assigns an already-instantiated instance of
Camera to Camera.current
So, from your scripts, I see 2 issues. The one directly related to this questions happens just in editor mode and I will start from that one.
Editor Issue: Camera.current is null
When working in the editor, Camera.current won't be just your own application's camera, but it could be any camera. It could even refer to the editor's scene view camera.
In this last case, if your scene view is not in focus (IE when you've focus on Game Window) Camera.current will be null.
Logical Issue: you couldn't switch back
When you try to switch back from skyboxCamera, your Camera.current will be the same skyboxCamera, and not your default camera. So you won't be able to retrieve the previous camera.
SOLUTION
Do not use Camera.current, but store all of your cameras in your script (this solution is also better for perfomance, since both Camera.current and Camera.Main are not performant scripts).
In your case you will need to add this piece of code to your script and use the EnableSkyBoxCamera method.
public Camera defaultCamera;
public Camera skyBoxCamera;
private Camera _currentCamera;
public void EnableSkyBoxCamera(bool enableSkyBox)
{
defaultCamera.enabled = !enableSkyBox;
skyBoxCamera.enabled = !enableSkyBox;
if (enableSkyBox) _currentCamera = skyBoxCamera;
else _currentCamera = defaultCamera;
}
If camera is null you can't set the enabled to false without getting a nullpointerexception. Instantiate the camera first or remove that line of code.
*** Edit ill take another crack at this
try
Camera.main.enabled = false;
instead of
Camera.current.enabled = false;
As per Unity docs in reference to Camera.current: 'Most of the time you will want to use Camera.main instead. Use this function only when implementing one of the following events: MonoBehaviour.OnRenderImage, MonoBehaviour.OnPreRender, MonoBehaviour.OnPostRender'
I'm creating a Character Selection Menu for my mobile game. I have a GlobalManager Gamobject which is a singelton persisting through scenes. Then I have a GameSession Gameobject which controls stuff inside the Gameplay Scene.
In MenuScene inside character selection window when I click on the character toggle I call function, which sets sprite and runtimeAnimatorController into a field of GlobalManager. Then When I load the Gameplay inside Start I call the function below to set the Player sprite and Animator.
Problem is that the Animator is set but the sprite not. Also when I start moving the player it looks like the Animator is calling all Animations at once for 3-4 sec until it stabilizes and starts playing the right one.
#region Set Character
public void SetCharacter(GameObject player)
{
if (CharacterSprite && CharacterRuntimeAnimatorController && player)
{
player.GetComponent<SpriteRenderer>().sprite = CharacterSprite;
if (player.GetComponent<PlayerBehavior>() && player.GetComponent<Animator>())
{
player.GetComponent<Animator>().runtimeAnimatorController = CharacterRuntimeAnimatorController;
}
}
}
#endregion
Expected behavior is that the sprite will be set and the Animator won't be glitching
EDIT:
When I deactivate Animator on Player GameObject the sprite is set. Still not sure what is causing this problem
EDIT 2:
Following script enables the sprite to be set but the Animation glitch remains
public void SetCharacter(GameObject player)
{
if (CharacterSprite && CharacterRuntimeAnimatorController && player)
{
player.GetComponent<SpriteRenderer>().sprite = CharacterSprite;
if (player.GetComponent<PlayerBehavior>() && !player.GetComponent<Animator>())
{
player.AddComponent(typeof(Animator));
}
if (player.GetComponent<PlayerBehavior>() && player.GetComponent<Animator>())
{
player.GetComponent<Animator>().runtimeAnimatorController = CharacterRuntimeAnimatorController;
}
}
}
I won't hide that I am new to the Unity and C#. I am trying to make mini escape game.
My problem: Changing sprites using colliders works only on one object. After clicking second object it works one time and then either the first and the second object don't work.
Description:
On the main screen I will have many items that are "clickable" and some that are "pickable". I created 2 scripts- one that close up to the clicked item, and second that return to the main view.
Main view looks like that: they are 3 colliders and each one close-up to different view. Colliders are the children of the Background. After close-up I don't want the child colliders of background to be working. Only the collider of the close-up should work.
So the question: Am I doing anything wrong? Is there any better method to change sprites after mouse click?
My code:
First script:
public class GetCloser : MonoBehaviour // shows close-up of clicked object
{
public GameObject Actual, Background;
void OnMouseDown()
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
if (hit.collider != null)
{
Background.SetActive(false);
Actual.GetComponent<Collider2D>().enabled = true;
Actual.GetComponent<SpriteRenderer>().enabled = true;
}
}
}
Second script:
public class ReturnTo : MonoBehaviour //hide the close-up image and return to the background
{
public GameObject Actual, Background;
void OnMouseDown()
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
if (hit.collider != null)
{
Background.SetActive(true);
Actual.GetComponent<Collider2D>().enabled = false;
Actual.GetComponent<SpriteRenderer>().enabled = false;
}
}
}
Last script:
public class PickUp : MonoBehaviour { //hide clicked object- works every time
// Use this for initialization
void Start () {
gameObject.GetComponent<SpriteRenderer>().enabled = true;
}
// Update is called once per frame
void OnMouseDown()
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
if (hit == true && hit.collider != null)
{
hit.collider.gameObject.GetComponent<SpriteRenderer>().enabled = false;
Destroy(hit.collider);
}
}
}
So if the issue is the colliders for your main screen still being active after zoom that's simply adding in your first script "zoom script" deactivating the colliders for all background or even just simply turning the gameobjects in the background off, then when you zoom back out simply turn the objects back on or colliders back on depending on which you decided to turn off.
Wait I just reread and realize after you click the first object you are no longer able to get the other objects to react any longer. Looking over your code it is probably because you are destroying the collider in your third script therefore you are no longer able to "hit" the other objects to trigger the code of a collision.
I am making a 2D platform game in Untiy for android and i am having some issues with a section of code i have. When i jump onto a platform the first time i can land onto the platform but when i jump again i fall through the platform. i have it so the box collider is inactive if the player is less then the height of the platform and active when the player is higher then the platform. I thought the box collider was to small and it was just missing the collider so i have tried different sizes of colliders and i have tried adjusting different heights at which it activates. Also when i set the height to low the player does a double jump. So what am i doing wrong?
public class Rock : MonoBehaviour
{
private BoxCollider2D platform;
private PlayerScript player;
public float height;
void Awake() {
player = GameObject.Find("Player").GetComponent<PlayerScript>();
platform = GetComponent<BoxCollider2D>();
}
void Start () {
platform.enabled = false;
}
// Update is called once per frame
void Update () {
if(player.transform.position.y > height){
platform.enabled = true;
} else if(player.transform.position.y < height){
platform.enabled = false;
}
}
}
Could it be that you're not covering the case where player.transform.position.y == height?
I can see that you're checking for greater / smaller than height but not equality. This could lead to unwanted behavior like the one you're describing.
Let me know if this was the problem.
This code actually worked. The issue ended up being in my playerscript where I had added a chunk of code where I was having a bug if you held the jump button down the player would get stuck in the jump animation.
void OnCollisionStay2D(Collision2D target) {
if (target.gameObject.tag == "Ground") {
grounded = true;
anim.SetBool("Jump",false);
}
}
public void Jump () {
if(grounded){
grounded = false;
anim.SetBool("Jump",true);
myBody.velocity = new Vector2(myBody.velocity.x, 0);
myBody.AddForce( new Vector2(0, jumpForce));
}
}
After some troubleshooting and going and removing pieces of code trying to see why I doubled jump I finally came across this piece then when I was trying with the touch controls instead of with the keyboard I noticed I am not actually able to hold the jump button down like you can with a keyboard so I didn't really need this piece of code. So I was my own worst enemy this time.