Unity: Changing camera position based off object click between scenes Unity - c#

I am creating a game that shifts the player between an isometric overhead view of the map, into a perspective view. The player starts by looking at the map as such,
Isometric view of map | Scene A
Upon clicking either of the red orbs floating, the player shifts into a separate scene in the perspective view at the orb location. Shown here,
Perspective 1 | Scene B
Perspective 2 | Scene B
The isometric map and the perspective maps are different scenes and it is important that they remain as such. The player needs to be able to click on an orb in Scene A and then have the camera move to the set position of the orb in Scene B.
My current thought is that each orb could have a tag (1,2,...) and once clicked, this tag would be referenced with an if statement to position the camera in the other scene. My problem is that I don't know how to reference the tag of the clicked orb once I am in the next scene. Or how I would reset this back to normal if I return to Scene A.
Here is some code that I have started, but I am not sure if I am on the right path.
using UnityEngine;
using UnityEngine.SceneManagement;
public class TagCheck : MonoBehaviour
{
Camera m_MainCamera;
public string sceneName;
int count;
private void Start()
{
m_MainCamera = Camera.main;
}
void LoadScene()
{
SceneManager.LoadScene(sceneName);
DontDestroyOnLoad(gameObject);
}
void OnMouseDown()
{
LoadScene();
Debug.Log(count);
}
void OnEnable()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
if (count == 1)
{
if (GameObject.FindWithTag("1"))
{
m_MainCamera.transform.position = new Vector3(5f, 1.5f, 5f);
}
else if (GameObject.FindWithTag("2"))
{
m_MainCamera.transform.position = new Vector3(-5f, 1.5f, -5f);
}
}
else
{
Destroy(gameObject);
}
}
Thank you all for the help! Let me know if I need to clarify anything.

I was able to come up with a solution to this problem. I have my scene change orbs follow me into the next scene by attaching a DontDestroyOnLoad script to them. In the next scene, there is an empty game object that continuously checks for objects with specific tags. Once found, the object tells the checker to move the camera to my desired empty parent and then reset the coordinates back to 0. Here is the checker script,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class tagChecker : MonoBehaviour {
Camera m_MainCamera;
void Start()
{
m_MainCamera = Camera.main;
}
void TagCheck()
{
if (GameObject.FindWithTag("1"))
{
m_MainCamera.transform.SetParent(GameObject.Find("Perspective1").transform); //GameObject.Find("A").transform.parent;
m_MainCamera.transform.localPosition = new Vector3(0f, 0f, 0f);
m_MainCamera.transform.localRotation = Quaternion.identity;
Destroy(GameObject.FindWithTag("1"));
}
else if (GameObject.FindWithTag("2"))
{
m_MainCamera.transform.SetParent(GameObject.Find("Perspective2").transform); //GameObject.Find("A").transform.parent;
m_MainCamera.transform.localPosition = new Vector3(0f, 0f, 0f);
m_MainCamera.transform.localRotation = Quaternion.identity;
Destroy(GameObject.FindWithTag("2"));
}
else if (GameObject.FindWithTag("3"))
{
m_MainCamera.transform.SetParent(GameObject.Find("Perspective3").transform); //GameObject.Find("A").transform.parent;
m_MainCamera.transform.localPosition = new Vector3(0f, 0f, 0f);
m_MainCamera.transform.localRotation = Quaternion.identity;
Destroy(GameObject.FindWithTag("3"));
}
else if (GameObject.FindWithTag("4"))
{
m_MainCamera.transform.SetParent(GameObject.Find("Perspective4").transform); //GameObject.Find("A").transform.parent;
m_MainCamera.transform.localPosition = new Vector3(0f, 0f, 0f);
m_MainCamera.transform.localRotation = Quaternion.identity;
Destroy(GameObject.FindWithTag("4"));
}
}
void Update()
{
TagCheck();
}
}
Thanks,

