I want to use a value from a json file
Here is the Json file
{
"button" : [
{
"x" : 50.0
},
{
"x" : 150.0
}
]
}
I have the following classes
(Button Class)
public class Button extends Sprite{
float x;
public Button() {
super(new Texture("button.png"));
}
#Override
public void setX(float x) {
this.x = x;
}
}
(Data Class)
public class Data {
public Array<Button> buttons;
public void load() {
buttons = new Array<Button>();
Json json = new Json();
json.setTypeName(null);
json.setUsePrototypes(false);
json.setIgnoreUnknownFields(true);
json.setOutputType(JsonWriter.OutputType.json);
json.fromJson(Data.class, Gdx.files.internal("buttons.json"));
}
}
(Main Class)
public class GameMain extends ApplicationAdapter {
SpriteBatch batch;
Data data;
#Override
public void create () {
batch = new SpriteBatch();
data = new Data();
data.load();
for(Button b : data.buttons) {
b.setX(b.x);
}
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
for(Button b : data.buttons) {
b.draw(batch);
}
batch.end();
}
}
I want to draw buttons in specific x positions that is held in json file
but it gives me nothing .
What is wrong in my code ?
Any ideas ?
at the end of load() you haven't asign the results. Just add buttons = :
public void load() {
//instead of this line:
//buttons = new Array<Button>();
Json json = new Json();
json.setTypeName(null);
json.setUsePrototypes(false);
json.setIgnoreUnknownFields(true);
json.setOutputType(JsonWriter.OutputType.json);
// set buttons here:
buttons = json.fromJson(Data.class, Gdx.files.internal("buttons.json"));
}
Your Data class loads another instance of a Data class and doesn't assign it to anything. It's circular and doesn't make sense. The load method should be static, return a Data object (which is what the last line of your current load method provides), and not be trying to instantiate an empty buttons array that goes unused.
Your button class hides both the x field and the setX method of the superclass, making it impossible to change the actual X position of the sprite that is used when it is drawn. Sprite already has an x parameter, so you should not be adding your own. If you merely remove those two things from your Button class, it should work.
That said, you should not be loading another copy of the same texture for each button. That's a waste of memory and texture swapping. And unless you are very careful about disposing the textures "owned" by these sprites, you are also leaking memory.
Related
How can I pass score value from one scene to another?
I've tried the following:
Scene one:
void Start () {
score = 0;
updateScoreView ();
StartCoroutine (DelayLoadlevel(20));
}
public void updateScoreView(){
score_text.text = "The Score: "+ score;
}
public void AddNewScore(int NewscoreValue){
score = score + NewscoreValue;
updateScoreView ();
}
IEnumerator DelayLoadlevel(float seconds){
yield return new WaitForSeconds(10);
secondsLeft = seconds;
loadingStart = true;
do {
yield return new WaitForSeconds(1);
} while(--secondsLeft >0);
// here I should store my last score before move to level two
PlayerPrefs.SetInt ("player_score", score);
Application.LoadLevel (2);
}
Scene two:
public Text score_text;
private int old_score;
// Use this for initialization
void Start () {
old_score = PlayerPrefs.GetInt ("player_score");
score_text.text = "new score" + old_score.ToString ();
}
but nothing displayed on screen, and there's no error.
Is this the correct way to pass data ?
I am using Unity 5 free edition, develop game for Gear VR (meaning the game will run in android devices).
Any suggestion?
There are many ways to do this but the solution to this depends on the type of data you want to pass between scenes. Components/Scripts and GameObjects are destroyed when new scene is loaded and even when marked as static.
In this answer you can find
Use the static keyword
Use DontDestroyOnLoad
Store the data local
3a PlayerPrefs
3b serialize to XML/JSON/Binary and use FileIO
1. Use the static keyword.
Use this method if the variable to pass to the next scene is not a component, does not inherit from MonoBehaviour and is not a GameObject then make the variable to be static.
Built-in primitive data types such as int, bool, string, float, double. All those variables can be made a static variable.
Example of built-in primitive data types that can be marked as static:
static int counter = 0;
static bool enableAudio = 0;
static float timer = 100;
These should work without problems.
Example of Objects that can be marked as static:
public class MyTestScriptNoMonoBehaviour
{
}
then
static MyTestScriptNoMonoBehaviour testScriptNoMono;
void Start()
{
testScriptNoMono = new MyTestScriptNoMonoBehaviour();
}
Notice that the class does not inherit from MonoBehaviour. This should work.
Example of Objects that cannot be marked as static:
Anything that inherits from Object, Component or GameObject will not work.
1A.Anything that inherits from MonoBehaviour
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
This will not work because it inherits from MonoBehaviour.
1B.All GameObject:
static GameObject obj;
void Start()
{
obj = new GameObject("My Object");
}
This will not work either because it is a GameObject and GameObject inherit from an Object.
Unity will always destroy its Object even if they are declared with the static keyword.
See #2 for a workaround.
2.Use the DontDestroyOnLoad function.
You only need to use this if the data to keep or pass to the next scene inherits from Object, Component or is a GameObject. This solves the problem described in 1A and 1B.
You can use it to make this GameObject not to destroy when scene unloads:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
You can even use it with the static keyword solve problem from 1A and 1B:
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
The testScript variable will now be preserved when new scene loads.
3.Save to local storage then load during next scene.
This method should be used when this is a game data that must be preserved when the game is closed and reopened. Example of this is the player high-score, the game settings such as music volume, objects locations, joystick profile data and so on.
Thare are two ways to save this:
3A.Use the PlayerPrefs API.
Use if you have just few variables to save. Let's say player score:
int playerScore = 80;
And we want to save playerScore:
Save the score in the OnDisable function
void OnDisable()
{
PlayerPrefs.SetInt("score", playerScore);
}
Load it in the OnEnable function
void OnEnable()
{
playerScore = PlayerPrefs.GetInt("score");
}
3B.Serialize the data to json, xml or binaray form then save using one of the C# file API such as File.WriteAllBytes and File.ReadAllBytes to save and load files.
Use this method if there are many variables to save.
General, you need to create a class that does not inherit from MonoBehaviour. This class you should use to hold your game data so that in can be easily serialized or de-serialized.
Example of data to save:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Grab the DataSaver class which is a wrapper over File.WriteAllBytes and File.ReadAllBytes that makes saving data easier from this post.
Create new instance:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
Save data from PlayerInfo to a file named "players":
DataSaver.saveData(saveData, "players");
Load data from a file named "players":
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
There is another way:
ScriptableObject
ScriptableObjects are basically data containers but may also implement own logic. They "live" only in the Assets like prefabs. They can not be used to store data permanently, but they store the data during one session so they can be used to share data and references between Scenes ... and - something I also often needed - between Scenes and an AnimatorController!
Script
First you need a script similar to MonoBehaviours. A simple example of a ScriptableObject might look like
// fileName is the default name when creating a new Instance
// menuName is where to find it in the context menu of Create
[CreateAssetMenu(fileName = "Data", menuName = "Examples/ExamoleScriptableObject")]
public class ExampleScriptableObject : ScriptableObject
{
public string someStringValue = "";
public CustomDataClass someCustomData = null;
public Transform someTransformReference = null;
// Could also implement some methods to set/read data,
// do stuff with the data like parsing between types, fileIO etc
// Especially ScriptableObjects also implement OnEnable and Awake
// so you could still fill them with permanent data via FileIO at the beginning of your app and store the data via FileIO in OnDestroy !!
}
// If you want the data to be stored permanently in the editor
// and e.g. set it via the Inspector
// your types need to be Serializable!
//
// I intentionally used a non-serializable class here to show that also
// non Serializable types can be passed between scenes
public class CustomDataClass
{
public int example;
public Vector3 custom;
public Dictionary<int, byte[]> data;
}
Create Instances
You can create instances of ScriptableObject either via script
var scriptableObject = ScriptableObject.CreateInstance<ExampleScriptableObject>();
or to make things easier use the [CreateAssetMenu] as shown in the example above.
As this created ScriptabeObject instance lives in the Assets it is not bound to a scene and can therefore be referenced everywhere!
This when you want to share the data between two Scenes or also e.g. the Scene and an AnimatorController all you need to do is reference this ScriptableObject instance in both.
Fill Data
I often use e.g. one component to fill the data like
public class ExampleWriter : MonoBehaviour
{
// Here you drag in the ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void StoreData(string someString, int someInt, Vector3 someVector, List<byte[]> someDatas)
{
example.someStringValue = someString;
example.someCustomData = new CustomDataClass
{
example = someInt;
custom = someVector;
data = new Dictionary<int, byte[]>();
};
for(var i = 0; i < someDatas.Count; i++)
{
example.someCustomData.data.Add(i, someDatas[i]);
}
example.someTransformReference = transform;
}
}
Consume Data
So after you have written and stored your required data into this ExampleScriptableObject instance every other class in any Scene or AnimatorController or also other ScriptableObjects can read this data on just the same way:
public class ExmpleConsumer : MonoBehaviour
{
// Here you drag in the same ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void ExampleLog()
{
Debug.Log($"string: {example.someString}", this);
Debug.Log($"int: {example.someCustomData.example}", this);
Debug.Log($"vector: {example.someCustomData.custom}", this);
Debug.Log($"data: There are {example.someCustomData.data.Count} entries in data.", this);
Debug.Log($"The data writer {example.someTransformReference.name} is at position {example.someTransformReference.position}", this);
}
}
Persistence
As said the changes in a ScriptableObject itself are only in the Unity Editor really persistent.
In a build they are only persistent during the same session.
Therefore if needed I often combine the session persistence with some FileIO (as described in this answer's section 3b) for loading and deserializing the values once at session begin (or whenever needed) from the hard drive and serialize and store them to a file once on session end (OnApplicationQuit) or whenever needed.
(This won't work with references of course.)
Besides playerPrefs another dirty way is to preserve an object during level loading by calling DontDestroyOnLoad on it.
DontDestroyOnLoad (transform.gameObject);
Any script attached to the game object will survive and so will the variables in the script.
The DontDestroyOnLoad function is generally used to preserve an entire GameObject, including the components attached to it, and any child objects it has in the hierarchy.
You could create an empty GameObject, and place only the script containing the variables you want preserved on it.
I use a functional approach I call Stateless Scenes.
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public static void loadMyScene(MySceneParams sceneParams, System.Action<MySceneOutcome> callback) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
UnityEngine.SceneManagement.SceneManager.LoadScene("MyScene");
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
You can keep global state in the caller's scope, so scene inputs and outputs states can be minimized (makes testing easy). To use it you can use anonymous functions:-
MyBigGameServices services ...
MyBigGameState bigState ...
Splash.loadScene(bigState.player.name, () => {
FirstLevel.loadScene(bigState.player, (firstLevelResult) => {
// do something else
services.savePlayer(firstLevelResult);
})
)}
More info at https://corepox.net/devlog/unity-pattern:-stateless-scenes
There are various way, but assuming that you have to pass just some basic data, you can create a singelton instance of a GameController and use that class to store the data.
and, of course DontDestroyOnLoad is mandatory!
public class GameControl : MonoBehaviour
{
//Static reference
public static GameControl control;
//Data to persist
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
//Otherwise check if the control instance is not this one
else if (control != this)
{
//In case there is a different instance destroy this one.
Destroy(gameObject);
}
}
Here is the full tutorial with some other example.
you have several options.
The first one I see is to use static variables, which you will not lose their information or value passing from scenes to scenes (since they are not bound to the object). [you lose the information when closing the game, but not when passing between scenes]
the second option is that the player or the object of which you do not want to lose the information, you pass it through the DontDestroyOnLoad function
Here I give you the documentation and the sample code. [You lose the information when you close the game, but not when you go between scenes]
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
Third is to use the playerPrefab [https://docs.unity3d.com/ScriptReference/PlayerPrefs.html]
that allow you to save information and retrieve it at any time without hanging it even after closing the game [you must be very careful with the latter if you plan to use it to save data even after closing the game since you can lose the data if you close the game suddenly , since player prefab creates a file and retrieves the information from there, but it saves the file at the end or closes the app correctly]
I'm developing an engineering app for android. The thing is that I need to draw: rectangles, figures made of rectangles, and their dimensions. Then if you touch one extreme of one dimension you are able to make that dimension of the rectangle longer or shorter.
I am implementing the next scheme in order to achieve my goal:
class DrawFigureWithDimensions extends View{
// implementation of the draw methods
// ...
class Rectangles{
// characterization of the attributes needed for each "rectangle"
// ...
class DimensionPositionType{ ... }
class DimensionExtremeType{ ... }
}
class DrawRectangleWithDimension extends DrawFiguresWithDimensions{ ... }
class DrawBoxWithDimension extends DrawFiguresWithDimensions{ ... }
...
Then, I have a problems implementing the inner classes of DimensionPositionType and DimensionExtremeType, I can't find out how to declare them in a suitable way. I need to be able to decide in the extended classes, like DrawRectangleWithDimensions, for example, what type of extreme of the dimension I need: fixed or movable. Something like this:
public class DrawRectangleWithDimensions extends DrawFiguresWithDimensions {
public DrawRectangleWithDimensions(Context context) {
super(context);
}
public void setFigure(double width, double height) {
figureRectangles = new Rectangle[1];
figureRectangles[0] = new Rectangle(0, 0, width, height);
figureRectangles[0].setHorizontalDimensionLeftExtremeType(FIXED);
figureRectangles[0].setHorizontalDimensionRightExtremeType(MOVABLE);
}
For instance, this is the code that I have for the inner class DimensionExtremeType:
class DimensionExtremeType{
boolean FIXED;
boolean MOVABLE;
DimensionExtremeType(String arg){
if(arg == "FIXED"){
setFixedExtreme();
}else if(arg == "MOVABLE"){
setMovableExtreme();
}
}
public void setFixedExtreme(){
FIXED = true;
MOVABLE = false;
}
public void setMovableExtreme(){
FIXED = false;
MOVABLE = true;
}
public String getDimensionExtremeType(){
if(FIXED==true){
return "FIXED";
}else if(MOVABLE==true){
return "MOVABLE";
}else {
return null;
}
}
}
I just know about the existence of the class enum, which solves the problem of design that I had. It's a much easier way of carrying it out. According to the example that I wrote in the wording of the question, this is the code using the class enum:
static class Rectangle{
// ...
DimensionExtremeType horizontalDimensionLeftExtremeType;
DimensionExtremeType horizontalDimensionRightExtremeType;
DimensionExtremeType verticalDimensionUpperExtremeType;
DimensionExtremeType verticalDimensionLowerExtremeType;
// =-=-=-= DIMENSION POSITION TYPES =-=-=-=
public enum DimensionExtremeType{FIXED, MOVABLE}
}
Then, in the extended classes, for instance DrawRectanglesWithDimensions:
public class DrawRectangleWithDimensions extends DrawFiguresWithDimensions {
public DrawRectangleWithDimensions(Context context) {
super(context);
}
public void setFigure(float width, float height) {
figureRectangles = new Rectangle[1];
figureRectangles[0] = new Rectangle(0, 0, width, height);
figureRectangles[0].horizontalDimensionLeftExtremeType = Rectangle.DimensionExtremeType.FIXED;
figureRectangles[0].horizontalDimensionRightExtremeType = Rectangle.DimensionExtremeType.MOVABLE;
figureRectangles[0].verticalDimensionUpperExtremeType = Rectangle.DimensionExtremeType.MOVABLE;
figureRectangles[0].horizontalDimensionRightExtremeType = Rectangle.DimensionExtremeType.MOVABLE;
}
}
This question has nothing to with debugging or in other words I'm not trying to monitor the value of a certain variable to verify if the code is running correctly. I have 6 buttons that can be enabled depending on a variable which we will call X. Each button has a different threshold of what X needs to be in order to enable that button. For example, button1 is enabled if X is at least 50, button2 if X is at least 165, etc. I can have an asynctask to poll variable X and enable or disable the buttons but is there a better way?
Add your variable to a class like so:
public class example {
private int X;
public int getX() { return X; }
public void setX(int x) {
X = x;
// When X is set notify your watchers
}
}
Next create an interface like so:
public interface VariableChangeWatcher {
public void variableChanged(int value);
}
If you make your class use this interface you can add watchers or listeners to know when the value of X has changed outside the class:
public class example {
VariableChangeWatcher watcher;
private int X;
public int getX() { return X; }
public void setX(int x) {
X = x;
// When X is set notify your watchers
if (watcher != null)
watcher.variableChanged(x);
}
}
Then in any class that uses example you can simply listen in to the interface to know when the value of X has changed:
public class exampleListener implements VariableChangeWatcher
{
public exampleListener() {
example e = new example();
}
#Override
public void variableChanged(int value) {
// Gets alerted when the X value inside our e variable has changed
}
}
Use encapsulation. Do not make x a variable. Make it a class, with a value inside it. Put a setter function on it. Then whenever the setter function is called, have it set the value and enable/disable all the proper buttons. This way you can't forget to do it anywhere- the only way to set it is via the setter method.
So I have a View:
public class RadialMenuWidget extends View
from where I want to start a thread like I do from an activity
String urlInput = "http://myserver.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(UpdateActivity, urlInput);
downloaderThread.start();
but I get the message "Expression expected" on this line "DownloaderThread(UpdateActivity,... " more specifically on the activity name (UpdateActivity) even though I imported the activity inside the Widget.
What can I do to avoid this while still being able to call the thread.
The idea is, I use the RadialMenuWidget, and inside the RadialMenuWidget class I test to see which menu button was pressed and based on that, I decide what to do next. Calling other intents works just fine, but now I want to start to download a file using a separate thread (that I can call from a regular activity's onButtonClick)
EDIT
So my radialMenu has this structure:
public class RadialMenuWidget extends View {
...
public interface RadialMenuEntry {
...
}
public RadialMenuWidget(Context context) {
...
}
#Override
public boolean onTouchEvent(MotionEvent e) {
...
if (state == MotionEvent.ACTION_UP) {
...
if (menuEntries.get(i).getName() == "Update now") {
String urlInput = "http://myhost.com/"+mynewfile;
DownloaderThread downloaderThread = new DownloaderThread(this.UpdateActivity, urlInput);
downloaderThread.start();
}
}
...
And the DownloadThread class looks like this:
public class DownloaderThread extends Thread {
public DownloaderThread(UpdateActivity inParentActivity, String inUrl)
{
downloadUrl = "";
if(inUrl != null)
{
downloadUrl = inUrl;
}
parentActivity = inParentActivity;
}
#Override
public void run()
{
// does the download
}
...
}
Please help.
Thank you
My solution in the end was to mimic a 2 button radial menu using images. I used the images as backgrounds for a button, placed them in a linear layout, used 9-patch images and got to call the thread onClick like before. So I avoided having to deal with radialMenuWidget in this view.
So question is over now.
I was hoping for a java solution to this problem since I am a newbie and eager to learn anything Android, but this is it, I will manage with my (ugly) solution.
The Setup : A RelativeLayout with a GLSurfaceView and a Button as shown in the image..
The Problem: Lets say I have other triangle models (The one in the picture being the initial model)... I wish to change the models cyclically on click of the button. Since button is on the UI thread and glSurfaceView runs on a separate thread, I don't exactly know how to pass the info/instruction to it. I know there is this thing called Handler in Android which might be useful in this case... But I need some help here..
Edit: If Handler is the right way, I need to know how to add Looper to that Handler... The documentation says add looper.prepare() at the start of run() method.. But the glSurfaceView creates thread implicitly, resulting in no run() method directly available..
I don't think it is necessary to use handlers to solve this issue but you may need to adjust the way you organise your classes.
Here is an example of an organisational structure that might solve your issue:
Activity Class
public class MainActivity extends Activity {
private int modelNumber = 0;
private ArrayList<Model> models = new ArrayList<Model>();
private YourRendererClass renderer;
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Setup GLSurfaceView
GLSurfaceView surface = new GLSurfaceView(this);
setContentView(surface);
renderer = new YourRendererClass();
surface.setRenderer(renderer);
// Set up models
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
etc.
// Display first model
renderer.setCurrentModel(models.get(modelNumber));
...
}
// Called by the button press:
// Use android:onClick="onClick"
// in your layout xml file within button
public void onClick(View view){
// Make it loop round
modelNumber++;
if(modelNumber>=models.size()){
modelNumber=0;
}
// Display current model
renderer.setCurrentModel(models.get(modelNumber));
}
}
Renderer Class
public class YourRendererClass implements Renderer {
private Model currentModel;
#Override
public void onDrawFrame(GL10 gl) {
// ** Your existing set-up code **//
// Draw model
if (currentModel!=null){
currentModel.draw(gl);
}
}
public void setCurrentModel(Model model){
currentModel = model;
}
}
Model class
public class Model {
// Holds model information
private int size;
private int x;
private int y;
// etc...
public model(int x, int y, int size etc...){
this.x=x;
this.y=y;
this.size=size;
// etc....
}
public void draw(GL10 gl) {
// ** Draw model based on model information fields above **
}
}
The above code is untested as I don't have access to your drawing code but the structure should work if implemented correctly. I've tried to make it clear where you'll have to insert your own code to make it work. In particular I wasn't sure what defines each of your different models so you'll need to include sufficient local variables within the Model class to define them.
I hope my answer helps, let me know if you have any questions.
Tim
You should look at queueEvent! It's a very convenient way to pass informations from UI Thread to renderer Thread:
queueEvent(new Runnable(){
#Override
public void run() {
mRenderer.method();
}});