Static Trouble

I’m having some trouble with static variables, and because of the type of problem I have, I thought this is the best place to try and find help. Now, I know this is a pure Java question, but after searching the Internet, I still can’t understand everything.



Let’s say I have a Quest Class, and from the Main Class, I create two Quest Objects:



[java]static Quest q, p;[/java]



Now I have a Control class, and want to print out the quests’ names:



[java]public class Control {



public void controlPrint() {

System.out.println("1: " + Main.q.getQuestName());

System.out.println("2: " + Main.p.getQuestName());

}



}[/java]



If I don’t make the Quest variables static, I can’t access them. When I make them static, am I making the global? i.e. if I change their name from the Main, when I access them from the Control do I find their names changed?



Thanks a lot in advance.

If you use statics, the variables are changed globally, which means: yes, if you change them in method A, you will find them changed in method B.



But in this case it would be not the best idea to use static variables. You would have to create a new quest-class for every quest, which makes it harder to handle them. Better you use a data-object where you hold all your quests in a list or something similar.

1 Like

Thanks for clearing that up ceiphren! In my case, I won’t have a lot of quests probably - one, two or three. They will probably be randomly generated and the data fed into these three quest-classes when the player enters a dungeon.



The other thing I could think of is to have arrays for the quests. One array for the name, one for the reward etc… But that’s kind of the same, no?



Or I could create an XML file. I like the quest-class idea, personally, but what would you recommend?

@memonick: That depends on what the quest-object has to represent. It if is only a data-container, then I would create one quest-class (with all parameters as variables) and create an object for every quest. And if every quest has to explizitly identified I would use a hashmap to hold the quests, combined with an enum which holds the keys for the hashmap.



Something like:

[java]

class Quest

{

Object reward;

String name;

}



enum QuestKey

{

DRAGON_FIGHT(),

TREASURE_HUNT();

}



//and somewhere in the data-storage:

Hashmap<QuestKey, Quest> _quests = … blablabla…

[/java]



XML would also be a good idea and is more flexible. I would favor the pure-java-solution, because it’s type-save. Typos in a long xml-file are sometimes really annoying.

Wait. I think I misunderstood the first time. This is the Quest Class:



I’m sorry it’s commented out. I don’t know what happened.



[java]package mygame;



/**

  • @author Nicholas Mamo/Nyphoon

    /



    public class Quest {



    String questName, questObject, questGiver;

    int questType, questDifficulty, questMoneyReward;

    String[] questObjectReward = new String[100];



    /

  • Returns the quest’s name.

    /

    public String getQuestName(){

    return questName;

    }



    /

  • Returns the quest’s object.
  • This is the object needed to finish the quest.

    /

    public String getQuestObject(){

    return questObject;

    }



    /

  • Returns the quest’s giver.
  • This is the person who hands out the quests, and who hands the rewards.

    /

    public String getQuestGiver(){

    return questGiver;

    }



    /

  • Returns the quest type.
  • This can be: find an object; kill a number of enemies; find a person.

    /

    public int getQuestType(){

    return questType;

    }



    /

  • Returns the quest’s difficulty.
  • The higher the difficulty, the longer the dungeon.

    /

    public int getQuestDifficulty(){

    return questDifficulty;

    }



    /

  • Returns the quest’s money as a reward for the player upon
  • completing the quest.

    /

    public int getQuestMoneyReward(){

    return questMoneyReward;

    }



    /

  • Returns the quest’s objects as a reward for the player upon
  • completing the quest.

    /

    public String getQuestObjectReward(int num){

    return questObjectReward[num];

    }



    /

  • Set name of the quest.

    /

    public void setName(String n){

    questName = n;

    }



    /

  • Set object required to complete the quest.

    /

    public void setObject(String n){

    questObject = n;

    }



    /

  • Set quest giver’s name.

    /

    public void setGiver(String n){

    questGiver = n;

    }



    /

  • Set difficulty of the quest.

    /

    public void setDifficulty(int n){

    questDifficulty = n;

    }



    /

  • Set type of the quest.

    /

    public void setType(int n){

    questType = n;

    }



    /

  • Set money reward for the quest.

    /

    public void setMoneyReward(int n){

    questMoneyReward = n;

    }



    /

  • Set object reward for the quest.

    */

    public void setObjectReward(int n, String s){

    questObjectReward[n] = s;

    }

    }[/java]



    Then I use;



    [java]static Quest q, p;[/java]



    and;



    [java]public class Control {



    public void controlPrint() {

    System.out.println("1: " + Main.q.getQuestName());

    System.out.println("2: " + Main.p.getQuestName());

    }



    }[/java]



    These are objects, no?