I would abstract your level data information into a JSON data file or ScriptableObject instead of placing it directly into your code.
You could also have a "TeleportTo" Vector3 field and "SceneTo" Scene field on your orb object that the code can reference.

Related

OnCollisionEnter does not work upon initial collision - Unity 3D

I am a beginner in Unity and I am currently making a simple game. I have a problem where upon initial collision, the event that I wanted to happen does not trigger or in other words the OnCollisionEnter is not working upon initial collision.
The process of my script is when colliding which is the OnCollisionEnter the button will appear or it will be set active to true. But in the first collision it does not trigger or it is not working, I need to walk away a bit and go back in that way it only works. Sometimes I need to do it 2 or more times for the collider to trigger. I don't know if the script has problem or the collider itself but I made sure it is colliding properly when I look at the editor.
I set the object to static so it will not be pushed when walking and colliding towards it. I wonder if that has to do with this problem because even disabled it is the same. But can anyone give suggestions on how not to make the objects move or be pushed away upon collision?
Here is the script for my collision:
using UnityEngine;
using UnityEngine.UI;
public class InteractNPC : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse, nameBtn;
private Transform head;
private Vector3 offset = new Vector3(0, 1.0f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
head = transform.GetChild(0);
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
//Debug.Log("wews2");
if(collisionInfo.collider.name == "Player")
{
nameBtn.gameObject.SetActive(true);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
nameBtn.gameObject.SetActive(false);
}
}
}
Here is another script with collision and has the same problem:
using UnityEngine;
using UnityEngine.UI;
public class InteractButtonPosition : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse;
private Vector3 offset = new Vector3(0, 0.5f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
//uiUse = GameObject.FindGameObjectWithTag("ViewButton");
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
Debug.Log("wews");
uiUse.gameObject.SetActive(true);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
//Destroy(uiUse.gameObject);
uiUse.gameObject.SetActive(false);
}
}
}
Try changing Colision detection from Descrete to Continuous
collission detection
I solved this issue by using OntriggerEnter instead of OnCollisionEnter. In the editor, for the NPC I put a Collider on each part of the body and check the IsTrigger in the parent Object so it will still collide with my character even if the IsTrigger is enabled that will make the character go through the object. I just enlarged the scale of the collider with IsTrigger enabled so the collision will be detected immediately.

Not all gameobjects with the same script attached are respawning

I'm working on a Unity2D platformer which has blocks that break/fall when the player jumps onto them. Once the player makes contact, there is a short delay, then the block begins to slide down and shortly disappears (using SetActive(false)). If the player dies, then all "falling" blocks should respawn and return to their original positions.
I've made a level where there are two of these blocks (two completely independent gameobjects), but the problem is that when the player breaks both and then dies, when the player respawns only one of the two blocks respawns to its original position. (The other is never to be seen again.)
I think this may have something to do with how they are both attached to the same script. However I don't see how because a different gameobject is still specified in each instance of the script for each block.
Here's the code for the script attached to the block gameobjects (called breakingBlock).
public class BreakingBlock : MonoBehaviour
{
Collider2D boxCollider;
public GameObject slidingBlock;
public PlayerController player;
public float delay;
public float X;
public float startY;
public float endY;
public float speed;
void Start() // Initialises the position of the blocks
{
boxCollider = GetComponent<Collider2D>();
boxCollider.enabled = true;
slidingBlock.transform.position = new Vector2(X, startY);
player = FindObjectOfType<PlayerController>();
}
void OnCollisionEnter2D(Collision2D collision)
// Starts sliding coroutine when touched by player
{
StartCoroutine(Slide(slidingBlock, new Vector2(X, startY), new Vector2(X, endY), delay, speed));
}
public IEnumerator Slide(GameObject slidingBlock, Vector2 start, Vector2 end, float delay, float speed)
{
yield return new WaitForSeconds(delay);
while (slidingBlock.transform.position.y != end.y)
{
// Move towards end position over duration given
slidingBlock.transform.position = Vector2.MoveTowards(slidingBlock.transform.position, end, speed * Time.deltaTime);
yield return new WaitForEndOfFrame();
}
boxCollider.enabled = false;
slidingBlock.SetActive(false);
}
public void ResetSlidingBlock() // Called by another script when player dies
{
Debug.Log("Reset block");
slidingBlock.transform.position = new Vector2(X, startY);
slidingBlock.SetActive(true);
boxCollider.enabled = true;
}
}
This is the part of the other script that calls ResetSlidingBlock from the above script breakingBlock when the player dies.
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.name == "Player")
{
levelManager.RespawnPlayer();
breakingBlock.ResetSlidingBlock();
}
}
Why is it that only one of the blocks is respawning when separate gameobjects are specified in the separate scripts on completely distinct gameobjects?
You have a public GameObject where only one object is assigned. Doesn't matter how many objects you assign this script to, only that GameObject that you refer to will be reset. If you have X number of GameObjects that you want to follow the same properties, you can:
Make a prefab and access the children using transform.getchild() or tags - assign them to GameObjects
ex:
GameObject objs[];
for(int i=0;i<How many u want;i++)
{
objs[i]=GameObject.Find("ParentObj").transform.GetChild(i);
//something similar to this
}
Or Simply Make public references and assign them manually.
Ex:
public GameObject slideblock1;
public GameObject slideblock2;
etc.

