- Home /
Input problems with character controller (one scene) and menu (added from a global scene) ,Change Input between Menu and Character Controller
Hello everyone,
Intro:
I am only about 6 weeks into unity so forgive me that I'm still quite inexperienced and not perfect at creating a reproducible example. I'll try my best. I want to create a bridge construction simulator used for engineering education.
My project so far:
1) One global scene including a menu with a couple of buttons - This scene includes a canvas, a level manager, an event system and three buttons -A script for the level manager and main menu was written and attached 2) A background 3D scene This includes a terrain displayed behind the the main menu on simulator start and a camera 3) A scene for bridge 1 - This scene includes a terrain and a first person camera (consisting of a character controller and a mouse script) 4) A scene for bridge 2 - Similar content as in bridge 1 only a different terrain and bridge
What works:
- On start scene 1 and 2 load and thus we get a clickable main menu, loading the scenes 3 and 4 works fine
In scene 3 or 4 the character controller works fine when the scene is started. Clicking on escape brings back - as intended - the overlaying menu included in the global scene to the current scene.
In scene 3 or 4, time is paused and the mouse arrow returns
What doesn't work:
- In scene 3 or 4 I cannot click any more on the buttons and the functionality is lost
In scene 3 or 4, when enter is pressed, the character controller takes over again and first person controll works decent (however, the focus of the mouse to the middle of the screen is lost).
Problem:
I guess my problem is that the menu input script (global scene) and the character controller in scene 3 or scene 4 get into their way.
I will also share the code of the menu and character controller with you but it is rather long and includes a lot of code about saving the game.
I would really appreciate any ideas and help.
Best regards from Munich, Germany Max
Below are two screenshots (Screenshot 1: global scene + background scene; Screenshot 2: global scene + bridge 1) [1]: /storage/temp/182542-scenes.jpg [2]: /storage/temp/182544-scene2.jpg
Here is the code for the menu:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class MainMenu : MonoBehaviour
{
/// <summary>
/// Pointer on the root object that can display/ undisplay the menu
/// </summary>
public GameObject menuRoot;
public bool firstOpened;
private void Start()
{
menuRoot.SetActive(true); // Menu should be activated at start
Time.timeScale = 0f; // swith time off
firstOpened = true;
}
private void Update()
{
// If the Menu is opened for the first time we close this function
// People should not be able to click away the menu with escape here
if (firstOpened == true)
return;
// If escape is pressed, the canvas/menu is hidden
if(Input.GetButtonDown("Menu"))
{
menuRoot.SetActive(!menuRoot.activeSelf);
// If canvas is opened, time is put on hold
if (menuRoot.activeSelf)
{
Time.timeScale = 0f;
}
else
{
Time.timeScale = 1f;
}
}
}
// starts a new game when start button is pressed
public void OnButtonStart()
{
Debug.Log("Play pressed");
// Set firstOpened on false because menu has been used now
firstOpened = false;
SaveGameData.current = new SaveGameData();
// Use a level manager for loading the other scene
LevelManager lm = FindObjectOfType<LevelManager>(); // erstellt ein Objekt
lm.loadScene("Bridge1");
// Hide menu
menuRoot.SetActive(false);
Time.timeScale = 1f;
}
public void OnButtonOptions()
{
Debug.Log("Options pressed");
// Set firstOpened on false because menu has been used now
firstOpened = false;
// For loading we use a lavel manager
LevelManager lm = FindObjectOfType<LevelManager>(); // erstellt ein Objekt
lm.loadScene("Bridge2");
// Hide menu
menuRoot.SetActive(false);
Time.timeScale = 1f;
}
public void OnButtonQuit()
{
Debug.Log("Quit pressed");
Application.Quit();
}
}
Here is the code for the PlayerMovement (in scene 3 and 4, attached to a prefab):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This script controls the horizontal and vertical movement and gravity
/// Saveable is my own class for logfiles, but it inherits from monobehaviour
/// </summary>
public class PlayerMovement : Saveable
{
// this is the characterController that we need for the transform
public CharacterController controller;
// speed of movement
public float speed = 12f;
// gravity
public float gravity = -9.81f;
Vector3 velocity;
// jumping
public float jumpHeight = 3f;
// ground check with sphere
public Transform groundCheck;
public float groundDistance = 0.2f;
public LayerMask groundMask; // Layers for controlling what collides
bool isGrounded;
// Update is called once per frame
void Update()
{
// Groundcheck with sphere,
// If collision, then isGrounded = true
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if(isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
// This transform moves in the direction in which we are faced
Vector3 move = transform.right * x + transform.forward * y;
controller.Move(move * speed * Time.deltaTime);
// Jump action
// Attention: this only worked after giving the terrain a so-called "ground" layer,
// probably because the isGrounded Check needs that!
if(Input.GetButtonDown("Jump") == true && isGrounded == true)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
// applying gravity based on gravity strength and time passed
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
// This is the code for saving games
// On first load, a registration at base class takes place
override protected void Awake()
{
base.Awake(); // Elternklasse aufrufen
}
override protected void Start()
{
base.Start(); // Start base class
}
// This method must look like described in the save handler
override protected void saveme(SaveGameData savegame)
{
base.saveme(savegame);
// The player writes his transformed position in the savegame
savegame.playerPosition = transform.position;
savegame.recentScene = gameObject.scene.name; /
}
// This loads the current savegame
override protected void loadme(SaveGameData savegame)
{
base.loadme(savegame);
if(savegame.recentScene == gameObject.scene.name)
{
transform.position = savegame.playerPosition;
}
}
}
Answer by MCF33 · Jun 25, 2021 at 12:02 PM
Hello everybody,
I discovered the solution myself today and would like to share it with you. It was actually quite simple. After returning to the menu from the scene, the input was somehow lost. The following lines of code solved the problem by changing mouse settings.
Cursor.visible = true;
Cursor.lockState = CursorLockMode.Confined;
The following lines of code werde integrated in the update function in order to be able to switch between the first person shooter and the menu smoothly and with correct mouse input.
private void Update()
{
// If the Menu is opened for the first time we close this function
// People should not be able to click away the menu with escape here
if (firstOpened == true)
return;
// Wenn Escape gedrückt wird, wir der Canvas ausgeschaltet
// Hiermit wird also das Menü ein und ausgeschaltet
if(Input.GetButtonDown("Menu"))
{
menuRoot.SetActive(!menuRoot.activeSelf);
// Wenn der Canvas des Menüs offen ist, ist die Zeit ausgeschaltet
if (menuRoot.activeSelf)
{
Time.timeScale = 0f;
// wenn das Menü an ist, muss die Mauszeiger sichtbar sein und bewegung möglich
Cursor.visible = true;
Cursor.lockState = CursorLockMode.Confined;
}
else
{
Time.timeScale = 1f;
// wenn das Menü an ist, muss die Mauszeiger sichtbar sein und bewegung möglich
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
}
Best regards from Munich, Germany Max
Your answer
