patternjavaMinor
Displaying game progress in a JApplet
Viewed 0 times
progressgamejappletdisplaying
Problem
I gave myself a small project to work on and at first I wanted to use the MVC approach, but I got confused as to which part of my code should go into which class. I did some research and still don't quite understand how I should go about it.
This is the GUI I made:
I created the View class:
```
public class LevelUpView extends JApplet{
Image levelUp, clickMeImg, expBarImg, currentLvlImg, obtainedExpImg;
Image expBarImg2, expBarImg3, expBarImg4;
ImageIcon levelUpIcon, clickMeIcon, expBarIcon, currentLvlIcon, obtainedExpIcon;
ImageIcon expBarIcon2, expBarIcon3, expBarIcon4;
JLabel title, expBar, currentLvl, currentLevel, obtainedExp;
JLabel expTotal;
JButton clickMe;
JPanel mainPanel;
int experience = 0;
int level = 0;
String lvl = "0";
String exp = "0";
public void init(){
mainPanel = new JPanel( new BorderLayout()); // main container for layout
mainPanel.setBackground(new Color(213, 213, 210));
add(mainPanel);
createTitle(); // creates each section of the layout
createCenter();
createBottom();
}
private void createTitle(){
levelUp = getImage(getCodeBase(), "Images/LevelUpLogo.png");
levelUpIcon = new ImageIcon(levelUp);
title = new JLabel(levelUpIcon);
mainPanel.add(title, BorderLayout.NORTH);
}
private void createCenter(){
JPanel centerPanel = new JPanel();
centerPanel.setLayout( new BoxLayout( centerPanel, BoxLayout.Y_AXIS));
centerPanel.setBorder(new EmptyBorder(0,0,-140,0)); // spacing
JPanel clickMeLayout = new JPanel(new BorderLayout());
clickMeLayout.setBorder( new EmptyBorder(90,0,0,0));
JPanel expBarLayout = new JPanel( new BorderLayout());
expBarLayout.setBorder( new EmptyBorder(-190,1,1,55));
expBarLayout.setOpaque(false); // allows background to show
clickMeLayout.setOpaque(false);
centerPanel.setOpaque(false);
This is the GUI I made:
I created the View class:
```
public class LevelUpView extends JApplet{
Image levelUp, clickMeImg, expBarImg, currentLvlImg, obtainedExpImg;
Image expBarImg2, expBarImg3, expBarImg4;
ImageIcon levelUpIcon, clickMeIcon, expBarIcon, currentLvlIcon, obtainedExpIcon;
ImageIcon expBarIcon2, expBarIcon3, expBarIcon4;
JLabel title, expBar, currentLvl, currentLevel, obtainedExp;
JLabel expTotal;
JButton clickMe;
JPanel mainPanel;
int experience = 0;
int level = 0;
String lvl = "0";
String exp = "0";
public void init(){
mainPanel = new JPanel( new BorderLayout()); // main container for layout
mainPanel.setBackground(new Color(213, 213, 210));
add(mainPanel);
createTitle(); // creates each section of the layout
createCenter();
createBottom();
}
private void createTitle(){
levelUp = getImage(getCodeBase(), "Images/LevelUpLogo.png");
levelUpIcon = new ImageIcon(levelUp);
title = new JLabel(levelUpIcon);
mainPanel.add(title, BorderLayout.NORTH);
}
private void createCenter(){
JPanel centerPanel = new JPanel();
centerPanel.setLayout( new BoxLayout( centerPanel, BoxLayout.Y_AXIS));
centerPanel.setBorder(new EmptyBorder(0,0,-140,0)); // spacing
JPanel clickMeLayout = new JPanel(new BorderLayout());
clickMeLayout.setBorder( new EmptyBorder(90,0,0,0));
JPanel expBarLayout = new JPanel( new BorderLayout());
expBarLayout.setBorder( new EmptyBorder(-190,1,1,55));
expBarLayout.setOpaque(false); // allows background to show
clickMeLayout.setOpaque(false);
centerPanel.setOpaque(false);
Solution
Some short note without really reading into the source.
In MVC usually the Model is independent of View and Controller.
So your
Some general notes how I would split these:
Model:
example of API:
View:
I prefer to couple my views tightly with models, so the init/update methods take reference to actual model class (ie. View has to import Model).
It's not storing the model reference, only using it's API to init/update it's current state and forgetting about it, so you can any time change the View to display current state of different instance of model.
With the above model, and intent to have special effect for "level up" event, I would probably design API as:
Which would use getters to set up the exp bar, exp number display, level number display, set up correct colours based on those, and finally to start some effect when
In case of some more complex level-up effect I would consider either making state of it part of original model, or having separate LevelUpEffectModel to hold state of effect, with it's own view and controller.
Controller:
Finally controller is the glue of view and model, but should not contain any biz-logic, or low-level view updating commands.
So in this example it would do probably things like:
So things like
Model contains every important state of the world, so the view can be reconstructed out of it (above I'm breaking it a bit by that "leveledUp" value, writing it now, I would probably move it inside Model, and create one more getter
View contains everything what is displayed, for example it contains the string representation of experience (Model doesn't have to, as it can be constructed from the
Controller should only "connect the dots" and control the execution flow, when what should be called/updated.
The Model/View relation - how I like it - can be demonstrated on this classic:
Consider having blog application, so for each article you have date+time of publishing the article.
Then Model should contain UTC timestamp value (can be unix timestamp, if you need only dates since 1970 onward).
And View will do all the formatting magic, ie showing "5 seconds ago" for fresh article, or "previous millennium" for some really old article, also converting the date/time to local time zone of user (source data stored on server being in UTC, time zone agnostic).
Usually when you can UnitTest all model API easily in pure JUnit (without mocking JApplet environment or providing fake UI/display), you are on the right track. There's sometimes need to provide some complex
In MVC usually the Model is independent of View and Controller.
So your
public class LevelUpModel extends LevelUpView implements ActionListener looks like mixing together Model and View class, supplementing functionality of Controller too.Some general notes how I would split these:
Model:
- contains experience, level (private, plus getter/setter), level exp-threshold values table (may be public constant, if it's not only internal, like some part of app is displaying page with exp levels)
- may contain some further model related constants, like MAX_EXP_TO_ADD, etc.
- contains "business" logic operating with the model state
example of API:
public interface LevelUpModel {
// it's actually quite rare for model class
// to extend some non-model/non-trivial class
// *** getters/setters ***
int getExperience();
// no need for setter? (addExperience method available to adjust exp)
int getLevel();
// no need for setter? (addExperience method available to adjust level)
int getLevelUpExperience(); // returns required exp to level up (at current level)
// *** biz-logic ***
void reset(); // resets everything to be prepared for new game. Or "init"
boolean addExperience(int addExp); // returns true upon levelling up
}View:
I prefer to couple my views tightly with models, so the init/update methods take reference to actual model class (ie. View has to import Model).
It's not storing the model reference, only using it's API to init/update it's current state and forgetting about it, so you can any time change the View to display current state of different instance of model.
With the above model, and intent to have special effect for "level up" event, I would probably design API as:
void update(final LevelUpModel model, final boolean leveledUp) { ... }Which would use getters to set up the exp bar, exp number display, level number display, set up correct colours based on those, and finally to start some effect when
leveledUp would be true (having that "effect" as an stand-alone app entity, capable to handle it's own life cycle, like some animation of fire works or sound player playing ding once).In case of some more complex level-up effect I would consider either making state of it part of original model, or having separate LevelUpEffectModel to hold state of effect, with it's own view and controller.
Controller:
Finally controller is the glue of view and model, but should not contain any biz-logic, or low-level view updating commands.
So in this example it would do probably things like:
- contains the LevelUpModel instance, and View instance. Either receives it from global app initializer (such design can be seen as "dependency injection", helping with unit testing), or creates the instances in it's own init().
- calls reset/init upon them at the beginning (in
Controller.init(model, view)?)
- gives an on-button-click handler to View
- the on-click handler will do
model.addExperience(some_value), andview.update(model, true/false)(in more complex multi-threaded app it may also resolve any race conditions, in case model itself is not thread-safe designed).
- probably that's all?
So things like
setIcon belongs to View.update, ++exp; belong to Model.addExperience, poking model/view in reaction to the click event belongs to Controller (although it shouldn't contain the logic itself, ie deciding whether level up happened or not, that's responsibility of Model).Model contains every important state of the world, so the view can be reconstructed out of it (above I'm breaking it a bit by that "leveledUp" value, writing it now, I would probably move it inside Model, and create one more getter
boolean didLevelUp(); being updated by last addExp call) - from scratch.View contains everything what is displayed, for example it contains the string representation of experience (Model doesn't have to, as it can be constructed from the
int in Model, by "formatter" in View). And also contains logic, how to display it.Controller should only "connect the dots" and control the execution flow, when what should be called/updated.
The Model/View relation - how I like it - can be demonstrated on this classic:
Consider having blog application, so for each article you have date+time of publishing the article.
Then Model should contain UTC timestamp value (can be unix timestamp, if you need only dates since 1970 onward).
And View will do all the formatting magic, ie showing "5 seconds ago" for fresh article, or "previous millennium" for some really old article, also converting the date/time to local time zone of user (source data stored on server being in UTC, time zone agnostic).
Usually when you can UnitTest all model API easily in pure JUnit (without mocking JApplet environment or providing fake UI/display), you are on the right track. There's sometimes need to provide some complex
Code Snippets
public interface LevelUpModel {
// it's actually quite rare for model class
// to extend some non-model/non-trivial class
// *** getters/setters ***
int getExperience();
// no need for setter? (addExperience method available to adjust exp)
int getLevel();
// no need for setter? (addExperience method available to adjust level)
int getLevelUpExperience(); // returns required exp to level up (at current level)
// *** biz-logic ***
void reset(); // resets everything to be prepared for new game. Or "init"
boolean addExperience(int addExp); // returns true upon levelling up
}Context
StackExchange Code Review Q#140605, answer score: 4
Revisions (0)
No revisions yet.