Java Removing Object from Scene - java

I stumbled upon this problem. In my engine I finally figured out how I add objects to the scene after a condition is met. However I still can't figure out how an object can be removed from the scene.
This is the game loop
while(isRunning == true)
{
if(frames > 200)
{
building1 = false;
}
if(building1 == true) {
if(frames > 100) {
if(create_001 == true) {
model = true;
loadModel();
create_001 = false;
}
}
}
[...]
the (create_001 = false;) is there so that the object is only created once.
And this is how the models are being loaded in:
private Game game;
public void loadModel() {
GameObject object = new GameObject();
Mesh mesh = new Mesh(obj);
Material material = new Material (new Texture(texture));
MeshRenderer meshRenderer = new MeshRenderer(mesh, material);
object.AddComponent(meshRenderer);
game.AddObject(object);
}
As you can see I make the object appear after 100 frames and try to remove the object again after 200 frames by disabeling the building1 if check - however this doesn't work.
After 200 frames the object is still there and I wouldn't know why, has anyone a suggestion because I can't understand why it wouldn't work like that?
Thanks for any Help!
EDIT:
Here's the game class where I have the AddObject method which I call at the end of loadModel method:
public abstract class Game
{
private GameObject m_root;
public void Init() {}
public void Input(float delta) { GetRootObject().InputAll(delta); }
public void Update(float delta) { GetRootObject().UpdateAll(delta); }
public void Render(RenderingEngine renderingEngine) { renderingEngine.Render(GetRootObject()); }
public void AddObject(GameObject object) { GetRootObject().AddChild(object); }
private GameObject GetRootObject()
{
if(m_root == null)
m_root = new GameObject();
return m_root;
}
public void SetEngine(CoreEngine engine) { GetRootObject().SetEngine(engine); }
}
I probably would need some remove Object method but do not really know how I would need to design it.. I'll try out a little more, but I'm still open for suggestions.
Again thanks for any help!
EDIT2;
Well and here some details about the GameObject class.. it seems we get closer to the root of the problem:
private ArrayList<GameObject> m_children;
private CoreEngine m_engine;
public GameObject()
{
m_children = new ArrayList<GameObject>();
m_engine = null;
}
public GameObject AddChild(GameObject child)
{
m_children.add(child);
child.SetEngine(m_engine);
return this;
}
Thanks for the hints so far, I've tried out several other things but nothing seems to work yet, maybe there can something be done in the GameObject class?
Thanks a lot!
Here's the array list of game objects:
public ArrayList<GameObject> GetAllAttached()
{
ArrayList<GameObject> result = new ArrayList<GameObject>();
for(GameObject child : m_children)
result.addAll(child.GetAllAttached());
result.add(this);
return result;
}
and here the setEngine method:
public void SetEngine(CoreEngine engine)
{
if(this.m_engine != engine)
{
this.m_engine = engine;
for(GameComponent component : m_components)
component.AddToEngine(engine);
for(GameObject child : m_children)
child.SetEngine(engine);
}
}
hope this helps :)

Maybe you need to call some "remove_object" if(frames > 200) ?
Need more complete code to understand.
public abstract class Game {
public void RemoveObject(GameObject object) {
GetRootObject().RemoveChild(object);
}
}
class GameObject {
public void RemoveChild(GameObject child) {
m_children.remove(child);
}
}

Related

How to add a item to player

