I got some trouble with my unity cardboard app. May some of you guys can help me.
I have build a little Island with Animations and A second island as a main menu.
So when the apps starts, you see the Island from above and the Logo of the App.
When the user pull down the magnet button on side the app will starts another level.
I used this scripts:
http://www.andrewnoske.com/wiki/Unity_-_Detecting_Google_Cardboard_Click
Detecting Google Cardboard Magnetic Button Click - Singleton Implementation
CardboardMagnetSensor.cs and CardboardTriggerControlMono.cs
I created a script in my asset folder(CardboardMagnetSensor.cs) like in the description from Link. Than I created a second script(CardboardTriggerControlMono.cs) like in the discription an dragged it onto my CardboardMain in may Projekt.
The CardboardTriggerControlMono.cs looks like:
using UnityEngine;
using System.Collections;
public class CardboardTriggerControlMono : MonoBehaviour {
public bool magnetDetectionEnabled = true;
void Start() {
CardboardMagnetSensor.SetEnabled(magnetDetectionEnabled);
// Disable screen dimming:
Screen.sleepTimeout = SleepTimeout.NeverSleep;
}
void Update () {
if (!magnetDetectionEnabled) return;
if (CardboardMagnetSensor.CheckIfWasClicked()) {
Debug.Log("Cardboard trigger was just clicked");
Application.LoadLevel(1);
CardboardMagnetSensor.ResetClick();
}
}
}
The CarboardMagnetSensor:
using UnityEngine;
using System.Collections.Generic;
public class CardboardMagnetSensor {
// Constants:
private const int WINDOW_SIZE = 40;
private const int NUM_SEGMENTS = 2;
private const int SEGMENT_SIZE = WINDOW_SIZE / NUM_SEGMENTS;
private const int T1 = 30, T2 = 130;
// Variables:
private static bool wasClicked; // Flips to true once set off.
private static bool sensorEnabled; // Is sensor active.
private static List<Vector3> sensorData; // Keeps magnetic sensor data.
private static float[] offsets; // Offsets used to detect click.
// Call this once at beginning to enable detection.
public static void SetEnabled(bool enabled) {
Reset();
sensorEnabled = enabled;
Input.compass.enabled = sensorEnabled;
}
// Reset variables.
public static void Reset() {
sensorData = new List<Vector3>(WINDOW_SIZE);
offsets = new float[SEGMENT_SIZE];
wasClicked = false;
sensorEnabled = false;
}
// Poll this once every frame to detect when the magnet button was clicked
// and if it was clicked make sure to call "ResetClick()"
// after you've dealt with the action, or it will continue to return true.
public static bool CheckIfWasClicked() {
UpdateData();
return wasClicked;
}
// Call this after you've dealt with a click operation.
public static void ResetClick() {
wasClicked = false;
}
// Updates 'sensorData' and determines if magnet was clicked.
private static void UpdateData() {
Vector3 currentVector = Input.compass.rawVector;
if (currentVector.x == 0 && currentVector.y == 0 && currentVector.z == 0) {
return;
}
if(sensorData.Count >= WINDOW_SIZE) sensorData.RemoveAt(0);
sensorData.Add(currentVector);
// Evaluate model:
if(sensorData.Count < WINDOW_SIZE) return;
float[] means = new float[2];
float[] maximums = new float[2];
float[] minimums = new float[2];
Vector3 baseline = sensorData[sensorData.Count - 1];
for(int i = 0; i < NUM_SEGMENTS; i++) {
int segmentStart = 20 * i;
offsets = ComputeOffsets(segmentStart, baseline);
means[i] = ComputeMean(offsets);
maximums[i] = ComputeMaximum(offsets);
minimums[i] = ComputeMinimum(offsets);
}
float min1 = minimums[0];
float max2 = maximums[1];
// Determine if button was clicked.
if(min1 < T1 && max2 > T2) {
sensorData.Clear();
wasClicked = true; // Set button clicked to true.
// NOTE: 'wasClicked' will now remain true until "ResetClick()" is called.
}
}
private static float[] ComputeOffsets(int start, Vector3 baseline) {
for(int i = 0; i < SEGMENT_SIZE; i++) {
Vector3 point = sensorData[start + i];
Vector3 o = new Vector3(point.x - baseline.x, point.y - baseline.y, point.z - baseline.z);
offsets[i] = o.magnitude;
}
return offsets;
}
private static float ComputeMean(float[] offsets) {
float sum = 0;
foreach(float o in offsets) {
sum += o;
}
return sum / offsets.Length;
}
private static float ComputeMaximum(float[] offsets) {
float max = float.MinValue;
foreach(float o in offsets) {
max = Mathf.Max(o, max);
}
return max;
}
private static float ComputeMinimum(float[] offsets) {
float min = float.MaxValue;
foreach(float o in offsets) {
min = Mathf.Min(o, min);
}
return min;
}
}
And my steps:
http://www.directupload.net/file/d/3887/mtjygjan_jpg.htm
(sorry I´m not able to upload pictures here)
How ever, it wont work. When I start the app and pull down the magnet, nothing happens. May I did something wrong with switching the level over level index?
I use a nexus 4 and 5 for testing the app
Thanks allot and greetz to you!
Phillip
If you are using the Google Cardboard SDK for Unity, it currently has a bug that prevents Unity from seeing the magnet (and gyro, and accelerometer). That is probably why your script is not working. Until the bug is fixed, there is no good workaround, but you can instead use the property Cardboard.CardboardTriggered to detect if the magnet was pulled.
Update for Unity 5: The sensor bug is gone. Cardboard SDK does not block the sensors.
Related
I want GameTipUI with a blank space for a certain amount of time and certain message(==NormalGuideTip) for a certain amount of time using CoRoutine.
I was thinking of putting an 'if' in the CoRoutine to check the time,so make it easy to empty the message, and display the message again.
However, the message just keeps getting blank.
What could be the problem?
I wanted to repeat the randomly selected game tip message for 5 seconds and the blank message for 7 seconds.
And I wanted to use realtimeForGameTip to immediately display a special message(==UrgentGameTip ) according to a specific game action later and repeat the above process again.
bool isGameTipOn= true;
public GameObject gameTipTitle;
public GameObject gameTipMsg;
Color normalTipColor = new Color(255f, 255f, 255f, 220f);
Color UrgentTipColor = Color.green;
float timeBetGameTip = 7f; //
float timeOfGameMsg = 5f; //
public readonly WaitForSeconds m_waitForSecondsForGameTip = new WaitForSeconds(7f);
float realtimeForGameTip= 0f;
public string[] NormalGuideTips;
public string[] UrgentGuideTips;
private void Start()
{
#region GameTipSetUp
OnOffGameTip(true);
StartCoroutine("GameTipUI");
#endregion GameTipSetUp
}
public void OnOffGameTip(bool OnOff)
{
isGameTipOn = OnOff;
gameTipTitle.gameObject.SetActive(isGameTipOn);
gameTipMsg.gameObject.SetActive(isGameTipOn);
}
private void ResetGameTip()
{
if (!isGameTipOn) return;
realtimeForGameTip = 0f ;
int index = Random.Range(0, NormalGuideTips.Length);
string selectedMsg = NormalGuideTips[index];
Debug.Log(selectedMsg);
gameTipMsg.GetComponent<Text>().text = selectedMsg;
gameTipMsg.GetComponent<Text>().color = normalTipColor;
}
public void UrgentGameTip(string id)
{
if (!isGameTipOn) return;
=
int index = Random.Range(0, NormalGuideTips.Length);
string selectedMsg = UrgentGuideTips[index];
Debug.Log(selectedMsg);
gameTipMsg.GetComponent<Text>().text = selectedMsg;
gameTipMsg.GetComponent<Text>().color = UrgentTipColor;
realtimeForGameTip = timeOfGameMsg;
}
public void MakeTermBetGameTip()
{
gameTipMsg.GetComponent<Text>().text = " blank ";
}
IEnumerator GameTipUI()
{
while (isGameTipOn)
{
if(realtimeForGameTip < timeOfGameMsg)
{
Debug.Log(realtimeForGameTip);
realtimeForGameTip += Time.deltaTime;
continue;
}
MakeTermBetGameTip();
yield return new WaitForSeconds(m_waitForSecondsForGameTip);
ResetGameTip();
}
}
I'm trying to understand tileSystem build in Unity, and i don't know how to stop animation in AnimatedTiles.
Once animation is started, there is no way i can think of to stop this. I'm working on Unity 2018.3.2f1, but i think that TileSystem is similar in next versions.
Only code in AnimatedTile handling animation is:
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
tileData.transform = Matrix4x4.identity;
tileData.color = Color.white;
if (m_AnimatedSprites != null && m_AnimatedSprites.Length > 0)
{
tileData.sprite = m_AnimatedSprites[0];
tileData.colliderType = m_TileColliderType;
}
}
public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
{
if (m_AnimatedSprites.Length > 0)
{
tileAnimationData.animatedSprites = m_AnimatedSprites;
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
tileAnimationData.animationStartTime = m_AnimationStartTime;
return true;
}
return false;
}
I want to stop animation after some time (like 3 seconds) or after last frame. Any help would be appritiated!
So after some time a got workaround and it looks like this :
public class TileBump : MonoBehaviour
{
public Transform m_GridParent;
public GameObject m_TileMap_Prefab;
public AnimatedTile m_tilePrefabAnimated;
public Tile m_tilePrefabStatic;
private Tilemap map;
void Start()
{
StartCoroutine(EStart());
}
public IEnumerator EStart()
{
GameObject t = Instantiate(m_TileMap_Prefab, m_GridParent);
map = t.GetComponent<Tilemap>();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
map.SetTile(new Vector3Int(i, j, 0), m_tilePrefabAnimated);
StartCoroutine(Operation(new Vector3Int(i, j, 0)));
yield return new WaitForSeconds(0.3f);
}
}
}
public IEnumerator Operation(Vector3Int x)
{
yield return new WaitForSeconds(m_tilePrefabAnimated.m_AnimatedSprites.Length / m_tilePrefabAnimated.m_AnimationSpeed);
map.SetTile(x, m_tilePrefabStatic);
}
}
BUT. What i understood here is that tiles are not for that. Every tile in TileMap refer to ScriptableObject, so every animation will be same in every frame.
However if someone need this kind of effect, its one way to do it.
thanks for reading.
I'm currently building a small memory card game in Unity using C#. I have the main portion of code finished but when I press the play button on a certain scene Unity freezes.
I believe it is due to an infinite While loop, but I can not find the issue. I would really appreciate any help anyone can offer. I will leave my code below. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine;
public class Pairs : MonoBehaviour {
public Sprite[] face; //array of card faces
public Sprite back;
public GameObject[] deck; //array of deck
public Text pairsCount;
private bool deckSetUp = false;
private int pairsLeft = 13;
// Update is called once per frame
void Update () {
if (!deckSetUp)
{
SetUpDeck();
}
if (Input.GetMouseButtonUp(0)) //detects left click
{
CheckDeck();
}
}//Update
void SetUpDeck()
{
for (int ix = 0; ix < 2; ix++)
{
for(int i = 1; i < 14; i++)//sets up card value (2-10 JQKA)
{
bool test = false;
int val = 0;
while (!test)
{
val = Random.Range(0, deck.Length);
test = !(deck[val].GetComponent<Card>().SetUp);
}//while
//sets up cards
deck[val].GetComponent<Card>().Number = i;
deck[val].GetComponent<Card>().SetUp = true;
}//nested for
}//for
foreach (GameObject crd in deck)
{
crd.GetComponent<Card>().setUpArt();
}
if (!deckSetUp)
{
deckSetUp = true;
}
}//SetUpDeck
public Sprite getBack()
{
return back;
}//getBack
public Sprite getFace(int i)
{
return face[i - 1];
}//getFace
void CheckDeck()
{
List < int > crd = new List<int>();
for(int i = 0; i < deck.Length; i++)
{
if(deck[i].GetComponent<Card>().State == 1)
{
crd.Add(i);
}
}
if(crd.Count == 2)
{
CompareCards(crd);
}
}//CheckDeck
void CompareCards(List<int> crd)
{
Card.NO_TURN = true; //stops cards turning
int x = 0;
if(deck[crd[0]].GetComponent<Card>().Number ==
deck[crd[1]].GetComponent<Card>().Number)
{
x = 2;
pairsLeft--;
pairsCount.text = "PAIRS REMAINING: " + pairsLeft;
if(pairsLeft == 0) // goes to home screen when game has been won
{
SceneManager.LoadScene("Home");
}
}
for(int j = 0; j < crd.Count; j++)
{
deck[crd[j]].GetComponent<Card>().State = x;
deck[crd[j]].GetComponent<Card>().PairCheck();
}
}//CompareCards
}
I believe the issue lies in the while(!test) but i do not know why test never become true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Card : MonoBehaviour {
public static bool NO_TURN = false;
[SerializeField]
private int cardState; //state of card
[SerializeField]
private int cardNumber; //Card value (1-13)
[SerializeField]
private bool _setUp = false;
private Sprite back; //card back (Green square)
private Sprite face; //card face (1-10 JQKA)
private GameObject pairsManager;
void Begin()
{
cardState = 1; //cards face down
pairsManager = GameObject.FindGameObjectWithTag("PairsManager");
}
public void setUpArt()
{
back = pairsManager.GetComponent<Pairs>().getBack();
face = pairsManager.GetComponent<Pairs>().getFace(cardNumber);
turnCard();//turns the card
}
public void turnCard() //handles turning of card
{
if (cardState == 0)
{
cardState = 1;
}
else if(cardState == 1)
{
cardState = 0;
}
if (cardState == 0 && !NO_TURN)
{
GetComponent<Image>().sprite = back; // shows card back
}
else if (cardState == 1 && !NO_TURN)
{
GetComponent<Image>().sprite = face; // shows card front
}
}
//setters and getters
public int Number
{
get {return cardNumber;}
set { cardNumber = value;}
}
public int State
{
get { return cardState; }
set { cardState = value; }
}
public bool SetUp
{
get { return _setUp; }
set { _setUp = value; }
}
public void PairCheck()
{
StartCoroutine(pause ());
}
IEnumerator pause()
{
yield return new WaitForSeconds(1);
if (cardState == 0)
{
GetComponent<Image>().sprite = back;
}
else if (cardState == 1)
{
GetComponent<Image>().sprite = face;
}
}
}
Thank you for reading, I will post a link to the github repository if that helps.
github repository
Your deck array has at least one card in it that has _setUp set to true which would make it go in a infinite loop.
The reason it goes in a infinite loop is because it will have set all available _setUp to true and it would keep looking for _setUp that are set to false and it will never find any.
The reason you need at least 26 object that have _setUp to false is because in the nested for loop you loop 13 times and then you do that twice which gives a total of 26 loops. So you need at least 26 objects.
What you can do to make sure that they're all false is to set them all to false before entering the for loop
for(int i = 0; i < deck.Length; i++)
{
deck[i].GetComponent<Card>().SetUp = false;
}
I want to use the volume of the audio that the user inputs with his/her microphone in Unity3d in a visual representation. So I'd like to get a value between 0 and 1 that tell how loud the user is. I went looking for a script, but the part that handles the volume doesn't work properly, that part is the method LevelMax(). For some reason micPosiotion never becomes higher than 0. I don't know what Microphone.GetPosition really does except for this:
http://docs.unity3d.com/ScriptReference/Microphone.GetPosition.html
Does anyone know what goes wrong in the method LevelMax()? I am getting no errors or anything. And it finds my microphone properly, and it is working. I tested it.
This is the code:
using UnityEngine;
using System.Collections;
public class MicInput : MonoBehaviour{
public float testSound;
public static float MicLoudness;
private string _device;
private AudioClip _clipRecord = new AudioClip();
private int _sampleWindow = 128;
private bool _isInitialized;
void InitMic()
{
if (_device == null) {
_device = Microphone.devices [0];
_clipRecord = Microphone.Start (_device, true, 999, 44100);
Debug.Log (_clipRecord);
}
}
void StopMicrophone()
{
Microphone.End (_device);
}
float LevelMax()
{
float levelMax = 0;
float[] waveData = new float[_sampleWindow];
int micPosition = Microphone.GetPosition (null) - (_sampleWindow + 1);
if (micPosition < 0) {
return 0;
}
_clipRecord.GetData (waveData, micPosition);
for (int i = 0; i < _sampleWindow; ++i) {
float wavePeak = waveData [i] * waveData [i];
if (levelMax < wavePeak) {
levelMax = wavePeak;
}
}
return levelMax;
}
void Update()
{
MicLoudness = LevelMax ();
testSound = MicLoudness;
}
void OnEnable()
{
InitMic ();
_isInitialized = true;
}
void OnDisable()
{
StopMicrophone ();
}
void OnDestory()
{
StopMicrophone ();
}
void OnApplicationFocus(bool focus)
{
if (focus) {
if (!_isInitialized) {
InitMic ();
_isInitialized = true;
}
}
if (!focus) {
StopMicrophone ();
_isInitialized = false;
}
}
}
This script works. I have just tested it and it shows the peak level of the mic in the inspector as the variable testSound. There is something going wrong on your end that is causing it to not begin recording into the audioclip. That is why it is always returning that the micPosition is less than zero.
The only thing that I can see that is slightly off is Microphone.GetPosition(null) inside the LevelMax method. Try changing this to Microphone.GetPosition(_device)
You might also want to try going through your different audio devices by changing the index passed in the line (in the InitMic method):
_device = Microphone.devices [0];
Try changing this to 1,2,3 etc and see if you are just finding the wrong audio device. If you have more than one mic or are not using the default mic then this could be the problem.
Also, I think you are misunderstanding how digital audio works. GetPosition gets the current sample that the microphone is recording into the audioclip (i.e the latest sample/current sample). This basically means that it gets the amount of samples that have been recorded. You are recording at 44.1Khz samples. That means that every second the audio is being checked 441000 times and a level is assigned to that individual sample. This is called the sample rate and it can be changed. For example CD's use the sample rate 44.1kHz where as digital video tends to use 48kHz. The accuracy of the the sample being recorded is defined by the bit-depth (but you don't have to worry about this). For example CD's use 16bit (which needs to be dithered) whereas digital media uses 24bit(generally). The line:
int micPosition = Microphone.GetPosition(null)-(_sampleWindow+1);
Says "find the amount samples we have recorded 129 samples ago". It then iterates through the values of the next 128 samples and finds the 'loudest' sample and returns it. This is then shown in the inspector. If you don't understand anything I've just said then look into how digital audio is recorded. It's not too complicated to understand the basics of it.
You should check out this thread, but here is the code that may help you:
public class MicInput : MonoBehaviour {
public static float MicLoudness;
private string _device;
//mic initialization
void InitMic(){
if(_device == null) _device = Microphone.devices[0];
_clipRecord = Microphone.Start(_device, true, 999, 44100);
}
void StopMicrophone()
{
Microphone.End(_device);
}
AudioClip _clipRecord = new AudioClip();
int _sampleWindow = 128;
//get data from microphone into audioclip
float LevelMax()
{
float levelMax = 0;
float[] waveData = new float[_sampleWindow];
int micPosition = Microphone.GetPosition(null)-(_sampleWindow+1); // null means the first microphone
if (micPosition < 0) return 0;
_clipRecord.GetData(waveData, micPosition);
// Getting a peak on the last 128 samples
for (int i = 0; i < _sampleWindow; i++) {
float wavePeak = waveData[i] * waveData[i];
if (levelMax < wavePeak) {
levelMax = wavePeak;
}
}
return levelMax;
}
void Update()
{
// levelMax equals to the highest normalized value power 2, a small number because < 1
// pass the value to a static var so we can access it from anywhere
MicLoudness = LevelMax ();
}
bool _isInitialized;
// start mic when scene starts
void OnEnable()
{
InitMic();
_isInitialized=true;
}
//stop mic when loading a new level or quit application
void OnDisable()
{
StopMicrophone();
}
void OnDestroy()
{
StopMicrophone();
}
// make sure the mic gets started & stopped when application gets focused
void OnApplicationFocus(bool focus) {
if (focus)
{
//Debug.Log("Focus");
if(!_isInitialized){
//Debug.Log("Init Mic");
InitMic();
_isInitialized=true;
}
}
if (!focus)
{
//Debug.Log("Pause");
StopMicrophone();
//Debug.Log("Stop Mic");
_isInitialized=false;
}
}
}
I need my script to go to the next camera every time I press a button on my Arduino, I just can't get it working can somebody please help me?
I got the Arduino communicating with Anity but i just can't get my head around the camera switching part.
Could someone tell me how to make a button press hop to the next camera, so I only need 1 button to show all the camera's
using UnityEngine;
using System.Collections;
using Uniduino;
#if (UNITY_3_0 || UNITY_3_0_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5)
public class DigitalRead : Uniduino.Examples.DigitalRead { } // for unity 3.x
#endif
namespace Uniduino.Examples
{
public class digitalread2 : MonoBehaviour {
public Arduino arduino;
public int pin = 2;
public int pinValue;
public int testLed = 11;
public int licht;
public int enable;
public int val = 0;
public GameObject cam1;
public GameObject cam2;
void Start ()
{
arduino = Arduino.global;
arduino.Log = (s) => Debug.Log("Arduino: " +s);
arduino.Setup(ConfigurePins);
cam1 = GameObject.Find ("cam1");
}
void ConfigurePins ()
{
arduino.pinMode(pin, PinMode.INPUT);
arduino.reportDigital((byte)(pin/8), 1);
// set the pin mode for the test LED on your board, pin 13 on an Arduino Uno
arduino.pinMode(testLed, PinMode.OUTPUT);
}
void Update ()
{
// read the value from the digital input
enable = arduino.digitalRead (pin);
licht = arduino.digitalRead (pin);
pinValue = arduino.digitalRead(pin);
// apply that value to the test LED
arduino.digitalWrite(testLed,pinValue);
Debug.Log(pinValue);
val = arduino.digitalRead (pin);
arduino.digitalWrite (testLed, val);
val = cam1.active = false;
val = cam2.active = true;
}
}
}
GameObject cam1, cam2;
void Start(){
cam1 = Find("camera_name");
cam2 = Find("camera2_name");
cam1.enabled = True;
cam2.enabled = False;
void Update(){
if(Input.GetButtonDown... // you need to implement ur arduino && cam1,isActive())
cam1.enabled = false;
cam2.enabled = true;
if(Input.GetButtonDown... // you need to implement ur arduino && cam2.isActive()) {
cam2.enabled = false;
cam1.enabled = true;
}
There might be something wrong. I am not able to use Unity Tool now. I am also not sure if you can you "cam1.enabled" or not.