Correct. Two static objects.

Is the Class I posted (the first, long code: public class Quest) what you suggest I use?

Yep. I can’t say if this is the best way. That depends on the project, but I would use the Quest-class as you wrote it.

1 Like

Thanks for the reassurance. Then I will use the Quest class I wrote. Once again, thanks a lot, and good night.

Using static is probably not the best way to go at it.



In my game, I have a QuestManager that takes care of the management. It hold several ArrayList containing the list of quests that have been done and the active ones. It’s also a listener to the InventoryManager that dispatch items when given/sold to the player/vendors (so for gathering quests when X item is received, the quest manager increment the quantity. Also, if a player tries to sell a quest item, it’s denied).



In my case, the QuestManager isn’t static, but you could do that.



You would end up with a static QuestManager class that would hold the list of active quests the player has. I think that’s the best way to go at it if you really want static.



But, exactly why do you need static quests?

The reason I ‘need’ it is because when I created the Control class, I couldn’t “access non-static from static context”.



In your case, what do the ArrayList contain? An array for the quests’ name, another one for the quests’ reward etc…? If this is what you do, I think I’d prefer making a Quest Manager, or just using static quests, rather than this. No offence intended, of course, but I find it easier to extract data like that. I think it’s more organized.

My QuestSystem (previously referred as QuestManager. I was going from memory.) contains something like this: (and yeah, it’s not an ArrayList, it’s a Map)



[java]

private Map<Integer, String> mainQuestsLog = Collections.synchronizedMap(new HashMap<Integer, String>());

[/java]



When a quest is created and accepted I add it to that log.



[java]

mainQuestsLog.put(rndQuest.questID, rndQuest.shortDescription);

[/java]



Think of this as a lookup table. The short description text contains what the user need to do at a first glance to complete the quest. The whole information can be retrieved from the QuestJournal.



The QuestJournal instantiation contains all the Quest objects in a List. That class’ activeQuests looks like this:



[java]

private final List<Quest> activeQuests = Collections.synchronizedList(new LinkedList<Quest>());

private final List<Quest> completedQuests = Collections.synchronizedList(new LinkedList<Quest>());

[/java]

In QuestJournal you can add, remove, get long and short description, etc.

To tell you the truth, I haven’t even learnt what a Map is, and neither a List. Why do you think using static quests wouldn’t work well? I can’t directly access non-static stuff from other classes, and therefore I need something (QuestManager) to be static.

Wee my approch is t have severl listernes spread everywhere.



NpcManager.deathlistener

Player.spawn

Player move

ect…

For alomost everything.

Quest objects now register to the needed listeners, and in a purly event based logic they do their work, untill they finish, then they deRegister everywhere and are disposed.

(Also quest states are saved into a database, so they can be continued after server restart.)



So short it depends on what you intend to do.



However instead of the 2-3 static variables I suggest to use a Static ArrayList, that way you decoupled the amount of quests from the logic.

First, static objects can’t be serialized unless you do it by hand. Not optimal, although it’s possible you might want to do that at some point, but that’s a different story. Serializing can be thought of as “saving” to disk, or dumped to disk would be a better equivalent, in binary format.



