I have included the following line to show a simple timer in the top left corner of a scene, which works of course, but when I tick the Virtual Reality Supported check-box and put on an Oculus Rift, it disappears.
void OnGUI()
{
GUI.Label(new Rect(10, 10, 100, 20), Time.time.ToString());
}
What am I missing? What should I do additionally to resolve this?
OnGUI() does not work in VR. Instead use world space canvas UI.
I did the following for the Gear-VR.
Add a canvas (or other UI elements containing "Canvas" component) to your scene. Set render mode to World Space. This can be found on the render mode drop down list for the UI Canvas object:
I ended up going for an 800 x 600 canvas.
For the timer itself I used Time.deltaTime.
Here is my whole PlayerController script:
void Start ()
{
timeLeft = 5;
rb = GetComponent<Rigidbody>();
count = 0;
winText.text = "";
SetCountText ();
}
void Update() {
if (gameOver) {
if (Input.GetMouseButtonDown(0)) {
Application.LoadLevel(0);
}
} else {
timeLeft -= Time.deltaTime;
timerText.text = timeLeft.ToString("0.00");
if (timeLeft < 0) {
winner = false;
GameOver(winner);
}
}
}
void GameOver(bool winner) {
gameOver = true;
timerText.text = "-- --";
string tryAgainString = "Tap the touch pad to try again.";
if (!winner) { // case A
winText.text = "Time's up.\n" + tryAgainString;
}
if (winner) { // case B
winText.text = "Well played!\n" + tryAgainString;
}
}
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis ("Mouse X");
float moveVertical = Input.GetAxis ("Mouse Y");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ( "Pick Up")){
other.gameObject.SetActive (false);
count = count + 1;
SetCountText ();
if (!gameOver) {
timeLeft += 3;
}
}
}
void SetCountText ()
{
if (!gameOver) {
countText.text = "Count: " + count.ToString ();
}
if (count >= 12) {
winner = true;
GameOver(winner);
}
}
OnGUI does not work in VR. You have to use world space canvas UI.
Related
So I made a snake game in unity but whenever the snake grows the segment that should be added to the snake dissappears when i change the direction and idk why.
Here's the code:
private void FixedUpdate()
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector2(
Mathf.Round(this.transform.position.x) + sobolan.x,
Mathf.Round(this.transform.position.y) + sobolan.y
);
}
private void Grow()
{
Transform segment = Instantiate(this.segmentPrefab);
segment.position = _segments[_segments.Count - 1].position;
_segments.Add(segment);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Food")
{
Grow();
}
}
When the player hits the ground the camera shakes and when he jumps he just get's teleported up in an unsmooth manner
public class PlayerController : MonoBehaviour {
CharacterController controller;
Vector3 motion = Vector3.zero;
#region Movement Variables
public float walkingSpeed = 4f;
public float runningSpeed = 6f;
public float jumpSpeed = 5f;
public float gravity = 9.8f;
#endregion Movement Variables
void Start () {
controller = GetComponent<CharacterController>();
}
void Update () {
motion = Vector3.zero;
motion.x = Input.GetAxis("Horizontal");
if (controller.isGrounded && Input.GetAxis("Vertical")>0) motion.y += jumpSpeed;
if (Input.GetKey(KeyCode.LeftShift))
{
motion.x *= runningSpeed;
}
else
{
motion.x *= walkingSpeed;
}
motion.y -= gravity;
}
void FixedUpdate()
{
controller.Move(motion * Time.deltaTime);
}
}
I'm trying to create smooth movement and currently it is not reliable at all. thanks for any helpers
Take controller.Move(motion * Time.deltaTime); out of FixedUpdate and put it at the very end of Update method.
In case you have some script on camera as well, for example, some implementation of a follow camera where you're working with the transform component of that camera in the Update loop, that should go in LateUpdate instead.
See this https://learn.unity.com/tutorial/update-and-fixedupdate#5c8a4242edbc2a001f47cd63
and https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html
This implementation of a player controller for GameObject that has a Character Controller component may also help you.
void Update()
{
if (isDead) return;
isWalking = Input.GetButton("Walk");
isGrounded = characterController.isGrounded;
if (isGrounded)
{
// Move
float verticalAxis = Input.GetAxis("Vertical");
moveDirection = new Vector3(0, 0, verticalAxis);
moveDirection = transform.TransformDirection(moveDirection);
if (verticalAxis > 0 && isWalking)
{
moveDirection *= walkingSpeed;
}
else if (verticalAxis > 0)
{
moveDirection *= runningSpeed;
}
// Jump
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
//moveDirection.z = jumpDistance; in case some forward boost is required
moveDirection = transform.TransformDirection(moveDirection);
}
}
// Gravity
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
// Rotation
float horizontalAxis = Input.GetAxis("Horizontal");
transform.Rotate(0, horizontalAxis, 0);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.FromToRotation(transform.up, GetHitNormal()) * transform.rotation, yRotationSpeed * Time.deltaTime);
}
// To keep local up aligned with global up on a slope ground
private Vector3 GetHitNormal()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, Vector3.down, out hit))
return hit.normal;
else
return Vector3.zero;
}
I am using Xamarin.Android to use inbuilt camera app to take a photo
but there are two missed things that I cant do and I have been googling them for long time:
I want to get a msg or popup (anything) after pressing the button to take a photo like "photo taken"
I want to let the user focus on any point of the camera - TAP TO FOCUS
async void TakePhotoButtonTapped(object sender, EventArgs e)
{
camera.StopPreview();
Android.Hardware.Camera.Parameters parameters = camera.GetParameters();
parameters.FocusMode = global::Android.Hardware.Camera.Parameters.FocusModeAuto;
camera.SetParameters(parameters);
var image = textureView.Bitmap;
try
{
var absolutePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim).AbsolutePath;
var folderPath = absolutePath + "/Camera";
var filePath = System.IO.Path.Combine(folderPath, string.Format("photo_{0}.jpg", Guid.NewGuid()));
var fileStream = new FileStream(filePath, FileMode.Create);
await image.CompressAsync(Bitmap.CompressFormat.Jpeg, 92, fileStream);
fileStream.Close();
image.Recycle();
var intent = new Android.Content.Intent(Android.Content.Intent.ActionMediaScannerScanFile);
var file = new Java.IO.File(filePath);
var uri = Android.Net.Uri.FromFile(file);
intent.SetData(uri);
MainActivity.Instance.SendBroadcast(intent);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ", ex.Message);
}
camera.StartPreview();
}
I tried this but not working:
public void OnAutoFocus(bool success, Android.Hardware.Camera camera)
{
var parameters = camera.GetParameters();
if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeContinuousPicture)
{
parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;
if (parameters.MaxNumFocusAreas > 0)
{
parameters.FocusAreas = null;
}
camera.SetParameters(parameters);
camera.StartPreview();
}
}
public bool OnTouch(Android.Views.View view, MotionEvent e)
{
if (camera != null)
{
var parameters = camera.GetParameters();
camera.CancelAutoFocus();
Rect focusRect = CalculateTapArea(e.GetX(), e.GetY(), 1f);
if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeAuto)
{
parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeAuto;
}
if (parameters.MaxNumFocusAreas > 0)
{
List<Area> mylist = new List<Area>();
mylist.Add(new Android.Hardware.Camera.Area(focusRect, 1000));
parameters.FocusAreas = mylist;
}
try
{
camera.CancelAutoFocus();
camera.SetParameters(parameters);
camera.StartPreview();
camera.AutoFocus(this);
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
Console.Write(ex.StackTrace);
}
return true;
}
return false;
}
private Rect CalculateTapArea(object x, object y, float coefficient)
{
var focusAreaSize = 500;
int areaSize = Java.Lang.Float.ValueOf(focusAreaSize * coefficient).IntValue();
int left = clamp((int) x - areaSize / 2, 0, textureView.Width - areaSize);
int top = clamp((int) y - areaSize / 2, 0, textureView.Height - areaSize);
RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
Matrix.MapRect(rectF);
return new Rect((int) System.Math.Round(rectF.Left), (int) System.Math.Round(rectF.Top), (int) System.Math.Round(rectF.Right),
(int) System.Math.Round(rectF.Bottom));
}
private int clamp(int x, int min, int max)
{
if (x > max)
{
return max;
}
if (x < min)
{
return min;
}
return x;
}
For focusing the camera when touching the preview you will need to:
Add a touch event handler to listen for the user touching the preview
Get the X and Y coordinates from that touch event, which are usually in the event arguments
Create a rectangle to focus to tell the Android Camera where to focus and in which area
Set FocusAreas and MeteringAreas on Camera.Parameters from your rectangle
Set the new Camera.Parameters on the camera
Set a AutoFocus callback on the camera
When the callback triggers, remove the callback from the camera, and cancel auto focus
To notify the user about a picture being taken, you can use a Toast or create a area in your preview where you want to show such messages. It is entirely up to you how you want to notify the user.
I wrote some code that allows the user to instantiate objects in editor mode by loading the input images in streaming assets and then creating objects using these images.
This has worked well, the problem is when I try to create a prefab with one of these objects. For some reason, the image is not saved in the prefab, and so when I load that prefab, I get white images instead of the ones that were in the original gameobject.
Update: It turns out that my background screen is actually working correctly, but none of the other gameobjects are. So I am not sure what is wrong and why it is only working for some objects but not the other.
here is my code:
public class PlacementObject : MonoBehaviour
{
private loadbackgroundImages backgroundReference;
public Sprite mouseShape;
private Image mouseSprite;
private RectTransform mouseMovement;
public Canvas myCanvas;
private int currentState = 0;
private bool canMove = true;
public List<Texture2D> allButtons;
private List<Sprite> allButtonsSprite;
private List<Sprite> allUISprites;
private List<Texture2D> allUIElements;
private int uiButtonStates = 0;
private int uiElementStates = 0;
public GameObject afterImport;
private GameObject clonedObject;
public GameObject child;
public GameObject objectToBeExported;
private bool isLoading = true;
private bool isfinishedUploading;
private Vector2 defaultSize;
// Use this for initialization
void Start()
{
allUIElements = new List<Texture2D>();
allButtons = new List<Texture2D>();
var info = new DirectoryInfo(Application.streamingAssetsPath + "/" + "UIButtons");
var fileInfo = info.GetFiles();
foreach (FileInfo file in fileInfo)
{
if (file.Extension == ".png" || file.Extension == ".jpg")
{
StartCoroutine(uploadButtonImages(System.IO.Path.Combine("file:///" + Application.streamingAssetsPath, "UIButtons/" + file.Name)));
}
}
var info2 = new DirectoryInfo(Application.streamingAssetsPath + "/" + "UIElements");
var fileInfo2 = info2.GetFiles();
foreach (FileInfo file2 in fileInfo2)
{
if (file2.Extension == ".png" || file2.Extension == ".jpg")
{
StartCoroutine(uploadUiImages(System.IO.Path.Combine("file:///" + Application.streamingAssetsPath, "UIElements/" + file2.Name)));
}
}
allButtonsSprite = new List<Sprite>();
allUISprites = new List<Sprite>();
//createSpritesForButtons(allButtons);
// createSpritesForElements(allUIElements);
mouseSprite = GetComponent<Image>();
mouseSprite.sprite = mouseShape;
mouseMovement = GetComponent<RectTransform>();
backgroundReference = FindObjectOfType<loadbackgroundImages>();
isfinishedUploading = true;
defaultSize = mouseMovement.sizeDelta;
}
// Update is called once per frame
void Update()
{
print(isLoading);
if (isfinishedUploading && backgroundReference.isfinished)
{
isLoading = false;
}
Cursor.visible = false;
transform.position = Input.mousePosition;
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(myCanvas.transform as RectTransform, Input.mousePosition, myCanvas.worldCamera, out pos);
transform.position = myCanvas.transform.TransformPoint(pos);
if (isLoading == false)
{
if (currentState == 2)
{
mouseSprite.sprite = allUISprites[uiElementStates];
}
if (currentState == 1)
{
mouseSprite.sprite = allButtonsSprite[uiButtonStates];
}
if (Input.GetKeyDown(KeyCode.V))
{
currentState = 0;
mouseSprite.sprite = mouseShape;
mouseMovement.sizeDelta = defaultSize;
}
else if (Input.GetKeyDown(KeyCode.B))
{
currentState = 1;
}
else if (Input.GetKeyDown(KeyCode.N))
{
currentState = 2;
}
if (Input.GetMouseButtonDown(0))
{
placeObject();
}
if (Input.GetAxis("Horizontal") > 0 && canMove)
{
canMove = false;
if (currentState == 0)
{
changeBackgroundNext();
}
else if (currentState == 1)
{
changeButtonNext();
}
else if (currentState == 2)
{
changeElementNext();
}
}
if (Input.GetMouseButton(1))
{
rotateObject();
}
if (Input.GetAxis("Vertical") < 0)
{
if (currentState == 1 || currentState == 2)
{
mouseMovement.sizeDelta -= new Vector2(1, 1);
}
}
if (Input.GetAxis("Vertical") > 0)
{
if (currentState == 1 || currentState == 2)
{
mouseMovement.sizeDelta += new Vector2(1, 1);
}
}
if (Input.GetAxis("Horizontal") < 0 && canMove)
{
canMove = false;
if (currentState == 0)
{
changeBackgroundPrev();
}
else if (currentState == 1)
{
changeButtonPrev();
}
else if (currentState == 2)
{
changeElementPrev();
}
}
if (Input.GetAxis("Horizontal") == 0)
{
canMove = true;
}
if (Input.GetKeyDown(KeyCode.Space))
{
var newBackgroundSprite = backgroundReference.allSprites[backgroundReference.imageIndex];
backgroundReference.imageReference.sprite = newBackgroundSprite;
// exportObject();
// importObject();
#if UNITY_EDITOR
var prefab = PrefabUtility.CreatePrefab( "Assets/Resources/Image.prefab", FindObjectOfType<loadbackgroundImages>().gameObject);
AssetDatabase.Refresh();
#endif
}
}
}
void rotateObject()
{
if (currentState == 1 || currentState == 2)
mouseMovement.eulerAngles += new Vector3(0, 0, 1);
}
private void exportObject()
{
UIData saveData = new UIData();
saveData.inputObject = objectToBeExported;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "UI");
}
public void importObject()
{
UIData loadedData = DataSaver.loadData<UIData>("UI");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.inputObject);
afterImport = loadedData.inputObject;
}
private void changeBackgroundNext()
{
backgroundReference.imageIndex++;
if (backgroundReference.imageIndex >= backgroundReference.allSprites.Count)
{
backgroundReference.imageIndex = 0;
}
}
private void changeButtonNext()
{
uiButtonStates++;
if (uiButtonStates >= allButtonsSprite.Count)
{
uiButtonStates = 0;
}
}
private void changeElementNext()
{
uiElementStates++;
if (uiElementStates >= allUISprites.Count)
{
uiElementStates = 0;
}
}
private void changeElementPrev()
{
uiElementStates--;
if (uiElementStates < 0)
{
uiElementStates = allUISprites.Count - 1;
}
}
private void changeButtonPrev()
{
uiButtonStates--;
if (uiButtonStates < 0)
{
uiButtonStates = allButtonsSprite.Count - 1;
}
}
private void changeBackgroundPrev()
{
backgroundReference.imageIndex--;
if (backgroundReference.imageIndex < 0)
{
backgroundReference.imageIndex = backgroundReference.allSprites.Count - 1;
}
}
IEnumerator uploadButtonImages(string url)
{
WWW www = new WWW(url);
yield return www;
if (www != null)
{
allButtons.Add(www.texture);
allButtonsSprite.Add(Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(0.5f, 0.5f)));
}
}
private void createSpritesForButtons(List<Texture2D> allTextures)
{
for (int i = 0; i < allTextures.Count; i++)
{
Sprite tempSprite = Sprite.Create(allTextures[i], new Rect(0, 0, allTextures[i].width, allTextures[i].height), new Vector2(0.5f, 0.5f));
tempSprite.name = "Button" + i;
allButtonsSprite.Add(tempSprite);
}
}
IEnumerator uploadUiImages(string url)
{
WWW www = new WWW(url);
yield return www;
print(url);
if (www != null)
{
allUIElements.Add(www.texture);
allUISprites.Add(Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(0.5f, 0.5f)));
}
}
private void createSpritesForElements(List<Texture2D> allTextures)
{
for (int i = 0; i < allTextures.Count; i++)
{
Sprite tempSprite = Sprite.Create(allTextures[i], new Rect(0, 0, allTextures[i].width, allTextures[i].height), new Vector2(0.5f, 0.5f));
tempSprite.name = "" + i;
allUISprites.Add(tempSprite);
}
}
private void placeObject()
{
if (currentState == 1)
{
var gameObject = Instantiate(child, transform.position, Quaternion.Euler(mouseMovement.eulerAngles.x, mouseMovement.eulerAngles.y, mouseMovement.eulerAngles.z), backgroundReference.transform);
gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(mouseMovement.sizeDelta.x, mouseMovement.sizeDelta.y);
var newSprite = allButtonsSprite[uiButtonStates];
gameObject.GetComponent<Image>().sprite = newSprite;
gameObject.AddComponent<Button>();
}
if (currentState == 2)
{
var gameObject = Instantiate(child, transform.position, Quaternion.Euler(mouseMovement.eulerAngles.x, mouseMovement.eulerAngles.y, mouseMovement.eulerAngles.z), backgroundReference.transform);
gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(mouseMovement.sizeDelta.x, mouseMovement.sizeDelta.y);
var newSprite = allUISprites[uiElementStates];
gameObject.GetComponent<Image>().sprite = newSprite;
}
}
}
When you're changing some object's state via an inspector script you have to tell Unity, that you've done some changes, otherwise it doesn't know that something has happened to objects at the scene. And according to the information about changes on your scene (also when you change it manually, not by script) Unity serializes all data on your scene to save all the information. And when you load scene (doesn't matter in editor or in play mode) Unity deserializes all the objects on scene to show you. As far as serializing/deserializng object is rather expensive operation Unity only does it when it's really necessary - in case of saving scene/object it's only performed when it knows that there're some changes that needs to be saved.
The actual solution of your problem depends on Unity version you're using. Try reading this post. Such things as Undo and MarkAllScenesDirty should help you. For older versions of Unity EditorUtility.SetDirty should help.
So as people pointed out like Vmchar, when you save the prefab using code. it gets saved using the initial state without any of the stuff that got loaded to it during runtime.
I found out a solution for this though, all you need to do is make a script that would save the image by serializing it in streamingassets (plenty of tutorials online on how to serialize image), and then loading it using www stream when needed in the other scene.
I have a game like WorldSearch on Store, I tried using this solution:
I created matrix by array of TextView and added TouchEvent on each TextView. Then I caught event by MOTION.UP, MOTION.DOWN. When I touched on a TextView and dragged it, although it went thought other TextViews but I just could get event of first TextView.
Here is code:
private void createMetrix(){
// amound of item in a row and column
int itemNum = 10;
// calculate size of item
ScreenDimension screenDimension = Utilities.getFinalScreenDimension(this);
int itemSize = screenDimension.screenWidth / 10;
// mContentLinear has VERTICAL orientation
// then adding children linear layouts, these layout has HORIZONTAL orientation
for(int i = 0; i < itemNum; i++) {
LinearLayout theItemLayout = createHorizontalLayout(itemNum, itemSize, i);
mContentLinear.addView(theItemLayout);
}
}
private LinearLayout createHorizontalLayout(int itemNum, int itemSize, int row) {
LinearLayout theLinear = new LinearLayout(this);
theLinear.setOrientation(LinearLayout.HORIZONTAL);
theLinear.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemSize));
for(int i = 0; i < itemNum; i++){
// add item metrix into linear layout having HORIZONTAL orientation
TextView itemTxt = createItemMatrix(itemSize, row, i);
theLinear.addView(itemTxt);
}
return theLinear;
}
private TextView createItemMatrix(int itemSize, int row, int column) {
TextView theItemTxt = new TextView(this);
theItemTxt.setWidth(itemSize);
theItemTxt.setHeight(itemSize);
theItemTxt.setTextSize(13);
theItemTxt.setGravity(Gravity.CENTER);
theItemTxt.setText("A" + row + "" + column);
String tag = row + "|" + column;
theItemTxt.setTag(tag);
theItemTxt.setOnTouchListener(mOnTouchListener);
return theItemTxt;
}
// Listener
private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
private Rect rect;
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v == null) return true;
TextView itemTxt = (TextView)v;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
Log.d("TEXT", "MOVE DOWN: " + itemTxt.getText().toString());
return true;
case MotionEvent.ACTION_UP:
if (rect != null
&& !rect.contains(v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY())) {
// The motion event was outside of the view, handle this as a non-click event
return true;
}
// The view was clicked.
Log.d("TEXT", "MOVE ON: " + itemTxt.getText().toString());
// TODO: do stuff
return true;
case MotionEvent.ACTION_MOVE:
Log.d("TEXT", "MOVE OUT: " + itemTxt.getText().toString());
return true;
default:
return true;
}
}
};
Does someone have any ideas on this case?
Thanks,
Ryan