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;
}
}
}
Related
Either the script is outdated, or it's not what I need, but I cannot find an answer to this.
To start off, I'm making a pinball styled game, whenever the ball hits a piece, it changes color, but I have multiple colored balls, and I want to lock the color in place as to not have the other balls change them (to make the game a little bit easier). I've provided a script, which may be a little too complex for a simple solution. The problem area is at the bottom with void FixedUpdate.
(I just wanna change a tag ): )
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColorBlue : MonoBehaviour
{
public Material mat;
public string ballTag;
public bool reset = false;
public bool found = false;
public void OnCollisionEnter (Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Ball" )
{
gameObject.GetComponent<MeshRenderer>().material.color = Color.blue;
reset = true;
}
}
public void FixedUpdate ()
{
if(reset)
{
GameObject.FindWithTag("Ball");
} found = true;
if(found)
{
GameObject.FindWithTag("Ball").tag = "Untagged";
}
}
}
Instead of searching for the GameObject with the "Ball" Tag which you probably have multiple off in your scene. You can rather just change the tag directly when the collision happens.
Because in the OnCollisionEnter Function you have a reference to the gameObject already, you can just use that to change the tag with collisionInfo.gameObject.tag = "Untagged".
public void OnCollisionEnter (Collision collisionInfo) {
if (collisionInfo.gameObject.CompareTag("Ball") && gameObject.CompareTag("Ball")) {
// Get Mesh Renderer of the Colided Ball Component.
var meshRenderer = collsionInfo.gameObject
.GetComponent<MeshRenderer>();
// Change Color of collided ball to be the same as the ball it collided with.
meshRenderer.material.color = gameObject
.GetComponent<MeshRenderer>().material.color;
// Set Tag to "Untagged" to make sure ball won't change color anymore
colliderInfo.gameObject.tag = "Untagged";
}
}
You could also add additional Code to change the color depending on the current Color of the gameObject. Additionaly I would advise you to use CompareTag(), which checks if the tag even exists in your scene.
If you want to get the collided gameObject you can do that with collisionInfo.gameObject.tag
I'm trying to make a game with "Death Blocks" that move the player to the respawn point after triggering the OnTrigger method. Here is the code:
public class DeathBlock : MonoBehaviour
{
public GameObject respawnPoint;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "Player")
{
collision.gameObject.transform.position = respawnPoint.transform.position;
}
}
}
Edit: I found out the problem. The camera was moving on the Z axis as well so clamp the cameras Z axis position to whatever you had it to on scene startup (-10 for me), and the character remains on screen.
Do either the respawn or the player have a parent game object? When you change the transform.position you change the local transform, if there is a parent object it will multiply the rotation/scale of the parent. You can also while the game is running click on 'scene' in the editor, then click on the player in the inspect, hit 'f' and find out where it is or what it doing, and whether its set active.
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
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'm trying to make a "player can't move while this animation is playing" check in my method for movement.
I have a 3x8 grid of panels I'm using for this application, with the player moving from panel to panel. I have 2 animations for this: MovingOut which plays when the player is moving away from a panel, and "MovingIn" which plays when the player is moving into a panel. So the flow I want is:
Player presses a movement key → movement is disabled → "MovingOut" plays → player's transform.position is moved to the target position → "MovingIn" plays → movement is re-enabled.
Each animation is only 4 frames. I currently have an animation event at the beginning of "MovingOut" which sets an int CanMove to 0, and another animation event at the end of "MovingIn" which sets CanMove to 1.
Here's what my code looks like so far:
public void Move(int CanMove)
{
//this lets me use panelManager to access methods in the PanelManager script.
panelManager = GameObject.FindObjectOfType(typeof(PanelManager)) as PanelManager;
animator = GetComponent<Animator>();
if (Input.GetAxisRaw("Horizontal") == 1 && CanMove == 1) //go right
{
movingToPanel += 1;
if (IsValidPanel(movingToPanel))
{
//play animation MovingOut
animator.Play("MovingOut");
transform.position = panelManager.GetPanelPos(onPanel + 1);
onPanel += 1;
}
else
{
movingToPanel -= 1;
}
}
//else if( ...the rest of the inputs for up/down/left are below.
}
I have MovingIn set up in the animator so that it plays at the end of the MovingOut animation, which is why I don't call it in the script:
I can't for the life of me figure out how to get CanMove passed into the method without being forced to define it upon calling the method. Currently I have Move(1); being called in my Update() method just to check if movement is working (other than this issue I'm having) and it works in the sense that I can move panel to panel, but since CanMove is being defined as 1 in the Update Function, the animation's events don't prevent the movement.
Any insight would be greatly appreciated!
You should change your design slightly. Remove canMove as a parameter being passed to Move and make it a field of the player's class. Then have one function to set canMove. Then have a separate function that allows you to move if canMove is true. Something like this:
private bool canMove = true;
public void SetMove(int setCanMove) // called with animation events
{
canMove = setCanMove == 1 ? true : false;
}
public void Move()
{
if (Input.GetAxisRaw("Horizontal") == 1 && canMove == true) //go right
{
//movement code and animation call...
}
// Other directions...
}
Then you can call the setMove funciton using your animation events and stop the player moving for the duration of them. i.e call setMove(false) at the start of the MovingOut animation and setMove(true) at the end of the MovingIn animation. This will stop canMove being set in your Update loop.
you can get the integer value from animator's GetInteger function which will return the integer value set to current animation.
if(this.GetComponent<Animator>().GetInteger(canmove)==0)
//move
else
//can't move