I have a couple of UI Panels that I wish to move into the screen area.
I have made a script to attach to each Panel but it does little when I do my changes in Update which I am now using LateUpdate instead which almost works.
The panel will move into the screen only very slightly as if LateUpdate was called only once.
Oddly, when I do the same with a second Panel, it's 'HidePanel' method then lets the first Panel come fully into view. Then the first Panel's 'HidePanel' method works correctly.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class DisplayPanel : MonoBehaviour {
private bool isMovingIn = false;
private bool isMovingOut = false;
private Vector2 posOut; //The panel's position hidden just outside the RH screen edge.
private Vector2 posIn; //The panel’s position shown just inside the RH screen edge.
private Vector2 pos; //The panel’s current position.
//Initialization
void Start () {
RectTransform rt = GetComponent<RectTransform>();
posOut = new Vector2 ((Screen.width + rt.rect.width)/2, 0); //To be hidden just outside the RH screen edge.
posIn = new Vector2 (posOut.x - rt.rect.width, 0); //To be visible just inside the RH screen edge.
pos = posOut;
rt.anchoredPosition = pos; //Move panel to the RH screen edge.
}
public void LateUpdate() {
RectTransform rt = GetComponent<RectTransform> ();
rt.anchoredPosition = pos; //Need this for start..
if (isMovingIn == true) {
if ((int)pos.x != (int)posIn.x) { //Casting floats to ints so we can eventually find equality.
pos = Vector2.Lerp (pos, posIn, 2*Time.deltaTime);
rt.anchoredPosition = pos;
}
else {
isMovingIn = false; }
}
else
if (isMovingOut == true) {
if ( (int)pos.x != (int)posOut.x) {
pos = Vector2.Lerp (pos, posOut, 2 * Time.deltaTime);
rt.anchoredPosition = pos; }
else {
isMovingOut = false; }
}
}
public void DisplayPanel(){
isMovingOut = false;
isMovingIn = true;
}
public void HidePanel(){
isMovingIn = false;
isMovingOut = true;
}
}//End class
Related
I'm trying to set Panning and zooming functions for my unity project. I got the codes i used from https://kylewbanks.com/blog/unity3d-panning-and-pinch-Ito-zoom-camera-with-touch-and-mouse-input. This is the code I used:
using UnityEngine;
using System.Collections;
public class CameraHandler : MonoBehaviour {
private static readonly float PanSpeed = 20f;
private static readonly float ZoomSpeedTouch = 0.1f;
private static readonly float ZoomSpeedMouse = 0.5f;
private static readonly float[] BoundsX = new float[]{-10f, 5f};
private static readonly float[] BoundsZ = new float[]{-18f, -4f};
private static readonly float[] ZoomBounds = new float[]{10f, 85f};
private Camera cam;
private Vector3 lastPanPosition;
private int panFingerId; // Touch mode only
private bool wasZoomingLastFrame; // Touch mode only
private Vector2[] lastZoomPositions; // Touch mode only
void Awake() {
cam = GetComponent<Camera>();
}
void Update() {
if (Input.touchSupported && Application.platform != RuntimePlatform.WebGLPlayer) {
HandleTouch();
} else {
HandleMouse();
}
}
void HandleTouch() {
switch(Input.touchCount) {
case 1: // Panning
wasZoomingLastFrame = false;
// If the touch began, capture its position and its finger ID.
// Otherwise, if the finger ID of the touch doesn't match, skip it.
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began) {
lastPanPosition = touch.position;
panFingerId = touch.fingerId;
} else if (touch.fingerId == panFingerId && touch.phase == TouchPhase.Moved) {
PanCamera(touch.position);
}
break;
case 2: // Zooming
Vector2[] newPositions = new Vector2[]{Input.GetTouch(0).position, Input.GetTouch(1).position};
if (!wasZoomingLastFrame) {
lastZoomPositions = newPositions;
wasZoomingLastFrame = true;
} else {
// Zoom based on the distance between the new positions compared to the
// distance between the previous positions.
float newDistance = Vector2.Distance(newPositions[0], newPositions[1]);
float oldDistance = Vector2.Distance(lastZoomPositions[0], lastZoomPositions[1]);
float offset = newDistance - oldDistance;
ZoomCamera(offset, ZoomSpeedTouch);
lastZoomPositions = newPositions;
}
break;
default:
wasZoomingLastFrame = false;
break;
}
}
void HandleMouse() {
// On mouse down, capture it's position.
// Otherwise, if the mouse is still down, pan the camera.
if (Input.GetMouseButtonDown(0)) {
lastPanPosition = Input.mousePosition;
} else if (Input.GetMouseButton(0)) {
PanCamera(Input.mousePosition);
}
// Check for scrolling to zoom the camera
float scroll = Input.GetAxis("Mouse ScrollWheel");
ZoomCamera(scroll, ZoomSpeedMouse);
}
void PanCamera(Vector3 newPanPosition) {
// Determine how much to move the camera
Vector3 offset = cam.ScreenToViewportPoint(lastPanPosition - newPanPosition);
Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed);
// Perform the movement
transform.Translate(move, Space.World);
// Ensure the camera remains within bounds.
Vector3 pos = transform.position;
pos.x = Mathf.Clamp(transform.position.x, BoundsX[0], BoundsX[1]);
pos.z = Mathf.Clamp(transform.position.z, BoundsZ[0], BoundsZ[1]);
transform.position = pos;
// Cache the position
lastPanPosition = newPanPosition;
}
void ZoomCamera(float offset, float speed) {
if (offset == 0) {
return;
}
cam.fieldOfView = Mathf.Clamp(cam.fieldOfView - (offset * speed), ZoomBounds[0], ZoomBounds[1]);
}
}
The Panning and Zooming are working fine but only works when i make transform.position = pos; a comment. This line is what messes my entire panning and zooming system up. Once i make it a comment, The panning and zooming works, but without boundaries. And i need those boundaries. I'm using a terrain for my scene. that's where my entire project settles on.
What happens is when i press play on my unity editor, it all looks fine until i click on the screen. Once my mouse button touches the screen on play mode, my camera just faces an entirely different direction. The entire camera translate changes, i won't even see any of the Gameobjects on my scene anymore. Does anyone know where the problem could be coming from?
I want that once the clicking on the object one time then I will be able to drag the object around with the mouse without holding down the left mouse button. Then next time making one click on the mouse left button it will drop the object.
Now I must hold down the mouse left button.
using System;
using System.Collections;
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class DragRigidbody : MonoBehaviour
{
const float k_Spring = 50.0f;
const float k_Damper = 5.0f;
const float k_Drag = 10.0f;
const float k_AngularDrag = 5.0f;
const float k_Distance = 0.2f;
const bool k_AttachToCenterOfMass = false;
private SpringJoint m_SpringJoint;
private void Update()
{
// Make sure the user pressed the mouse down
if (!Input.GetMouseButtonDown(0))
{
return;
}
var mainCamera = FindCamera();
// We need to actually hit an object
RaycastHit hit = new RaycastHit();
if (
!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition).origin,
mainCamera.ScreenPointToRay(Input.mousePosition).direction, out hit, 100,
Physics.DefaultRaycastLayers))
{
return;
}
// We need to hit a rigidbody that is not kinematic
if (!hit.rigidbody || hit.rigidbody.isKinematic)
{
return;
}
if (!m_SpringJoint)
{
var go = new GameObject("Rigidbody dragger");
Rigidbody body = go.AddComponent<Rigidbody>();
m_SpringJoint = go.AddComponent<SpringJoint>();
body.isKinematic = true;
}
m_SpringJoint.transform.position = hit.point;
m_SpringJoint.anchor = Vector3.zero;
m_SpringJoint.spring = k_Spring;
m_SpringJoint.damper = k_Damper;
m_SpringJoint.maxDistance = k_Distance;
m_SpringJoint.connectedBody = hit.rigidbody;
StartCoroutine("DragObject", hit.distance);
}
private IEnumerator DragObject(float distance)
{
var oldDrag = m_SpringJoint.connectedBody.drag;
var oldAngularDrag = m_SpringJoint.connectedBody.angularDrag;
m_SpringJoint.connectedBody.drag = k_Drag;
m_SpringJoint.connectedBody.angularDrag = k_AngularDrag;
var mainCamera = FindCamera();
while (Input.GetMouseButton(0))
{
var ray = mainCamera.ScreenPointToRay(Input.mousePosition);
m_SpringJoint.transform.position = ray.GetPoint(distance);
yield return null;
}
if (m_SpringJoint.connectedBody)
{
m_SpringJoint.connectedBody.drag = oldDrag;
m_SpringJoint.connectedBody.angularDrag = oldAngularDrag;
m_SpringJoint.connectedBody = null;
}
}
private Camera FindCamera()
{
if (GetComponent<Camera>())
{
return GetComponent<Camera>();
}
return Camera.main;
}
}
}
Instead of
while(Input.GetMouseButton(0))
use
while(!Input.GetMouseButtonDown(0))
Then you still have to catch whether you maybe are already dragging and skip in this case the begining of a drag.
E.g. with a book like
bool isDragging;
private void Update()
{
if(!Input.GetMouseButtonDown(0) || isDragging) return;
...
}
private IEnumerator DragObject()
{
isDragging = true;
...
while(!Input.GetMouseButtonDown(0))
{
...
}
...
isDragging = false;
}
Further note: Usage of Camera.main or even worse GetComponent repeatedly is quite inefficient. Rather store the result once and reuse it:
// If possible already reference it via the Inspector!
[SerializeField] private Camera mainCamera;
// Or get and store it once
private void Awake ()
{
FetchComponents ();
}
// Little pro tip ;)
// using this you can already in the Inspector click on the context menu
// and click on "FetchComponents"
// this way you don't have to sear for it manually
// and additionally you can see if it works as expected
[ContextMenu (nameof(FetchComponents))]
private void FetchComponents ()
{
if(!mainCamera) mainCamera = GetComponent<Camera>();
if(!mainCamera) mainCamera = Camera.main;
}
Ok, I am having a problem with a Unity scroll panel in C#. I downloaded this character picker that consists of a script attached to a scroll panel from here:
https://www.youtube.com/watch?v=YBsGhYuTavA
It works very well but problem is I cant make it scroll vertically instead of horizontal. I have checked the "vertical" boolean instead of horizontal on the actual scroll panel then in the script I have changed the places that based off x values to y values.
I commented where, here is the script:
float[] distance;
bool dragging = false;
int minButtonNum;
int currentSelectedPly = -1;
public float objectScale = 1.7f;
public int bttnDistance = 300;
void OnEnable() {
//txtGeneralCash.text = "" + PlayerPrefs.GetInt ("money", 0);
}
void Start(){
distance = new float[prefab.Length];
//instatiate the prefab
for(int i=0; i<prefab.Length;i++){
prefab[i] = Instantiate(prefab[i],center.transform.position,camInUse.transform.rotation) as GameObject;
prefab [i].transform.SetParent(panel.transform);
Vector3 pos = prefab[i].GetComponent<RectTransform>().anchoredPosition;
pos.x += (i * bttnDistance); //**CHANGED TO POS.Y
prefab [i].GetComponent<RectTransform> ().anchoredPosition = pos;
}
}
void Update(){
//calculate the relative distance
for(int i=0;i<prefab.Length;i++){
distance [i] = Mathf.Abs (center.transform.position.x - prefab [i].transform.position.x); //CHANGED THESE TO .Y
}
float minDistance = Mathf.Min (distance);
// Aplly the scale to object
for(int a=0;a<prefab.Length;a++){
if (minDistance == distance [a]) {
minButtonNum = a;
//this is when each char is selected !!!!!!!!!!!!!!!
if(minButtonNum != currentSelectedPly){
//lookAtPrice (minButtonNum);
scaleButtonCenter (minButtonNum);
currentSelectedPly = minButtonNum;
txtName.text = prefab [minButtonNum].GetComponent<CharacterProperty> ().nameObj;
bgMat.color = prefab [minButtonNum].GetComponent<CharacterProperty> ().color;
}
}
}
// if the users aren't dragging the lerp function is called on the prefab
if(!dragging){
LerpToBttn (currentSelectedPly* (-bttnDistance));
}
}
/*
* Lerp the nearest prefab to center
*/
void LerpToBttn(int position){
float newX = Mathf.Lerp (panel.anchoredPosition.x,position,Time.deltaTime*7f); //CHANGED TO .Y
Vector2 newPosition = new Vector2 (newX,panel.anchoredPosition.y);
panel.anchoredPosition = newPosition;
}
/*
* Set the scale of the prefab on center to 2, other to 1
*/
public void scaleButtonCenter (int minButtonNum){
for (int a = 0; a < prefab.Length; a++) {
if (a == minButtonNum) {
StartCoroutine (ScaleTransform(prefab [a].transform,prefab [a].transform.localScale,new Vector3 (objectScale,objectScale,objectScale)));
} else {
StartCoroutine (ScaleTransform(prefab [a].transform,prefab [a].transform.localScale,new Vector3 (1f, 1f, 1f)));
}
}
}
/*
* If the prefab is not free, show the price button
/*
* Courutine for change the scale
*/
IEnumerator ScaleTransform(Transform transformTrg,Vector3 initScale,Vector3 endScale){
float completeTime = 0.2f;//How much time will it take to scale
float currentTime = 0.0f;
bool done = false;
while (!done){
float percent = currentTime / completeTime;
if (percent >= 1.0f){
percent = 1;
done = true;
}
transformTrg.localScale = Vector3.Lerp(initScale, endScale, percent);
currentTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
}
/*
* Called by the canvas, set dragging to true for preventing lerp when users are dragging
*/
public void StartDrag(){
dragging = true;
}
/*
* Called by the canvas, set dragging to true for preventing lerp when users are dragging
*/
public void EndDrag(){
dragging = false;
}
/*
* Called when character is selected, it change the player model
*/
public void CharacterSelected(){
bool oneEnable = false;
string nameSelected = prefab [currentSelectedPly].GetComponent<CharacterProperty> ().name;
nameSelected = nameSelected.Split('(')[0];
GameObject player = GameObject.Find ("CharactersPlayer");
if(player != null){
foreach (Transform child in player.transform) {
if (child.gameObject.name == nameSelected) {
child.gameObject.SetActive (true);
oneEnable = true;
PlayerPrefs.SetString ("SelectedPlayer", nameSelected);
} else {
child.gameObject.SetActive (false);
}
}
// if no one was selected
if (oneEnable == false) {
player.transform.GetChild (0).gameObject.SetActive (true);
}
}
}
Ive gone through it several times and I don't know why just changing the values from .x to .y does not work. I get a bunch of glitching and the characters do stack up vertically, but they move off the screen when i try to scroll.
How can I fix this?
This script controls the cameras FOV when "Fire2" is pressed as well as displaying a GUI texture. However, once the user presses the button once, the texture displays and does not disappear until the button is pressed again - I want it to only show when the button is held down? This script is attached to a prefab which is a child object of the player prefab. I have tried to just use GetButton but seeing as OnGUI() is called every frame as well as the Update() function it just made the texture flicker.
using UnityEngine;
using System.Collections;
public class awpScopeIn : MonoBehaviour {
public Texture scopeGUI;
private bool _isScoped = false;
public Color color = Color.black;
private Camera cam;
public GameObject awp_graphics;
void Start()
{
cam = GetComponentInParent( typeof(Camera) ) as Camera;
cam.clearFlags = CameraClearFlags.SolidColor;
cam.fieldOfView = 70f;
}
void OnGUI()
{
float width = 600;
float height = 600;
if (_isScoped) {
GUI.DrawTexture (new Rect ((Screen.width / 2) - (width/2), (Screen.height / 2) - (height/2), width, height), scopeGUI);
}
}
void Update()
{
if(Input.GetButtonDown("Fire2"))
{
_isScoped = !_isScoped;
cam.backgroundColor = color;
cam.fieldOfView = 45f;
awp_graphics.gameObject.SetActive(false);
}else if(Input.GetButtonUp("Fire2"))
{
cam.fieldOfView = 70f;
awp_graphics.gameObject.SetActive(true);
}
}
}
You are just changing the value when the button is pressed but you have to update the flag for showing texture when the button is released. So your Update method should be:
if(Input.GetButtonDown("Fire2"))
{
_isScoped = !_isScoped;
cam.backgroundColor = color;
cam.fieldOfView = 45f;
awp_graphics.gameObject.SetActive(false);
}else if(Input.GetButtonUp("Fire2"))
{
cam.fieldOfView = 70f;
awp_graphics.gameObject.SetActive(true);
_isScoped = false;
}
I'm trying to display a simple rectangle right in front of my OVRPlayerController's camera but it seems to be impossible.
I think it might have something to do with the fact that Rect is 2D and my environment is 3D. Does that make sense?
The code is the following (I have ommited the unnecessary stuff):
static int MAX_MENU_OPTIONS = 3;
public GameObject Menu;
private bool showMenu = false;
private float menuIndex = 0;
private bool hasPressedDirectionalPad = false;
public Transform[] buttons = new Transform[MAX_MENU_OPTIONS];
private static Texture2D staticRectTexture;
private static GUIStyle staticRectStyle;
bool DpadIsPressed() {
if (!hasPressedDirectionalPad && Input.GetAxis("DpadY") != 0 && hasPressedDirectionalPad == false){
menuIndex += Mathf.Sign(Input.GetAxis("DpadY")) * (-1);
if (menuIndex < 0) menuIndex = 0;
else if (menuIndex > MAX_MENU_OPTIONS-1) menuIndex = MAX_MENU_OPTIONS-1;
hasPressedDirectionalPad = true;
}
if(Input.GetAxis("DpadY") == 0){
hasPressedDirectionalPad = false;
}
return hasPressedDirectionalPad;
}
void Start() {
Menu.SetActive(false);
staticRectTexture = new Texture2D(1, 1, TextureFormat.RGB24, true);
staticRectStyle = new GUIStyle();
}
void Update() {
if (Input.GetButtonDown("A")) {
DoAction ();
print ("A key was pressed");
}
if (Input.GetButtonDown("Options")) {
showMenu = !showMenu;
if (showMenu) {
Time.timeScale = 0;
menuIndex = 0;
Menu.transform.rotation = this.transform.rotation;
Menu.transform.position = this.transform.position;
} else
Time.timeScale = 1;
}
if (DpadIsPressed ()) {
print ("Dpad key was pressed and menuIndex = " + menuIndex);
}
if (showMenu) {
Menu.SetActive (true);
}
if (!showMenu) {
Menu.SetActive (false);
}
}
void OnGUI() {
if (showMenu) {
Vector3 offset = new Vector3(0, 0, 0.2f);
Vector3 posSelectRectangle = buttons[(int)menuIndex].transform.position + offset;
Rect selectionRectangle = new Rect(posSelectRectangle.x - (float)177/2,
posSelectRectangle.y - (float)43/2,
177.0f, 43.0f);
GUIDrawRect(selectionRectangle, new Color(255.0f, 0, 0));
}
}
void DoAction () {
if (menuIndex == 0)
Salir ();
/*else if (menuIndex == 1)
Guardar ();*/
else if (menuIndex == 2)
Salir ();
}
public static void GUIDrawRect(Rect position, Color color ) {
staticRectTexture.SetPixel( 0, 0, color );
staticRectTexture.Apply();
staticRectStyle.normal.background = staticRectTexture;
GUI.Box( position, GUIContent.none, staticRectStyle );
}
The functions are visited, but the rectangle doesn't show up. Do you see the mistake? Maybe it has something to do with the Oculus Rift?
OnGUI and Screen-space Canvas are not supported in VR mode. This is because there is no way to handle stereoscopic rendering. (Note: They will render to the duplicate display on the user's PC though).
If you want to render in front of the user's camera (like a HUD), you can:
Use a Canvas:
Create a canvas, then add your UI, and set the canvas in world-space. Parent the canvas to the VR Camera game object, and scale it down (it defaults to very very big) and rotate it so it faces the camera.
Or, Use 3D:
Create a 3d Object (Plane, Cube, Quad, whatever!) and parent it to your VR Camera. You can use standard 3d techniques to update it's texture or render texture.