OO game design question - java

I am programming a simple game in Java but I am trying to do it 'right' with a nice clean design and no hacks.
I have two classes GamePanel that receives clicks and keypresses and Model which contains all the Entities and is responsible for their updates. The Model needs to know where the user's mouse is but I can't decide on the 'right' way to do it.
Should the Model and every Entity within keep a reference to the GamePanel or just cache the last known mouse position and receive updates from the GamePanel regularly. With the first option when the model is created it will need to be given a reference to the GamePanel and with the second the last mouse position will be sent as a parameter to the World.update() method.
Neither of these solutions seem elegant so I was wondering if there is a 'right' way to do this that I have missed.
Thanks,
Ben.

In my opinion, it would depend on how your classes are interacting. Is a change in the mouse position triggering the entities in the Model class? or Is the Model class independent of the GamePanel and only works on the current values of Mouse position?
If the later and in that case I agree with what jeff has said before me. Pass a handle on the GamePanel to the Model class when creating it and let every entity use the handle to access the mouse position whenever needed. That way the updated mouse position is always used.
If the former I would suggest use Observers to let the Model class know when the mouse position value has changed. Then Model class could use the same design (i.e let the Model class have an handle on the GamePanel class always) and access the current values in the GamePanel.
To sum up my answer to your question, I think it is only logical and conforming to OO concepts to let the GamePanel hold the values of the mouse position and let other classes access that information using a GamePanel instance.
Thanks,
Rohan.

A common solution is to fire events. In this case GamePanel would fire an event informing all interested (subscribed to the event) objects (Entity) in Model of the new mouseposition.
In this way, GamePanel does not need to know explicitly which Entities to inform, and the Entities do not need to keep an instance of GamePanel around.
My advice: read up on event listeners. (Java.util)

You could always have the current coordinates be a public property of the GamePanel, so that the Entitys/Models can simply access it from there.

Does the model always need to know where the mouse is. IE: Do you need the mouse position at every update, or only at a specific points.
If you need it at every point or during every update then either solution that you have documented, or anyone solution here should be solid.
If you only need it at specific points then only grab it then. (IE: if your game responds to mouse clicks then do something on click.) Meaning Read about Event Listeners.
Good luck! Hope that helps.

If you want to poll the current mouse position, you could run this code snipplet in the Event Dispatch Thread at any time you wish:
Point pt = MouseInfo.getPointerInfo().getLocation();
Point cpt = GamePanel.getLocationOnScreen();
Point rel = new Point(pt.x - cpt.x, pt.y - cpt.y);
And rel contains the relative position of the mouse.
Alternatively, you could have a look at JInput, as it is designed to cope with keyboard/mouse/whatever inputs.

Related

Swing: Determining containing object for end of drag

I'd like to know what object a swing MouseMotionEvent (or MouseReleased) ends in. The problem is that both the MousePressed and MouseReleased events go to the object that was under the "press", not the release.
Here's a contrived example that may explain better:
The user sees a screen with some balls and some baskets and is told to drag a ball to a basket. Each ball represents some entity in the application space and each basket represents some action to take in the application space. From the Swing point of view, the balls and baskets are implemented separately as highly-overridden JButtons. On mousePressed the ball stores its identity in a known place. I'd like mouseReleased to be caught by a MouseListener in the basket which checks up the balls identity in the known place and then goes off into program logic and do the task represented by that basket.
But as I understand Swing (actually the AWT) the mouseReleased event goes to the component that contained the mousePressed event (ie the ball). Other than looking at X and Y (which seems an atrocious kludge) how do I figure out which basket the mouseReleased happened in? (If the mouseRelease happened outside of any basket, I'll need to take some sort of default reset action. Than can be done by a mouseEvent handler in the underlying JPanel).
(Please don't tell me this is a poor interface. The example I've given is not real. It abstracts out the problem I have in a way that I think is easy to visualize and understand.)
If the mouseRelease happened outside of any basket, I'll need to take some sort of default reset action -
Use the Drag and Drop API and then you will only be able to drop on components that support your drop.
Other than looking at X and Y (which seems an atrocious kludge)
Why? The event doesn't have the information so you need to get it somehow. So if you don't want to use the DnD API then you need to do this yourself.
There are methods in the API to help you do this:
Window window = SwingUtilities.windowForComponent( e.getComponent() );
Point dropPoint = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), window);
Component dropComponent = SwingUtilities.getDeepestComponentAt(window, dropPoint.x, dropPoint.y);

In Java, is it good practice to pass through listeners (or objects) where it affects the parent component?