Instantiating a prefab at the mouse position for my sandbox game

I can't manage to instantiate a prefab at my mouse position.
I've tried to instantiate the prefab at the current mouse position, but on click, the block shows in the hierarchy and not the scene. It also creates 4-5 prefabs.
using UnityEngine;
public class Building : MonoBehaviour
{
public GameObject block;
void Update()
{
if (Input.GetMouseButton(0))
{
Instantiate(block, new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f), Quaternion.identity);
}
}
}
I want to create 1 prefab of the block, and I want it to show up in the scene view.
Input.mousePosition is the coordinates of the mouse on the screen. Use Camera.ScreenToViewportPoint to get the world position.
The block will not show in the scene, because its position is likely something like (500, 300, 0), which is very far. Select the block in the Hierarchy and press "F" to see it.
Input.GetMouseButton() keeps firing as long as the mouse is held. Change this to Imput.GetMouseButtonDown()
using UnityEngine;
public class Building : MonoBehaviour {
public GameObject block;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition);
Instantiate(block, pos, Quaternion.identity);
}
}
}
You need to convert from screen space to world space.
One way to do this is to use Camera.ScreenToWorldPoint:
private Camera mainCam;
void Start()
{
mainCam = Camera.main;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 blockPos = mainCam.ScreenToWorldPoint(Input.mousePosition);
Instantiate(block, blockPos, 0f), Quaternion.identity);
}
}
If you want to spawn further away from the camera, look into Camera.ScreenPointToRay.

Unity 2D - sprite flicker while follow object

