My app have some problem!
My app have three Scene , One of them using ARCore(ARScene), another one using camera device(CamScene). Problem is if i don't run ARScene , CamScene also does not work( NOT ASKING FOR PERMISSION)!
I create new app only use camera device, and it work (it ask for permission when begin run app)
public IEnumerator LoadAsync(SceneType levelNum)
{
yield return null;
StartOperation(levelNum);
yield return new WaitForSeconds(0.5f);
while (DoneLoading() == false)
{
Debug.Log("In while");
}
if (loadSceneMode == LoadSceneMode.Additive)
UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync(currentScene.name);
else
operation.allowSceneActivation = true;
yield return new WaitForSeconds(0.2f);
//effect.Hiden();
}
private bool DoneLoading()
{
return (loadSceneMode == LoadSceneMode.Additive && operation.isDone) || (loadSceneMode == LoadSceneMode.Single && operation.progress >= 0.9f);
}
private void StartOperation(SceneType levelNum)
{
operation = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(levelNum.ToString(), loadSceneMode);
operation.allowSceneActivation = false;
}
public void LoadSceneAsync(SceneType sceneType)
{
effect.Show();
StartCoroutine(LoadAsync(sceneType));
}
This is my load scene, i build this app for android device, when i run with editor my app word normal, no error messages!!
Related
I made a simple game in unity, and I implemented google play services using This Plugin and I have encountered some issue which I can't find any solution simply by searching on google btw I have already read the docs and made a custom skin/ui for my leaderboard as this and this works fine (that not registered text is intentional) but the issue I am getting is that some of my tester can't even login to google play and some can
and even one of them got a rank of -1 see this, idk how this happened but we can't access the database to edit the data manually(or without editing code/creating new leaderboard).
the codes I am using:-
This one is for authenticating and loading the leaderboard
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;
using System;
public class GPauth : MonoBehaviour
{
public bool IsConnected = false;
public GameObject Lockbtn;
public Button btn;
public Transform EntryContainer;
public Transform EntryTemplate;
public float TemplateHeight = 300f;
public TextMeshProUGUI PlayerName;
public TextMeshProUGUI PlayerRank;
public TextMeshProUGUI PlayerScore;
GooglePlayData data;
PlayerData playerData;
public GameObject scroeDisplay;
public GameObject newtya;
public GameObject mainMenu;
public GameObject lbUI;
[SerializeField] private AudioSource LockSFX;
[SerializeField] private Animator LockAnime;
[SerializeField] private AudioSource source;
private bool LeaderboardDataHasFilled;
private void Start()
{
playerData = SaveSystem.LoadPlayer();
data = SaveSystem.LoadConsole();
if(data == null || playerData == null || playerData.HasPlayed == false)
{
Lockbtn.SetActive(true);
SaveSystem.SaveConsole(this);
return;
}
else
{
IsConnected = data.connectedToGooglePlay;
}
PlayGamesPlatform.DebugLogEnabled = true;
PlayGamesPlatform.Activate();
AuthenticateUser();
LeaderboardDataHasFilled = false;
}
private void AuthenticateUser()
{
PlayGamesPlatform.Instance.Authenticate(ProcessAuthentication);
}
private void ProcessAuthentication(SignInStatus status)
{
if (status == SignInStatus.Success)
{
IsConnected = true;
}
else IsConnected = false;
SaveSystem.SaveConsole(this);
}
public void ShowLeaderboard()
{
if(data == null || playerData == null || playerData.HasPlayed == false)
{
LockSFX.Play();
LockAnime.SetBool("Start", true);
Invoke("resetLockAnime", 0.1f);
}
else
{
source.Play();
if (!IsConnected) AuthenticateUser();
else LeaderboardUI();
}
}
private void resetLockAnime()
{
LockAnime.SetBool("Start", false);
}
private void LeaderboardUI()
{
scroeDisplay.SetActive(false);
mainMenu.SetActive(false);
newtya.SetActive(false);
lbUI.SetActive(true);
if (LeaderboardDataHasFilled) return;
PlayGamesPlatform.Instance.LoadScores(
GPGSIds.leaderboard_newtya,
LeaderboardStart.TopScores,
10,
LeaderboardCollection.Public,
LeaderboardTimeSpan.AllTime,
(data) =>
{
if (data == null)
{
Debug.LogError("Data Was Null");
return;
}
/*Public Leaderboard database logic starts here*/
// get scores
IScore[] scores = data.Scores;
// get user ids
string[] userIds = new string[scores.Length];
for (int i = 0; i < scores.Length; i++)
{
userIds[i] = scores[i].userID;
}
// forward scores with loaded profiles
Social.LoadUsers(userIds, profiles => DisplayLeaderboardEntries(scores, profiles, data.PlayerScore));
/*Public Leaderboard database logic Ends here*/
if (data.PlayerScore == null)
{
Debug.Log("Data.PlayerScore was null");
PlayerName.text = "Not registered";
return;
}
if (data.PlayerScore.userID == null)
{
Debug.Log("Data.PlayerScore.UserID was null");
PlayerName.text = "Not registered";
return;
}
IScore pScore = data.PlayerScore;
string userId = data.PlayerScore.userID;
string[] PlayerIDS = new string[] { userId };
Social.LoadUsers(PlayerIDS, profiles => PlayerScoreSetup(pScore, profiles));
});
LeaderboardDataHasFilled = true;
}
private void PlayerScoreSetup(IScore data, IUserProfile[] profiles)
{
PlayerName.text = profiles[0].userName.ToString();
PlayerScore.text = data.formattedValue.ToString();
PlayerRank.text = data.rank.ToString();
}
private void DisplayLeaderboardEntries(IScore[] scores, IUserProfile[] profiles, IScore playerData)
{
EntryTemplate.gameObject.SetActive(false);
for (int i = 0; i < profiles.Length; i++)
{
Transform entryTransform = Instantiate(EntryTemplate, EntryContainer);
RectTransform entryRectTransform = entryTransform.GetComponent<RectTransform>();
entryRectTransform.anchoredPosition = new Vector2(0, -TemplateHeight * i);
entryRectTransform.gameObject.SetActive(true);
TextMeshProUGUI txRank = entryRectTransform.Find("RankTXT").GetComponent<TextMeshProUGUI>();
TextMeshProUGUI txName = entryRectTransform.Find("NameTXT").GetComponent<TextMeshProUGUI>();
TextMeshProUGUI txScore = entryRectTransform.Find("ScoreTXT").GetComponent<TextMeshProUGUI>();
txRank.text = scores[i].rank.ToString();
txName.text = profiles[i].userName.ToString();
txScore.text = scores[i].formattedValue.ToString();
}
}
}
and this one runs when player loses to upload the score
long scoreforlb = Convert.ToInt64(HighScore);
Social.ReportScore(scoreforlb, GPGSIds.leaderboard_newtya, UpdateLeaderboard);
//to check if score was reported or not
private void UpdateLeaderboard(bool success)
{
if (success) Debug.Log("Success");
else Debug.Log("err");
}
I have already implemented some checks to prevent above code to run if user isnot connect to google play games.
Any help will be very appreciable.
In my experience '-1' rank is caused by player's Google Play profile's Game Activity being set to private.
Players have the option to set this preference during initial creation of google play games account, or they can change it later in the play games app ('Game Activity' setting under 'Profile and privacy').
One solution (which I used) is to show a help button (to players with -1 rank) which shows a message box explaining why the rank is not available and how the player can set their profile to public if they want to see their rank.
Regarding the login problem, you can see the reason for login failure in the SignInStatus returned in authentication callback, which might point out the issue.
Also check to see if the tester is able to sign into other games which use google play games, to make sure it is not a device/account issue.
Hi! If you want to save time and still help please read this section and the last one to get glimpse of my problem (part 1 and 6). So much code was needed to fully present problem
Using Unity 2019.3.0b2
1.
Im creating WebGL application that allows you to customize your character via assets from downloaded asset bundles. So far I got downloading and instantiating work, but I also want to change downloaded gameobject material to custom color from color-picker. In this case I need to refer to adequate Renderer. I've got function that sends request and it goes like so:
private IEnumerator SendRequestCoroutine(UnityWebRequest request, UnityAction<UnityWebRequest> OnDownloadCompleteHandler, UnityAction<float> OnDownloadProgressHandler = null)
{
request.SendWebRequest();
while(!request.isDone)
{
if(OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(request.downloadProgress);
yield return null;
}
// Has to fire once more because progress stops at around 0.87,
// never returning 1 unless download is finished.
if (OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(1);
OnDownloadCompleteHandler.Invoke(request);
}
2.
I fire this coroutine like that:
public void DownloadAssetBundle(string url, ProgressBar bar = null)
{
if (isRequestSend)
{
Alerter.ShowMessage("Request has been already send, please wait untill complete.");
return;
}
UnityWebRequest request = HttpService.Instance.GetAssetBundleRequest(url);
if(bar != null)
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); },
(rq) => OnDownloadProgressHandler(rq, bar)
);
isRequestSend = true;
}
else
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); }
);
isRequestSend = true;
}
}
3.
OnDownloadAssetBundleCompleteHandler looks like this:
//Function that will handle asset bundle when completed.
private void OnDownloadAssetBundleCompleteHandler(UnityWebRequest request)
{
isRequestSend = false;
if(request.isHttpError || request.isNetworkError)
{
//Handle downloading error
Alerter.ShowMessage("Seems like there was a problem with downloading, try again.");
}
else
{
AssetBundle bundle;
//Handle content update
bundle = DownloadHandlerAssetBundle.GetContent(request);
AssetBundleInfo assetBundleInfo = bundle.LoadAllAssets<AssetBundleInfo>().FirstOrDefault();
if (assetBundleInfo == null)
{
//Handle error
Alerter.ShowMessage("Couldn't read information about this Character Part. AssetBundleInfo null exception.");
bundle.Unload(false);
return;
}
GameObject goToLoad = null;
goToLoad = bundle.LoadAsset<GameObject>(assetBundleInfo.ObjectName);
if (goToLoad == null)
{
Alerter.ShowMessage("Couldn't read information about this Character Part. Downloaded asset's gameobject null exception.");
bundle.Unload(false);
return;
}
Sticher.ConnectComponent(goToLoad, assetBundleInfo.PartType);
ColorSetter.Instance.ChangeSelectedBodyPart(assetBundleInfo.PartType);
bundle.Unload(false);
}
}
4.
Now the final step is to set adequate transform so my script will search for component of type Renderer, get its material of index 0 as current material to modify, class that contain ChangeSelectedBodyPart function looks like so:
using Assets.Scripts.Models.Enums;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColorSetter : MonoBehaviour
{
public Renderer rend;
public ColorPicker picker;
public static ColorSetter Instance;
private void Awake()
{
if(Instance != null)
{
Destroy(this);
}
else
{
Instance = this;
DontDestroyOnLoad(this);
}
}
// Start is called before the first frame update
void Start()
{
picker.onValueChanged.AddListener(color =>
{
if (rend == null)
return;
rend.material.SetColor("_BaseColor", color);
}
);
}
public void ChangeSelectedBodyPart(AvatarPartType p)
{
switch(p)
{
case AvatarPartType.ClothesUpper:
SetActiveMaterial(Sticher.Instance.Clothes_Upper);
break;
case AvatarPartType.ClothesLower:
SetActiveMaterial(Sticher.Instance.Clothes_Lower);
break;
case AvatarPartType.Shoes:
SetActiveMaterial(Sticher.Instance.Shoes);
break;
case AvatarPartType.Hair:
SetActiveMaterial(Sticher.Instance.Hair);
break;
case AvatarPartType.Skin:
SetActiveMaterial(Sticher.Instance.Skin);
break;
}
}
private void SetActiveMaterial(Transform parent)
{
rend = parent.GetComponentInChildren<Renderer>();
}
}
5.
PS. parent has only one child that contains Renderer component
Now, finally, problem is that I don't get proper material reference, I got the old one that is being set via toggle button, simply as that:
public void OnValueChanged(bool value)
{
if(value)
{
ColorSetter.Instance.ChangeSelectedBodyPart(PartType);
ButtonManager.Instance.RemoveAllButtonsFromPartsWindow();
ButtonManager.Instance.PopulatePartsPanelWithAvatarPartsOfType(PartType);
}
}
6.
So in conclusion when I press on "toggle button" that represents some avatar body/clothing part it sets its parent and material properly via function, even after asset bundle has been downloaded (but I have to click the same toggle again to make it work), but when I fire the same function in OnDownloadAssetBundleCompleteHandler just after asset been downloaded it doesn't work :S Why? Is it related with asset unloading speed? Any tips on fixing this?
In Game View it behave like that:
I fixed it. Since you can't use DestoyImmediate like #derHugo said because it can cause reference errors or even it could destroy assets permamently I had to use Destroy() instead before Instantiating new gameobject from assetbundle, however Destroy() will delete given object at the end of the frame while I try to access Renderer component on freshly instantiated GameObject just at the same frame, before old one is acutally destoryed. I fixed it yielding one frame using yield return new WaitForEndOfFrame(); just after function that takes care of destroying old GameObjects before trying to access new GameObject.
I'm trying to add an attack to my character, everything works fine except my button its called multiple times by click (I'm not holding the key down, and its called in average 4 times).
Thats my Update method:
void Update() {
attackArea.enabled = false;
InputCharacter();
MoveAttackArea();
SetAnimation();
ApplyColorFilters();
}
and my InputCharacter method:
void InputCharacter() {
direction = Vector2.zero;
if (Input.GetKey(KeyCode.B)) {
lastAttackTime = currentTime;
Attack();
} else if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) {
Move(Vector2.up);
} else if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S)) {
Move(Vector2.down);
} else if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A)) {
Move(Vector2.left);
} else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D)) {
Move(Vector2.right);
}
}
also my Attack method:
private void Attack() {
Debug.Log("attacking");
animator.SetTrigger("attack");
attackArea.enabled = true;
}
I don't know if the this part its related but:
The log show multiple times and my animations are playing twice (when I play an object destruction animation it runs twice, I don't know if its related)
Replace
Input.GetKey
with
Input.GetKeyDown
A friend of mine and I are working on a VR project in Unity at the moment and we are trying to implement voice recognition as a feature. We are using Unity version 2018.3.3f1. The idea is that a user can say a word and the voice recognition will see if they pronounced it correctly. We have chosen to use the Google cloud speech-to-text service for this as it supports the target language (Norwegian). In addition, the application is also multiplayer and so we are trying to use the streaming version of Google cloud speech. Here is a link to their documentation: https://cloud.google.com/speech-to-text/docs/streaming-recognize
What we have done is to have a plugin that essentially runs the speech recognition for us. It is a modification of the example code given in the link above:
public Task<bool> StartSpeechRecognition()
{
return StreamingMicRecognizeAsync(20, "fantastisk");
}
static async Task<bool> StreamingMicRecognizeAsync(int inputTime, string inputWord)
{
bool speechSuccess = false;
Stopwatch timer = new Stopwatch();
Task delay = Task.Delay(TimeSpan.FromSeconds(1));
if (NAudio.Wave.WaveIn.DeviceCount < 1)
{
//Console.WriteLine("No microphone!");
return false;
}
var speech = SpeechClient.Create();
var streamingCall = speech.StreamingRecognize();
// Write the initial request with the config.
await streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
StreamingConfig = new StreamingRecognitionConfig()
{
Config = new RecognitionConfig()
{
Encoding =
RecognitionConfig.Types.AudioEncoding.Linear16,
SampleRateHertz = 16000,
LanguageCode = "nb",
},
InterimResults = true,
}
});
// Compare speech with the input word, finish if they are the same and speechSuccess becomes true.
Task compareSpeech = Task.Run(async () =>
{
while (await streamingCall.ResponseStream.MoveNext(
default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
if (alternative.Transcript.Replace(" ", String.Empty).Equals(inputWord, StringComparison.InvariantCultureIgnoreCase))
{
speechSuccess = true;
return;
}
}
}
}
});
// Read from the microphone and stream to API.
object writeLock = new object();
bool writeMore = true;
var waveIn = new NAudio.Wave.WaveInEvent();
waveIn.DeviceNumber = 0;
waveIn.WaveFormat = new NAudio.Wave.WaveFormat(16000, 1);
waveIn.DataAvailable +=
(object sender, NAudio.Wave.WaveInEventArgs args) =>
{
lock (writeLock)
{
if (!writeMore) return;
streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
AudioContent = Google.Protobuf.ByteString
.CopyFrom(args.Buffer, 0, args.BytesRecorded)
}).Wait();
}
};
waveIn.StartRecording();
timer.Start();
//Console.WriteLine("Speak now.");
//Delay continues as long as a match has not been found between speech and inputword or time that has passed since recording is lower than inputTime.
while (!speechSuccess && timer.Elapsed.TotalSeconds <= inputTime)
{
await delay;
}
// Stop recording and shut down.
waveIn.StopRecording();
timer.Stop();
lock (writeLock) writeMore = false;
await streamingCall.WriteCompleteAsync();
await compareSpeech;
//Console.WriteLine("Finished.");
return speechSuccess;
}
We made a small project in Unity to test if this was working with a cube GameObject that had this script:
private CancellationTokenSource tokenSource;
VR_VoiceRecognition.VoiceRecognition voice = new VR_VoiceRecognition.VoiceRecognition();
IDisposable speech;
// Use this for initialization
void Start() {
speech = Observable.FromCoroutine(WaitForSpeech).Subscribe();
}
// Update is called once per frame
void Update() {
}
IEnumerator WaitForSpeech()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Debug.Log("Starting up");
Task<bool> t = Task.Run(() => voice.StartSpeechRecognition());
while (!(t.IsCompleted || t.IsCanceled))
{
yield return null;
}
if (t.Status != TaskStatus.RanToCompletion)
{
yield break;
}
else
{
bool result = t.Result;
UnityEngine.Debug.Log(t.Result);
yield return result;
}
}
void OnApplicationQuit()
{
print("Closing application.");
speech.Dispose();
}
We are also using a plugin that was recommended to us by Unity support that they thought might have a workaround called UniRx (https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276).
At the moment it is working fine when you play it in the editor for the first time. When the voice recognition returns false then everything is fine (two cases when this happens is if it cannot find a microphone or if the user does not say the specific word). However, if it is a success then it still returns true, but if you exit play mode in the editor and try to play again then Unity will freeze. Unity support suspects that it might have something to do with the Google .dll files or Google API. We are not quite sure what to do from here and we hope that someone could point us to the right direction.
I am trying to setup a Facebook marketing campaign with the objective being to track app installs. Facebook recommends using their SDK to get accurate information about app installs, but I don't want to prompt the user to login to Facebook in my app. Is it possible to have the Facebook SDK track app installs without users logging in? According to Facebook their API automatically tracks app installs but it seems that in their initialization script called mainmenu.cs requires a Facebook login to occur.
What I did was basically create a persistent game object in my first scene and attached this code to it. I based this code off of Facebook's example https://developers.facebook.com/docs/app-events/unity but added some additional checks so FB.Init() would not be called twice. I also added a coroutine that would wait to activate an event until FB.Init() is done since FB.Init() is an asynchronous function.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Facebook.Unity;
public class FacebookTracker : MonoBehaviour {
private static FacebookTracker instance;
private bool initCalled;
private void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
} else
{
Destroy(gameObject);
}
if (FB.IsInitialized == false && initCalled == false)
{
FB.Init();
initCalled = true;
}
}
private void OnApplicationPause(bool pause)
{
Debug.Log("OnApplicationPause = " + pause);
if (pause == false)
{
if (FB.IsInitialized == true)
{
FB.ActivateApp();
} else
{
if (initCalled == false)
{
FB.Init();
initCalled = true;
}
StartCoroutine(ActivateEvent());
}
}
}
private IEnumerator ActivateEvent()
{
yield return new WaitUntil(() => FB.IsInitialized == true);
Debug.Log("Facebook Activate Event Logged");
FB.ActivateApp();
}
}