I'm trying to add some custom ability to this plugin by using it own API. I have some trouble adding items to players when they got a kill. I have tried a lot of different methods to add potion to the killer by using .addItem(). There is no wiki for this plugin and on their page, there is some information about the API. Here is my code
public class ChemistryAbility extends Ability{
//Return name of ability
#Override
public String getName() {
return "Chemistry";
}
//Get the data form config file.
#Override
public void load(FileConfiguration file) {
// TODO Auto-generated method stub
}
//Get the activate Material
#Override
public Material getActivationMaterial() {
return null;
}
//Get the activate projectile
#Override
public EntityType getActivationProjectile() {
return null;
}
//Will this ability activate when player attack another player
#Override
public boolean isAttackActivated() {
return true;
}
//Will this ability activate when player get attacked by another player
#Override
public boolean isAttackReceiveActivated() {
return false;
}
//Will this ability activate when player get damage
#Override
public boolean isDamageActivated() {
return false;
}
//Will this ability activate when player interact with another player
#Override
public boolean isEntityInteractionActivated() {
return false;
}
#Override
public boolean execute(final Player p, final PlayerData PD, final Event e) {
ItemStack potion = new ItemStack(Material.SPLASH_POTION, 3);
PotionMeta pmeta = (PotionMeta) potion.getItemMeta();
pmeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 2), true);
potion.setItemMeta(pmeta);
Player killer = p.getKiller();
if (p.isDead()) {
p.getKiller();
if (p.getKiller() instanceof Player) {
killer.getInventory().addItem(potion);
}
}
return false;
}
}
K, So i don't know that much about plugin dev, but here is my best shot with 15 min of research. Not sure about the API, but if u can implement this outside the event, try this
#EventHandler
public void onKill(PlayerDeathEvent e) {
if (e.getEntity().getKiller() != null) { // to check if there was actually a killer
Entity killer = e.getEntity.getKiller(); // stores killer instance
if (killer.hasMetadata("Chemistry")) { // checks if has class
killer.getInventory().addItem(new ItemStack(Material.BOOK));
}
}
}
i think. i honestly dont know
Potions have always been a pain in Minecraft. Mojang changes how item data works.
I have some Deprecated code that I made. This should work for a few of the upcoming updates.
public ItemStack getPotionItem(Color c, PotionEffectType type, PotionType pType, boolean splash, int time, int level) {
Potion p = new Potion(pType);
p.setSplash(splash);
p.setType(pType);
ItemStack pot = new ItemStack(Material.SPLASH_POTION);
PotionMeta im = (PotionMeta) pot.getItemMeta();
List<String> lores = new ArrayList<String>();
lores.add(getLore());
im.setDisplayName(getName());
im.addCustomEffect(new PotionEffect(type, time, level - 1), true);
im.setLore(lores);
im.setColor(getColor());
im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
pot.setItemMeta(im);
p.apply(pot);
return pot;
}

java.lang.InstantiationError. Class becomes abstract