im creating simple script which tells gameobject that it needs to follow other gameobject in defined distance.
code:
void Update()
{
objPos = GameObject.FindGameObjectWithTag("Player").transform.position;
transform.position = new Vector3(objPos.x + 0.5f, objPos.y + 0.5f);
}
problem is: following gameobject is flickering. When you watch it, it appears to be few frames behind followed gameobject. I noticed it before in my earlier prototype but now its crutial for my new game. So i think its pretty common issue.
Is there sollution for this unwanted behaviour?
Thanks
GameObject.FindGameObjectWithTag("Player") has high performance cost, instead of using it each frame, hold an instance of the player. If the player is constant in the scene,
public Transform playerTransform;
void Update()
{
transform.position = playerTransform.position + new Vector3(0.5f, 0.5f);
}
and then assign the Player transform in Unity editor to this object using inspector. (Or dynamically in the code)
If your Player object gets destroyed and a new one instantiates once in a while, you can either assign the new one to the follower objects, or use a simple accessor method like this:
Transform _playerTransform;
Transform playerTransform
{
get
{
if(_playerTransform == null)
{
_playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
return _playerTransform;
}
}
void Update()
{
transform.position = playerTransform.position + new Vector3(0.5f, 0.5f);
}

Unity Game Engine Tutorial?

My game is a 2D RTS, and I was wondering if anyone knew of a good tutorial for Unity, or if someone well-versed in the syntax of it could tell me what I could have done wrong.
So, I have my camera object, and my player object, both tagged. The player object just has a sprite on it, and is set to rigidbody. The script goes as follows:
using UnityEngine;
using System.Collections;
public class AIsciript : MonoBehaviour
{
private bool thisIsPlayer = true;
private GameObject objPlayer;
private GameObject objCamera;
//input variables (variables used to process and handle input)
private Vector3 inputRotation;
private Vector3 inputMovement;
//identity variables (variables specific to the game object)
public float moveSpeed = 100f;
// calculation variables (variables used for calculation)
private Vector3 tempVector;
private Vector3 tempVector2;
// Use this for initialization
void Start()
{
objPlayer = (GameObject)GameObject.FindWithTag("Player");
objCamera = (GameObject)GameObject.FindWithTag("MainCamera");
if (gameObject.tag == "Player")
{
thisIsPlayer = true;
}
}
// Update is called once per frame
void Update()
{
FindInput();
ProcessMovement();
if (thisIsPlayer == true)
{
HandleCamera();
}
}
void FindInput()
{
if (thisIsPlayer == true)
{
FindPlayerInput();
}
else
{
FindAIInput();
}
}
void FindPlayerInput()
{
//find vector to move
inputMovement = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
//find vector to the mouse
tempVector2 = new Vector3(Screen.width * 0.5f, 0, Screen.height * 0.5f);
// the position of the middle of the screen
tempVector = Input.mousePosition;
// find the position of the mouse on screen
tempVector.z = tempVector.y;
tempVector.y = 0;
Debug.Log(tempVector);
inputRotation = tempVector - tempVector2;
}
void FindAIInput()
{
}
void ProcessMovement()
{
rigidbody.AddForce(inputMovement.normalized * moveSpeed * Time.deltaTime);
objPlayer.transform.rotation = Quaternion.LookRotation(inputRotation);
objPlayer.transform.eulerAngles = new Vector3(0, transform.eulerAngles.y + 180, 0);
objPlayer.transform.position = new Vector3(transform.position.x, 0, transform.position.z);
}
void HandleCamera()
{
objCamera.transform.position = new Vector3(transform.position.x, 15, transform.position.z);
objCamera.transform.eulerAngles = new Vector3(90, 0, 0);
}
}
I just figured I would post the code just in case, but I figure it's probably not the issue, as I tried to force it to move in Start() and nothing happened.
You shouldn't be using all those checks for thisIsPlayer. You should have separate classes for the player entity and non-player entities.
Public variables are exposed in the editor and get serialized with the entity when the level is saved. This could mean that moveSpeed is not currently set to what it is initialized to in this class.
You shouldn't add force to a rigidbody in the Update method. There's a FixedUpdate method that's used for applying physics. This is because Update is called once per frame, no matter what the framerate, and FixedUpdate is only called at specific intervals, so physics forces aren't affected by framerate.
Also, you shouldn't try to apply a force and set the position of the transform of the same object. Strange things will happen.
If you go into the Unity Asset Store (available in the Window menu within Unity) there is a section called "Complete Projects" that contains some free tutorials. I can't remember which of them is written in C#, but even the JavaScript ones will give you some ideas on how to structure the project.
I don't know if I understood it right: your problem is that it is not moved by the AI?
if this is so, one problem could be that you initialize your
private bool thisIsPlayer = true;
with true but I can not see any condition setting it to false (enter ai mode)
just my 2 cents :)

Categories

Resources