More of a theory question, possibly a silly one but was curious to know if there's a better way of implementing it.
Ok so the question:
What is the best way of implementing two child-classes to interact with each other when an event from one of them is fired? I didn't word that well, so perhaps a diagram would be of use.
MainPanel
/ \
/ \
/ \
Child #1 Child #2
So in the above 'diagram' (yey amazing drwaz skills), there's a MainPanel that holds/instantiates two child panels. These components are outside of each others scope, unless I'm mistaken, and therefore can not directly interact with each other.
Lets say Child #1 has a JButton, and when the event is fired, Child #2 changes it's JLabel from "Hi" to "Bye". How would you go about doing so in the 'best' way possible?
Currently, my implementation of the above would involve having Child #1's constructor call for a Listener to be passed through it, where it sets the listener on the JButton to whatever listener the object is instantiated with.
Code of that would look like :
public class MainPanel extends JPanel {
private Child1 child1;
private Child2 child2;
private ActionListener listener;
public MainPanel(){
listener = new ActionListener(){
public void actionPerformed(ActionEvent ex){
//some code
}
};
child1 = new Child1(listener);
child2 = new Child2();
}
}
public class Child1 extends JPanel {
private JButton button;
private Component component;
public Child1(ActionListener listener){
button = new JButton("button");
component = new Component();
button.addActionListener(listener);
setUpGUI();
}
}
Just crude coding to show what I currently do to relate sub-classes like that, I realize there are some things missing. And yes, in that above case I could've had the JButton in the main panel as it's only one button, but with JPanels or components that have many many layers to them it's not so simple and dividing them up is necessary.
Also, the Child2 panel would have a method to invoke when the action is fired, that I would call in the listener I create in the main panel.
TL;DR:
Essentially is there a better way of going about what I do in the above code to relate two sub classes that aren't in the same scope?
The general strategy this is solved is through an MVC architecture. In an MVC architecture, you keep a model that represents the data being manipulated and is the single repository of truth. In some situations, this model may be linked with a database, but there does not necessarily have to be a database.
All of UI views only have to know about the model and how to update itself with regard to the current state of the model. All UI controls only have to know about the model and how to update the model when the UI control is activated. The model provides a notification service for interested parties, every time the model gets updated, the model searches through the list of interested parties for those that are listening for the type of change that had just happened, and send a change event notification so they can update themselves.
This way, any UI elements doesn't need to know about any other UI elements, it only needs to know about the models. Note that when a UI control is activated, it triggers action notifications to the model, which triggers change notifications to the UI views and possibly to the database; the UI views do not need to know what control originally triggered the change in the model and thus do not need the original action listener. Which controls triggered the change does not matter, only that the change happens and that the UI view is stale and need to be updated.
Note that a single UI widget can play the role of both a UI view and a UI controller, but these roles should be distinguished.
In your case, Child #1 seems to play the role of the UI controller, and Child #2 plays the role of one of the view that needs to be updated. You need a way to manage the events registrations such that the Model is notified when Child #1 is activated and register Child #2 as an interested party whenever the Model's status changes. Once this is set up, child #1 should only need to know to notify the Model that it wants the model to change its status to "Bye"; the Model then needs to look for who is interested in the status change, and find that Child #2 does, and sends a status change event.
There are plenty of ways to do it. Neither of them is the best (depends on the situation). I would stick to the rule called "KISS" - in short, keep it simple. If one does not have many references in their code (which is your example) - just give a reference to its sibling to each acting class, and that is it. Very easy, and you will be able to understand what is happening in your code easily. Unless you want struggling.
If you want struggling - this is a very good solution for your example: http://en.wikipedia.org/wiki/Mediator_pattern. But I would just stick to your present solution, because simplicity is the ultimate sophistication.

Force repaint from another class - Swing

I basically have 1 class called ClueGame dedicated to painting the main gui using swing.
In this class, I iterate through a list of BoardCell objects, and call boardcell.draw(g) from within paintComponents(Graphics g), which draws rectangles to the board.
However, in a different class entirely, the WalkwayCell class (a child of BoardCell), I need to update the color of specific rectangles. I'm thinking something like cell.updateColor()
But obviously I need to get draw to do that some how. I don't know how to update the color of one object (rectangle) on the board because I can't call draw because I don't have a graphics object.
Hopefully that makes sense. I can post code if someone requests it.
You have any number of options...
You Could
Pass a reference of your ClueGame to the instances of WalkwayCell which would then be capable of calling repaint on the ClueGame reference directly.
The problem with this is you expose the entire ClueGame class to ever instance of WalkwayCell, which allows them to do whatever they want to it...
You Could
Use an observer pattern, to allow the ClueGame to monitor changes to the state of the WalkwayCells
This means that WalkwayCell doesn't really care, it will simply provide some kind of event notification when the state of the object changes and doesn't expose parts of your application to other parts that have no right to know about...
Swing makes use of the observer pattern for it's listener API. You could take a look at Writing Event Listeners for some more ideas...
When creating a Swing GUI, it’s important to create GUI model classes. The model classes hold the data for the GUI. Having model classes makes coding the Swing view classes so much simpler.
In your case, you would change the state of the instance of the WalkwayCell class, using a method like cell.updateColor(), as you suggested. First, you update the model instances. Then you draw the model instances on the view.
I've explained this concept in more detail with a working example in my Hangman Swing GUI article.

Any methods in place to detect when focus is lost on a jfreechart plot/chart

this is hopefully going to be a simple one on a friday afternoon. I have a plot/jfreechart and i add a marker and change it based on the x,y location. The question i have is, is there anyway to tell when the jfreechart in quesition looses foscus. i.e the mouse has been moved from the jfreechart/plot on to another Jcomponent?
Cheers
The only way I imagine to do such a thing would be to add a listener to the chart, Either a MouseListener or FocusListener as these record 'live' events such as mouse movements or focus changes. I don't know how compatible these options are with your chart but these are likely to be your best (and possibly) only options. I would look into whether you are able top incorporate these into your program onto your chart and go from there.
Good Luck!

How do I revert state of JToggleButton from another class?

I am trying to write simple vector graphics editor in Java and got stuck with GUI... I have 2 JPanels: First one is for the "canvas area", second one is for the buttons. Canvas area is a Singleton, so then button pressed, it calls method of the Singleton and it adds element to list of the Singleton and re-paints the area. But now, I want to change these buttons to JToggleButtons and don't know how to revert it's state after click on the canvas.
Which design pattern should I use (because I have bad feeling that I'm doing it wrong)?
Have you ever heard of call backs? Once they are understood and implemented correctly, they can work quite nicely.
http://en.wikipedia.org/wiki/Callback_(computer_science)
I like this example too.
http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ310_019.htm
Make use of the Command and Memento patterns. Implement an Undo Command. Allow commands to store state in the form of a Memento. Restore the state from the Caretaker when you find fit.

Categories

Resources