I am currently working on a Bukkit plugin for Minecraft and I am getting a java.lang.InstantiationError error while trying to create a new object. The stacktrace is as follows;
Caused by: java.lang.InstantiationError: fancyui.craterhater.components.FancyComponent
at fancyui.craterhater.uibuilder.ComponentMaker.getComponent(ComponentMaker.java:13) ~[?:?]
at fancyui.craterhater.uibuilder.Editor_Page_0.getComponents(Editor_Page_0.java:40) ~[?:?]
at fancyui.craterhater.uibuilder.Editor$1.call(Editor.java:36) ~[?:?]
at fancyui.craterhater.masterfancyui.FancyUI.openInventory(FancyUI.java:195) ~[?:?]
at fancyui.craterhater.uibuilder.Editor.createEditorGUI(Editor.java:236) ~[?:?]
at fancyui.craterhater.commandhandler.MasterCommand$2.call(MasterCommand.java:69) ~[?:?]
at fancyui.craterhater.commandhandler.CECommand.playerExecutes(CECommand.java:105) ~[?:?]
at fancyui.craterhater.commandhandler.CECommand.checkPlayerExecutes(CECommand.java:98) ~[?:?]
at fancyui.craterhater.commandhandler.MasterCommand.onCommand(MasterCommand.java:153) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[1.8.jar:git-Spigot-870264a-0a645a2]
... 15 more
Line 13 of the ComponentMaker class simply says;
FancyComponent fancyComponent = new FancyComponent();
I did some debugging and decided to print the following;
System.out.println(FancyComponent.class.toGenericString());
This printed;
public abstract class fancyui.craterhater.components.FancyComponent
While the FancyComponent class is not abstract. Here is the FancyComponent class:
public class FancyComponent {
//FancyComponent class represents the individual items placed in a FancyUI.
//It handles things such as animation, itemstack building and event handling whilst
//allowing the FancyUI to handle loading and deleting of these components.
//FancyComponents are added to the FancyUI by the user of the API using LoadFunctions.
//They can also be generated from a FancyUI file.
private FancyLocation fancyLocation;
private FancyItemStack fancyItemStack;
private FancyDisplayType fancyDisplayType;
private String identifier = null;
private int ID = 0;
private int basicSlot = 0;
private boolean copied;
public FancyComponent() {
fancyDisplayType = FancyDisplayType.DYNAMIC;
}
public FancyComponent copy(FancyLocation newLocation) {
FancyComponent newComponent = new FancyComponent();
newComponent.setDisplayType(fancyDisplayType);
newComponent.setID(ID);
newComponent.setFancyItemStack(fancyItemStack);
newComponent.setFancyLocation(newLocation);
newComponent.setAttributes(attributes);
newComponent.setIdentifier(identifier);
return newComponent;
}
//Method gets called when FancyUI decides to load in new FancyComponents.
//This happens when openInventory gets called and new components are generated.
//This method should start future animations. It should also handle ItemStack placement.
//The boolean here represents whether or not it has succesfully been added. This is used in the
//FancyUI in order to keep track of all active components and not the once off-screen.
public boolean addToUI(Inventory inventory, Player p, FileConfiguration fc, FileConfiguration fc2) {
if(fancyLocation == null) {return false;}
return addToUI(inventory, p, fancyLocation, fc, fc2);
}
public boolean addToUI(Inventory inventory, Player p, FancyLocation fancyLocation, FileConfiguration fc, FileConfiguration fc2) {
if(fancyItemStack == null) {return false;}
FancyUI fancyUI = fancyLocation.getFancyUI();
FancyLocation masterFancyLocation = fancyUI.getFancyData().getCurrentFancyLocation();
if(!fancyLocation.isInView(masterFancyLocation, fancyDisplayType)) {return false;}
int basicSlot = fancyLocation.getBasicLocation(masterFancyLocation.getX(), masterFancyLocation.getY(), fancyDisplayType);
if(basicSlot < 0 || basicSlot >= inventory.getSize()) {return false;}
this.basicSlot = basicSlot;
ItemStack itemStack = fancyItemStack.buildItemStack(p,fc2);
if(fc != null) {
if(fc.contains("Components."+identifier+".Animations")) {
for(String animation : fc.getConfigurationSection("Components."+identifier+".Animations").getKeys(false)) {
if(fc.getBoolean(("Components."+identifier+".Animations."+animation+".continious"))){
List<String> frames = new ArrayList<>();
if(fc.contains("Components."+identifier+".Animations."+animation+".animation")) {
frames = fc.getStringList("Components."+identifier+".Animations."+animation+".animation");
}
int interval = fc.getInt("Components."+identifier+".Animations."+animation+".interval");
if(interval < 1) {
interval = 2;
}
int position = fc.getInt("Components."+identifier+".Animations."+animation+".position");
boolean continious = fc.getBoolean("Components."+identifier+".Animations."+animation+".continious");
boolean reverse = fc.getBoolean("Components."+identifier+".Animations."+animation+".reverse");
fancyItemStack.startAnimation(frames, p, interval, position, this, continious, reverse);
break;
}
}
}
}
if(fancyLocation.getFancyUI().getFancyData().isPlayerInventory()) {
if(fancyItemStack.getCustomName().getFancyStringAnimations().length > 0) {
fancyItemStack.startAnimation(fancyItemStack.getCustomName().getFancyStringAnimations()[0].getFrames(), p, 4, 0, this, true, false);
}
}
inventory.setItem(basicSlot, itemStack);
return true;
}
//Method to reload just this component. It is used when cycling through fancyLore. If a function makes changes
//to other components the reload method in the FancyUI has to be called in order to fully reload a page.
public void reload(Player p) {
FileConfiguration fc = DataHandler.getFile(96,p.getUniqueId().toString(), false, "Data", "Users");
ItemStack itemStack = fancyItemStack.buildItemStack(p,fc);
if(fancyLocation == null) {
return;
}
if(fancyLocation.getFancyUI().getFancyData().isPlayerInventory()) {
p.getInventory().setItem(basicSlot, itemStack);
return;
}
fancyLocation.getFancyUI().getFancyData().getInventory().setItem(basicSlot, itemStack);
}
//Method gets called when FancyUI deletes all information on other FancyComponents.
//This happens when openInventory gets called and new components are generated.
//Make sure that this method cleans up future animations so they don't go around throwing nullpointers.
//The ItemStack itself is removed automatically by the FancyUI.
public void notifyOfDeletion() {
fancyItemStack.stopAnimating();
}
//Attributes are pieces of code written by the user of the API in order to have certain things
//happen at certain events such as ON_CLICK or ON_DROP etc.
private List<Attribute> attributes = new ArrayList<>();
public void addAttribute(Attribute attribute) {
attributes.add(attribute);
}
public List<Attribute> getAttributes(){
return attributes;
}
public void setAttributes(List<Attribute> attributes) {
this.attributes = attributes;
}
//Method to identify which Attributes need to run at these specific occasions. These occasions
//may include things suchs as ON_CLICK or ON_1 just to name a few. This method consists of two
//distinct parts. The first part handles all generated components which have scripts assigned to them
//and the second part handles all components that have been generated by the plugin itself. And thus
//do not have scripts assigned to them.
public void handleEvent(FileConfiguration fc, FileConfiguration fc2, FunctionParams params, AttributeOccasion... attributeOccasions) {
//The 'identifier' is a tag all generated components get. It is unique to all components.
//Non-generated components do not have this tag and thus we can check for null to see whether or not
//it is generated.
if(identifier != null) {
if(fc.contains("Components."+identifier+".Scripts")) {
for(String script : fc.getConfigurationSection("Components."+identifier+".Scripts").getKeys(false)) {
if(fc.contains("Components."+identifier+".Scripts."+script+".events")) {
List<String> scriptLines = fc.getStringList("Components."+identifier+".Scripts."+script+".script");
for(String event : fc.getStringList("Components."+identifier+".Scripts."+script+".events")) {
A: for(AttributeOccasion attributeOccasion : attributeOccasions) {
if(attributeOccasion.name().equalsIgnoreCase(event)) {
fancyLocation.getFancyUI().getScriptParser().executeScript(params.getPlayer(), scriptLines, FancyUI.fancyUI.get(params.getPlayer().getUniqueId()), params.getFancyComponent(), fc2, false);
break A;
}
}
}
}
}
}
if(fc.contains("Components."+identifier+".Animations")) {
for(String script : fc.getConfigurationSection("Components."+identifier+".Animations").getKeys(false)) {
if(fc.contains("Components."+identifier+".Animations."+script+".events")) {
for(String event : fc.getStringList("Components."+identifier+".Animations."+script+".events")) {
A: for(AttributeOccasion attributeOccasion : attributeOccasions) {
if(attributeOccasion.name().equalsIgnoreCase(event)) {
List<String> frames = new ArrayList<>();
if(fc.contains("Components."+identifier+".Animations."+script+".animation")) {
frames = fc.getStringList("Components."+identifier+".Animations."+script+".animation");
}
int interval = fc.getInt("Components."+identifier+".Animations."+script+".interval");
if(interval < 1) {
interval = 2;
}
int position = fc.getInt("Components."+identifier+".Animations."+script+".position");
boolean continious = fc.getBoolean("Components."+identifier+".Animations."+script+".continious");
boolean reverse = fc.getBoolean("Components."+identifier+".Animations."+script+".reverse");
fancyItemStack.startAnimation(frames, params.getPlayer(), interval, position, this, continious, reverse);
break A;
}
}
}
}
}
}
}
//Handles all components generated by the plugin as well as generated components from file if this component is inside of an editor.
//If inside an editor generated components will have some attributes linked to them by the plugin. If not inside an editor, generated components
//will not have any attributes linked to them.
A:for(Attribute attribute : attributes) {
for(AttributeOccasion attributeOccasion : attribute.getAttributeOccasions()){
for(AttributeOccasion attributeOccasion2 : attributeOccasions) {
if(attributeOccasion.equals(attributeOccasion2)) {
attribute.getAttributeFunction().call(params);
continue A;
}
}
}
}
}
//This method is used to move the cursor in list cycleables.
public void performCursorMove(int delta, Player p) {
if(fancyItemStack == null) {return;}
FancyLore fancyLore = fancyItemStack.getFancyLore();
if(fancyLore == null) {return;}
fancyLore.moveCursor(delta, p);
}
public void setCursorPosition(int n, Player p) {
if(fancyItemStack == null) {return;}
FancyLore fancyLore = fancyItemStack.getFancyLore();
if(fancyLore == null) {return;}
fancyLore.setCursorPosition(n, p);
}
public int getSlot() {
return basicSlot;
}
public FancyLocation getFancyLocation() {
return fancyLocation;
}
public FancyItemStack getFancyItemStack() {
return fancyItemStack;
}
public void setFancyItemStack(FancyItemStack fancyItemStack) {
this.fancyItemStack = fancyItemStack;
}
public void setFancyLocation(FancyLocation fancyLocation) {
this.fancyLocation = fancyLocation;
}
public void setDisplayType(FancyDisplayType fancyDisplayType) {
this.fancyDisplayType = fancyDisplayType;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
public void setIsCopied(boolean copied) {
this.copied = copied;
}
public boolean isCopied() {
return copied;
}
public void setID(int ID) {
this.ID = ID;
}
public int getID() {
return ID;
}
public FancyDisplayType getFancyDisplayType() {
return fancyDisplayType;
}
}
The weird thing is that this does not occur on later versions of Spigot. I have tested this on 1.8, 1.9, and 1.15 and the error occurs on 1.8 and 1.9 but not on 1.15. Any help would be appreciated.
It appears to only not throw the error on the latest version (1.15). All other versions do throw the error.
After a few hours of testing I decided to copy paste the code of the problematic class into a new class. I renamed all references to this class. This fixed my issue but I am not particularly happy with it especially because the original name is still causing the error. So if I rename the new class to the old name the error reappears.

Java8 - "effectively final"

I'm using RxVertx which is a sort of RxJava along with Java8 and I have a compilation error.
Here is my code:
public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {
return context.findGame(templateId, state)
.flatMap(new Func1<RxMessage<byte[]>, rx.Observable<Game>>() {
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game game = null;
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game = new Game(); // ERROR is at this line
singleGames.put(0, game);
} else {
game = singleGames.get(0); // ERROR is at this line
}
}
});
}
}
return rx.Observable.from(game);
}
});
}
The compilation error is:
"Local variable game defined in an enclosing scope must be final or effectively final"
I cannot define 'game' as final since I do allocation\set and return it at the end of the function.
How can I make this code compile??
Thanks.
I have a Holder class that I use for situations like this.
/**
* Make a final one of these to hold non-final things in.
*
* #param <T>
*/
public class Holder<T> {
private T held = null;
public Holder() {
}
public Holder(T it) {
held = it;
}
public void hold(T it) {
held = it;
}
public T held() {
return held;
}
public boolean isEmpty() {
return held == null;
}
#Override
public String toString() {
return String.valueOf(held);
}
}
You can then do stuff like:
final Holder<Game> theGame = new Holder<>();
...
theGame.hold(myGame);
...
{
// Access the game through the `final Holder`
theGame.held() ....
Since you need to not modify the reference of the object you can wrap the Game in something else.
The quickest (but ugly) fix is to use an array of size 1, then set the content of the array later. This works because the the array is effectively final, what is contained in the array doesn't have to be.
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game[] game = new Game[1];
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game[0] = new Game();
singleGames.put(0, game[0]);
} else {
game[0] = singleGames.get(0);
}
}
});
}
}
return rx.Observable.from(game[0]);
}
Another similar option is to make a new class that has a Game field and you then set that field later.
Cyclops has Mutable, and LazyImmutable objects for handling this use case. Mutable is fully mutable, and LazyImmutable is set once.
Mutable<Game> game = Mutable.of(null);
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game.mutate(g -> new Game());
singleGames.put(0, game.get());
} else {
game[0] = game.mutate(g->singleGames.get(0));
}
}
LazyImmutable can be used to set a value, lazily, once :
LazyImmutable<Game> game = LazyImmutable.def();
public void call(RxMessage<byte[]> t1) {
//new Game() is only ever called once
Game g = game.computeIfAbsent(()->new Game());
}
You cant. At least not directly. U can use a wrapper class however: just define a class "GameContainer" with game as its property and foward a final reference to this container instead.
#dkatzel's suggestion is a good one, but there's another option: extract everything about retrieving/creating the Game into a helper method, and then declare final Game game = getOrCreateGame();. I think that's cleaner than the final array approach, though the final array approach will certainly work.
Although the other approaches look acceptable, I'd like to mention that you can't be sure subscribing to ebs will be synchronous and you may end up always returning null from the inner function. Since you depend on another Observable, you could just simply compose it through:
public rx.Observable<Game> findGame(
long templateId,
GameModelType game_model,
GameStateType state) {
return context.findGame(templateId, state)
.flatMap(gameRawReply -> {
switch(game_model) {
case SINGLE: {
return ebs.map(t1 -> {
Game game;
if (!singleGame.contains(0) {
game = new Game();
singleGames.put(0, game);
} else {
game = singleGames.get(0);
}
return game;
});
}
}
return rx.Observable.just(null);
});
}

How to navigate in a circle

the title might be not very descriptive but i couldn't think of a better one.
The problem is as follows:
I have one screen (ScreenOne) with a link to another screen (ScreenTwo).
On the ScreenTwo is a link back to ScreenOne.
I implemented this via custom RichTextFields and a custom ChangeListener.
Now the problem is that i keep getting a StackOverflowError!
Is there any way to navigate back and forth in that way?
regards matt
public class MyApp extends UiApplication
{
public static void main(String[] args)
{
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp()
{
ScreenOne so = ScreenProvider.getInstance().getScreenOne();
so.initialize();
ScreenProvider.getInstance().getScreenTwo().initialize();
pushScreen(so);
}
}
public class ScreenOne extends MainScreen {
MyTextField link;
public ScreenOne() {
link = new MyTextField("FirstScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenTwo()));
}
}
public class ScreenTwo extends MainScreen {
MyTextField link;
public ScreenTwo() {
link = new MyTextField("SecondScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenOne()));
}
}
public class MyFieldChangeListener implements FieldChangeListener {
private Screen nextScreen;
public MyFieldChangeListener(Screen nextScreen) {
this.nextScreen = nextScreen;
}
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().pushScreen(nextScreen);
}
}
public class MyTextField extends RichTextField {
public MyTextField() {
super();
}
public MyTextField(String text) {
super(text);
}
protected boolean touchEvent(TouchEvent message) {
if (TouchEvent.CLICK == message.getEvent()) {
FieldChangeListener listener = getChangeListener();
if (null != listener)
listener.fieldChanged(this, 1);
}
return super.touchEvent(message);
}
}
public class ScreenProvider {
private static ScreenProvider instance = null;
private ScreenProvider(){}
public static ScreenProvider getInstance() {
if (instance == null) {
instance = new ScreenProvider();
}
return instance;
}
private ScreenOne screenOne = new ScreenOne();
private ScreenTwo screenTwo = new ScreenTwo();
public ScreenOne getScreenOne() {
return screenOne;
}
public ScreenTwo getScreenTwo() {
return screenTwo;
}
}
The constructor of ScreenOne creates a ScreenTwo instance, and the constructor of ScreenTwo creates a ScreenOne instance. You have an infinite loop here.
Regarding revision 5 of this question:
new ScreenProvider() -> new ScreenOne() -> ScreenProvider.getInstance() -> new ScreenProvider() -> ...
still infinite. Again, the problem is that you're trying to setup a cycle via object constructors. You need to create the objects first, then assign the next and previous.
Regarding revision 4 of this question:
getScreenOne() -> new ScreenOne() -> getScreenTwo() -> new ScreenTwo() -> getScreenOne() -> newScreenOne() -> ...
you still have an infinite loop, because the constructors are trying to store an instance of each other. You need to construct the objects first, then add the cyclic references.
In your ScreenProvider you don't need to make screen1/screen2 static -- they're members of the singleton instance.
Outside of that the other problem I see in this current version is that you're going to be pushing a screen onto the stack -- that's already on the stack. Try popping the prior screen first.
That overflow error is likely the result of an infinite loop caused by constantly jumping from ScreenOne and ScreenTwo. Could you describe what you actually would want to accomplish and/or show a snippet of code?

Overriding constructors in Java

For school I need to learn Java and since I'm used to C++ (like Cocoa/Objective-C) based languages, I get really frustrated on Java.
I've made a super-class (that can also be used as a base-class):
public class CellView {
public CellViewHelper helper; // CellViewHelper is just an example
public CellView() {
this.helper = new CellViewHelper();
this.helper.someVariable = <anything>;
System.out.println("CellView_constructor");
}
public void draw() {
System.out.println("CellView_draw");
}
public void needsRedraw() {
this.draw();
}
}
public class ImageCellView extends CellView {
public Image someImage;
public ImageCellView() {
super();
this.someImage = new Image();
System.out.println("ImageCellView_constructor");
}
public void setSomeParam() {
this.needsRedraw(); // cannot be replaced by this.draw(); since it's some more complicated.
}
#Override public void draw() {
super.draw();
System.out.println("ImageCellView_draw");
}
}
Now, when I call it like this:
ImageCellView imageCellView = new ImageCellView();
imageCellView.setSomeParam();
I get this:
CellView_constructor
ImageCellView_constructor
CellView_draw
However, I want it to be:
CellView_constructor
ImageCellView_constructor
CellView_draw
ImageCellView_draw
How can I do this?
Thanks in advance,
Tim
EDIT:
I also implemented this method to CellView:
public void needsRedraw() {
this.draw();
}
And this to ImageCellView:
public void setSomeParam() {
this.needsRedraw(); // cannot be replaced by this.draw(); since it's some more complicated.
}
And I've been calling this:
ImageCellView imageCellView = new ImageCellView();
imageCellView.setSomeParam();
Does this causes the problem (when I call a function from the super it calls to the super only)? How can I solve this... (without having to redefine/override the needsRedraw()-method in every subclass?)
You should get proper output.
I tried you example just commented unrelated things:
import java.awt.Image;
public class CellView {
//public CellViewHelper helper; // CellViewHelper is just an example
public CellView() {
//this.helper = new CellViewHelper();
//this.helper.someVariable = <anything>;
System.out.println("CellView_constructor");
}
public void draw() {
System.out.println("CellView_draw");
}
public static void main(String[] args) {
ImageCellView imageCellView = new ImageCellView();
imageCellView.draw();
}
}
class ImageCellView extends CellView {
public Image someImage;
public ImageCellView() {
super();
//this.someImage = new Image();
System.out.println("ImageCellView_constructor");
}
#Override public void draw() {
super.draw();
System.out.println("ImageCellView_draw");
}
}
and I get following output:
CellView_constructor
ImageCellView_constructor
CellView_draw
ImageCellView_draw
This is exactly what you want, and this is what your code print's.
The short answer is "you can't."
Objects are constructed from the bottom up, calling base class initializers before subclass initializers and base class consrtuctors before subclass constructors.
EDIT:
The code you have looks good, based on your edit. I would go through the mundane tasks like ensuring that you have compiled your code after you've added you System.out.println calls to your subclass

Categories

Resources