I imagine you want your players to save and load their games, and that would include quests accepted. If your quests are never changing then it would be fine, you could store the questID in an array list of something else and fetch the quests from that never-changing (most probably a “final static” list.



My guess as to why you have to use static is that you’re doing something wrong, or at the wrong place in your code.



Are you initializing those quests or whatever in the “main”?



What would be helpful is to have the code where a method instantiated such a quest.

To save the quests etc… I am already planning to save them in an XML file. Yes, I’m initializing them in the main. You think I should initialize them somewhere else?



Main:

[java]public class Main extends SimpleApplication {



Quest q, p = new Quest();

Control c = new Control();



public static void main(String[] args) {

Main app = new Main();

app.start();

}



@Override

public void simpleInitApp() {

q.setName(“First Quest”);

System.out.println(q.getQuestName());



p.setName(“Second Quest”);

System.out.println(p.getQuestName());

}

}[/java]



Control:

[java]public class Control {



public void controlPrint() {

System.out.println("1: " + Main.q.getQuestName());

System.out.println("2: " + Main.p.getQuestName());

}



}[/java]



As it is, from the Control class I can’t access them. “non-static variable q cannot be referenced from a static context”

Instantiate your q and p quests and your c control inside simpleInitApp instead.



[java]

@Override

public void simpleInitApp() {

q = new Quest();

p = new Quest();



q.setName(“First Quest”);

System.out.println(q.getQuestName());



p.setName(“Second Quest”);

System.out.println(p.getQuestName());

}

[/java]



The thing is that when “main(String arg[])” runs (which is a static method), this instantiates Main. When Main is instantiated, it also instantiates q, p and c but because Main is from a static method those also have to be static.



I might be unclear in my answer. Hopefully not.

No use. Same error. This is what I’m doing:



Main:

[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;



public class Main extends SimpleApplication {



Quest q, p;

Control c;



public static void main(String[] args) {

Main app = new Main();

app.start();

}



@Override

public void simpleInitApp() {

c = new Control();

q = new Quest();

q.setName(“First Quest”);

System.out.println(q.getQuestName());



p = new Quest();

p.setName(“Second Quest”);

System.out.println(p.getQuestName());

}



@Override

public void simpleUpdate(float tpf) {

c.controlPrint();

p.setName(“Third one”);

}

}

[/java]



Control:

[java]package mygame;



public class Control {



public void controlPrint() {

System.out.println("1: " + Main.q.getQuestName());

System.out.println("2: " + Main.p.getQuestName());

}



}

[/java]



Quest:



[java]package mygame;



public class Quest {



String questName, questObject, questGiver;

int questType, questDifficulty, questMoneyReward;

String[] questObjectReward = new String[100];



/*

  • Returns the quest’s name.

    /

    public String getQuestName(){

    return questName;

    }



    /

  • Returns the quest’s object.
  • This is the object needed to finish the quest.

    /

    public String getQuestObject(){

    return questObject;

    }



    /

  • Returns the quest’s giver.
  • This is the person who hands out the quests, and who hands the rewards.

    /

    public String getQuestGiver(){

    return questGiver;

    }



    /

  • Returns the quest type.
  • This can be: find an object; kill a number of enemies; find a person.

    /

    public int getQuestType(){

    return questType;

    }



    /

  • Returns the quest’s difficulty.
  • The higher the difficulty, the longer the dungeon.

    /

    public int getQuestDifficulty(){

    return questDifficulty;

    }



    /

  • Returns the quest’s money as a reward for the player upon
  • completing the quest.

    /

    public int getQuestMoneyReward(){

    return questMoneyReward;

    }



    /

  • Returns the quest’s objects as a reward for the player upon
  • completing the quest.

    /

    public String getQuestObjectReward(int num){

    return questObjectReward[num];

    }



    /

  • Set name of the quest.

    /

    public void setName(String n){

    questName = n;

    }



    /

  • Set object required to complete the quest.

    /

    public void setObject(String n){

    questObject = n;

    }



    /

  • Set quest giver’s name.

    /

    public void setGiver(String n){

    questGiver = n;

    }



    /

  • Set difficulty of the quest.

    /

    public void setDifficulty(int n){

    questDifficulty = n;

    }



    /

  • Set type of the quest.

    /

    public void setType(int n){

    questType = n;

    }



    /

  • Set money reward for the quest.

    /

    public void setMoneyReward(int n){

    questMoneyReward = n;

    }



    /

  • Set object reward for the quest.

    */

    public void setObjectReward(int n, String s){

    questObjectReward[n] = s;

    }

    }[/java]

The way you try to do it the fields have to be static. It seems you didn’t get what “instatiating an object” actually means. I also think that using this kind of static accessors is not good though.

Sorry, I confused it with initialization. But if I do this:



[java]Control c = new Control();

Quest q = new Quest();

q.setName("First Quest");

System.out.println(q.getQuestName());



Quest p = new Quest();

p.setName("Second Quest");

System.out.println(p.getQuestName());[/java]



how can I access q and p from another class?