I'd first like to apologise beforehand if my question is very basic and dumb as I am very new to coding and unity/vuforia in general.
I'd like to track a custom image and display a quad under it (i've done this part). I've also managed to set the material/texture/look of the quad to a image located in my computer. However, when trying to do build into a android app, I am unable to set the file path correctly and it doesnt work.
I would like the material/texture/look of the quad to be constantly changing/updating, is this possible? I can constantly overwrite the image file on my computer/phone but will the photo update in the app itself?
Thank you so much for any help in advance!
A desperate student
void Start()
{
string path = "file://storage/emulated/0/Android/data/com.kenny.argame/files/im2.jpg";
StartCoroutine(DownloadImage(path));
}
IEnumerator DownloadImage(string MediaUrl)
{
GetComponent<Renderer>().material = FinalMaterialRef;
UnityWebRequest request = UnityWebRequestTexture.GetTexture(MediaUrl);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
Debug.Log(request.error);
else
_material.mainTexture = ((DownloadHandlerTexture)request.downloadHandler).texture;
FinalMaterialRef = _material;
}
}
While it's not clear from your code where _material and FinalMaterialRef are originally declared -- they're not in the scope you showed -- you might have your references mixed up and overwrite them, but not the actual material. This works:
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class ChangeTexture : MonoBehaviour
{
Material material = null;
void Start()
{
material = GetComponent<Renderer>().material;
const string path = "file://E:/_temp/1.jpg";
StartCoroutine(DownloadAndAssignImage(path));
}
IEnumerator DownloadAndAssignImage(string mediaUrl)
{
UnityWebRequest request = UnityWebRequestTexture.GetTexture(mediaUrl);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
}
else
{
material.mainTexture =
((DownloadHandlerTexture)request.downloadHandler).texture;
}
}
}
Related
So i want to retrieve the amount of results from a google search. I dont use the Google search API because it doesnt give the right numbers, i want the exact same that are one the webpage when you google someting (thats actually the whole point of the game). I tried Python (with no experience) but failed misaberly. Then I search a bit around the Internet and this what i came up with:
(found code but it was in javascript, and im also to dumb for that)
Edit: Heres the link to the JavaScript r google search result count retrieve
And apparently some guy wanted the same but in java, so if someone could "translate" this(easiest (legal) way to programmatically get the google search result count?) I would be really happy
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Windows;
using File = System.IO.File;
public class SearchGoogle : MonoBehaviour
{
public string keyword;
private string searchwebsite;
string fileName = "MyFile.html";
void Start()
{
searchwebsite = "https://www.google.com/search?q=" + keyword;
Debug.Log(searchwebsite);
StartCoroutine(GetText());
Debug.Log("Coroutine wird gecallt");
}
IEnumerator GetText()
{
UnityWebRequest www = UnityWebRequest.Get(searchwebsite);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log("Fehler:(");
Debug.Log(www.error);
}
else
{
Debug.Log("CErfolg");
// Show results as text
Debug.Log(www.downloadHandler.text);
if (File.Exists(fileName))
{
Debug.Log(fileName + " already exists.");
}
var sr = File.CreateText(fileName);
sr.WriteLine(www.downloadHandler.text);
sr.Close();
//Printing it in a file to open it in my browser, not nessecary in the final build
// Or retrieve results as binary data
byte[] results = www.downloadHandler.data;
}
}
}
But this code just returns the scource code of the website, and I actually dont quite understand it. Does anyone have a solution for this (i just want the amount of results, nothing else)? I just think it would be possible to do, but if it's not, correct me please. Thanks in advace.
Edit:(The div in html is called "result-stats"
I've taken over development of an app that is complete minus a bug requiring an internet connection to load images as it doesn't access them from the cache despite an attempt to do so.
Can anyone help me figure out what is going wrong in the following?
public class SpriteCache : Singleton<SpriteCache>
{
Dictionary<string, Sprite> _cache = new Dictionary<string, Sprite>();
public void LoadSprite(string url, Action<Sprite> callback)
{
StartCoroutine(LoadSpriteCoroutine(url, callback));
}
public IEnumerator LoadSpriteCoroutine(string url, Action<Sprite> callback)
{
if (_cache.ContainsKey(url))
{
callback(_cache[url]);
yield break;
}
var www = new WWW(url);
while (!www.isDone)
{
yield return www;
}
if (!string.IsNullOrEmpty(www.error))
{
Debug.LogErrorFormat("Tried to obtain texture at '{0}' but received error '{1}'", url, www.error);
yield break;
}
var texture = www.texture;
if (texture == null)
{
Debug.LogErrorFormat("No texture found at '{0}'!", url);
yield break;
}
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2, texture.height / 2));
_cache[url] = sprite;
callback(sprite);
}
edit:
A further explanation to clarify
var www = new WWW(url)
This grabs the images stored on a server which works, as far as I'm aware after one instance of grabbing the image this should place the item in cache for use later.
I've tried using the following updated method to see if that would fix it.
var www = WWW.LoadFromCacheOrDownload(url, 1)
This resulted in it not working in any capacity and never changing the images from the placeholders.
The first if statement in the "LoadSpriteCoroutine" is supposed to catch if the sprite already exists in the "_cache" Dictionary by checking if there is a key for the url, which there should be after the first running instance with and internet connection
Load image from _cache if its in there:
if (_cache.ContainsKey(url))
{
callback(_cache[url]);
yield break;
}
Add image to _cache if it wasn't previously in there:
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(texture.width / 2, texture.height / 2));
_cache[url] = sprite;
So I figured out a solution,
all the other methods of saving images to the cache seemed to fail for iOS, I removed all of the previous "_cache" stuff.
this function for saving worked for me:
//if file doesn't exist then save it for fututre reference
if (!File.Exists(_FileLocation + texName))
{
byte[] bytes;
if (Path.GetExtension(texName) == ".png")
{
bytes = texture.EncodeToPNG();
}
else
{
bytes = texture.EncodeToJPG();
}
File.WriteAllBytes(Application.persistentDataPath + texName, bytes);
}
that section is placed after the "callback(sprite)".
The check for saved items is placed where the old "if(_cache.ContainsKey(url))" section was
texName = Path.GetFileName(texName);
if (File.Exists( _FileLocation + texName))
{
url = _FileLocation + "/"+ texName;
}
please note that the "LoadSpriteCoroutine" now take a extra string argument 'texName' in its calls which is just the a shortened instance of the url which it then cuts to just the file name and extension. If it finds a match then it replaces url with a the persistent file path + the fileName to grab it locally opposed to over the network as normal.
_FileLocation is defined as follows
string _FileLocation;
public void Start()
{
_FileLocation = Application.persistentDataPath;
}
The reason behind referencing it in that method is to save performance from calling the address though application AND if you were working on a cross platform solution then the data path for saving may need to be changed as such you could put a detection if or case statement to change _FileLocation to suit your needs.
This question already has answers here:
Unity - need to return value only after coroutine finishes
(3 answers)
Closed 5 years ago.
Hi im trying to implement saving/loading from sql database into my game.
i have it all working apart from the fact that i need to hit load twice for it to load the data.
the code to set the data finishes before i have a chance to set it.
public void loadData()
{
GetComponent<SavingLoading>().Load(GameObject.Find("LoginSystem").GetComponent<LoginSystem>().Username);
if (GetComponent<SavingLoading>().LoadedData != "")
{
string[] Data = GetComponent<SavingLoading>().LoadedData.Split(',');
Level = Convert.ToInt32(Data[0]);
CurrentXp = Convert.ToInt32(Data[1]);
currentHealth = Convert.ToInt32(Data[2]);
maxHealth = Convert.ToInt32(Data[3]);
Vector3 LoadedPos = new Vector3(Convert.ToSingle(Data[4]), Convert.ToSingle(Data[5]), Convert.ToSingle(Data[6]));
transform.position = LoadedPos;
}
}
Theese functions are in another script.
public void Load(string name)
{
StartCoroutine(LoadCall(name));
}
IEnumerator LoadCall(string name)
{
WWWForm form = new WWWForm();
form.AddField("name", name);
WWW www = new WWW(LoadPhP, form);
yield return www;
string _return = www.text;
LoadedData = _return;
}
how can i go about only updating the data if there is data present? without having to press the load button twice.
According to the docs, you should wrap the www variable in a using statement in order to properly disposeit. Then yield return on it, like so:
using (WWW www = new WWW(url))
{
yield return www;
string _return = www.text;
LoadedData = _return;
}
I am not sure what you mean by 'only updating the data if there is data present'. Do you have more code to show that might help to clarify your intent?
I am using Unity3d (c#) with facebook API. I try to show my profile image on the screen when I run it on the unity simulator everything works perfect and I got the image. but when I build a version and try it on a real device I get nothing.
I know that there is a issue with facebook CDN. the result of the request is 302 and WWW class can't handle with redirects so I did something like this (c# is a new language for me):
WWW www = new WWW(url);
yield return www;
if( www.responseHeaders.ContainsKey( "LOCATION" ) ){
var redirection = www.responseHeaders[ "LOCATION" ];
WWW wwwRe = new WWW( redirection );
yield return wwwRe;
callback( wwwRe.texture, userID );
}else{
callback( www.texture, userID );
}
please help me I loose my mind, why all my personal data comes on the device except the image that works perfect in unity. what I did wrong?
thanks.
The solution:
I tried many options to get profile image on the device nothing worked.
finally I upgrade Facebook SDK from 6.2.1 to 6.2.2 and Unity from 5.1 to 5.1.3 remove the app again from the device ( clear all the data ) and it works. it looks like Facebook's issue ( this is not the first time that they release SDK with bugs ).
I accept Umair's answer even that his code have some syntax issues, he really tried to help me and basically his answer is right.
I used this code to test my image:
( hope it will help for someone )
private void getMyProfileData(){
// get profile image.
FB.API( Util.GetPictureURL( "me", 128, 128 ), Facebook.HttpMethod.GET, callBackGetProfilePicture );
}
private void callBackGetProfilePicture( FBResult result ){
// in case if there some error with the image.
if( result.Error != null ){
// call this method again
}
string ImageUrl = Util.DeserializePictureURLString( result.Text );
StartCoroutine(LoadPictureCoroutune( ImageUrl ));
}
IEnumerator LoadPictureCoroutune(string url){
var profilePicRequest = new WWW( (string)url );
yield return profilePicRequest;
if( profilePicRequest.error == null)
{
Texture2D profilePic = profilePicRequest.texture;
// my test image place
Image profileImage = FBavatar.GetComponent<Image>();
profileImage.sprite = UnityEngine.Sprite.Create( profilePic, new Rect(0,0,128,128), new Vector2( 0, 0 ));
}
else
{
Debug.LogError("Error While downloading Picture: " + profilePicRequest.error);
}
}
Use following Code to get Picture data from Facebook API:
FB.API ("/v2.4/me/?fields=picture", Facebook.HttpMethod.GET, RequestResponce);
In RequestResponce method:
void RequestResponce(FBResult result)
{
Debug.Log("requestResponce(): " + result.text);
if (!string.IsNullOrEmpty(result.Error))
{
Debug.Log("FB_API:ReadRequest:Failed:"+result.Error);
}
else
{
var data = SimpleJSON.JSON.Parse(result.Text);
string url = data["picture"]["data"]["url"];
StartCoroutine(LoadPictureCoroutune(url));
}
}
IEnumerator LoadPictureCoroutune(string url)
{
var profilePicRequest = new WWW(url);
Debug.Log("Going to Load Picture ");
yield return profilePicRequest;
if(profilePicRequest.error == null)
{
Texture2D profilePic = profilePicRequest.texture;
if(profilePic != null)
{
// Use ProfilePic to wherever you want to.
//SetPicture(ProfilePic);
}
}
else
{
Debug.LogError("Error While downloading Picture: " + profilePicRequest.error);
}
}
I have problems with my video player that uses the AV Foundation API and plays a clip via HTTP progressive download. Even when the AVPlayer is released, I'm still downloading the video clip (observed via an HTTP Traffic sniffer).
My player is initialized like that:
m_player = new AVPlayer();
m_playerLayer = new AVPlayerLayer();
m_playerLayer.Player = m_player;
Then, when I have the URL of the video:
m_url = new NSUrl (...);
m_asset = new AVAsset(m_url);
m_asset.AddObserver(this, new NSString ("playable"), NSKeyValueObservingOptions.Initial | NSKeyValueObservingOptions.New, AVPlayerAssetObservationContext);
When I'am notified that the asset is playable, I'm creating an AVPlayerItem:
m_playerItem = new AVPlayerItem(m_asset);
if (m_player.CurrentItem != m_playerItem)
{
m_player.ReplaceCurrentItemWithPlayerItem (m_playerItem);
}
My video is playing without any problems. Then, when I press a back button, I have a mechanism that call a Destroy() method. Here I tried a lot of things to be sure that my player is well released:
if(m_player != null)
{
m_player.Pause();
m_player.Dispose();
m_player = null;
}
if(m_playerLayer != null)
{
m_playerLayer.Dispose();
m_playerLayer = null;
}
if(m_playerItem != null)
{
m_playerItem.Dispose();
m_playerItem = null;
}
if(m_asset != null)
{
m_asset.CancelLoading();
m_asset.RemoveObserver(this, new NSString("playable"));
m_asset.Dispose();
m_asset = null;
}
if(m_url != null)
{
m_url.Dispose();
m_url = null;
}
I tested my app with a debugger and for sure, I'am falling into this code. My objects seems to be well released, but for sure the application is still downloading the video url. Am I doing something wrong in the init / release code?
Thank in advance for your help!
The workaround I found is to add this line in the Destroy() code
m_player.ReplaceCurrentItemWithPlayerItem(new AVPlayerItem());
The video download is then interrupted.