I'm making a Java shoot em up game for Android phones. I've got 20 odd enemies in the game that each have a few unique behaviors but certain behaviors are reused by most of them. I need to model bullets, explosions, asteroids etc. and other things that all act a bit like enemies too. My current design favors composition over inheritance and represents game objects a bit like this:
// Generic game object
class Entity
{
// Current position
Vector2d position;
// Regular frame updates behaviour
Behaviour updateBehaviour;
// Collision behaviour
Behaviour collideBehaviour;
// What the entity looks like
Image image;
// How to display the entity
Renderer renderer;
// If the entity is dead and should be deleted
int dead;
}
abstract class Renderer { abstract void draw(Canvas c); }
abstract class Behaviour { abstract void update(Entity e); }
To just draw whatever is stored as the entity image, you can attach a simple renderer e.g.
class SimpleRenderer extends Renderer
{
void draw(Canvas c)
{
// just draw the image
}
}
To make the entity fly about randomly each frame, just attach a behavior like this:
class RandomlyMoveBehaviour extends Behaviour
{
void update(Entity e)
{
// Add random direction vector to e.position
}
}
Or add more complex behaviour like waiting until the player is close before homing in:
class SleepAndHomeBehaviour extends Behaviour
{
Entity target;
boolean homing;
void init(Entity t) { target = t; }
void update(Entity e)
{
if (/* distance between t and e < 50 pixels */)
{
homing = true;
// move towards t...
}
else
{
homing = false;
}
}
}
I'm really happy with this design so far. It's nice and flexible in that you can e.g. modularize the latter class so you could supply the "sleep" behavior and the "awake" behavior so you could say something like new WaitUntilCloseBehaviour(player, 50/pixels/, new MoveRandomlyBehaviour(), new HomingBehaviour()). This makes it really easy to make new enemies.
The only part that's bothering me is how the behaviors and the renderers communicate. At the moment, Entity contains an Image object that a Behaviour could modify if it chose to do so. For example, one behavior could change the object between a sleep and awake image and the renderer would just draw the image. I'm not sure how this is going to scale though e.g.:
What about a turret-like enemy that faces a certain direction? I guess I could add a rotation field to Entity that Behavior and Renderer can both modify/read.
What about a tank where the body of the tank and the gun of the tank have separate directions? Now the renderer needs access to two rotations from somewhere and the two images to use. You don't really want to bloat the Entity class with this if there is only one tank.
What about an enemy that glows as his gun recharges? You'd really want to store the recharge time in the Behaviour object, but then the Renderer class cannot see it.
I'm having trouble thinking of ways to model the above so the renderers and the behaviors can be kept somewhat separate. The best approach I can think of is to have the behavior objects contain the extra state and the renderer object then the behavior objects call the renderers draw method and pass on the extra state (e.g. rotation) if they want to.
You could then e.g. have a tank-like Behaviour object that wants a tank-like Renderer where the latter asks for the two images and two rotations to draw with. If you wanted your tank to just be a plain image, you would just write a subclass Renderer that ignored the rotations.
Can anyone think of any alternatives? I really want simplicity. As it's a game, efficiency may be a concern as well if e.g. drawing a single 5x5 enemy image, when I have 50 enemies flying around at 60fps, involves many layers of function calls.
The composition design is a valid one, as it allow to mix-and-match the behaviour(s) and render.
In the game we're toying with, we've added a "databag" that contains basic informations (in your case the position and the dead/alive status), and variables datas that are set/unset by the behaviour and collision subsytem. The renderer can then use these data (or not if not needed). This work well, and allows for neat effect, such as setting a "target" for a given graphical effect.
A few problems :
if the Renderer ask for data that the behaviour did not set. In our case, the event is logged, and default values (defined in renderer) is used.
It's a little bit harder to check for the needed informations beforehand (ie what data should be in the databag for the Renderer A ? what data are set by the Behaviour B ?). We try to keep the doc up-to-date, but we're thinking of recording the set/get by the classes, and generate a doc page...
Currently we're using a HashMap for the databag, but this is on a PC, not an IPhone. I don't know if perfomance will be enough, in which case another struct could be better.
Also in our case, we've decided for a set of specialized renderer. For example, if the entity possess a non void shield data, the ShieldRenderer display the representation... In your case, the tank could possess two renderer linked to two (initialization-defined) datas :
Renderer renderer1 = new RotatedImage("Tank.png", "TankRotation");
Renderer enderer2 = new RotatedImage("Turret.png", "TurretRotation");
with "TankRotation" and "TurretRotation" set by the behaviour. and the renderer simply rotating the image before displaying it at the position.
image.rotate (entity.databag.getData(variable));
Hope this help
Regards
Guillaume
The design you're going with looks good to me. This chapter on components may help you.
Related
I have a problem keeping my code maintainable.
In my problem I have defined a 'RenderableShape' that is the parent interface of both 2D and 3D shapes (those two are interfaces).
I have a Renderer class that 'asks' a RenderableShape for the data to render.
A 3D shape should return some mathematical formula or object wrapped around that and a 2D shape returns all its 2D shapes it consists of (triangles, circles etc.).
Obviously 'RenderableShape' cannot return both types two the renderer.
I could make two different methods, but that would force all implementations to implement a useless method.
The renderer can also ask for the shape what kind it is, but you would need a cast afterwards, which should not only be unnecessary, but would also be too slow to use in rendering.
Furthermore, the rendering code should not be in shapes themselves, since I would like to have all rendering code in a renderer, to allow for different renderer types (Z-Buffer, raytracer etc.)
What would be a maintainable and preverably efficient approach to this problem?
What would be a maintainable and preverably efficient approach to this problem?
One of the OOP principles which should be applied here is tell, don't ask!
Pass the renderer to the RenderableShape and have it draw itself to the renderer.
First of all, you should not even think about "removing" a method from an interface. If you can call foo() on the super class, the Liskov substitution principle states that you need that foo() must exist on the derived classes, too. Anything else is a clear violation of how OOP is supposed to work.
So, you should follow the answer that was already given. Don't ask a shape for something that tells the renderer what to do - but instead enable each shape to render itself (by passing the renderer to the shape).
Try to decompose your task further, what is shapes? it is set of curves and lines in certain positions
of display. How about to make something like simple api to do that? Make render to write lines, curves,
dots, etc.
interface Render {
renderLine(Formula formula);
renderCurve(Formula formula);
renderDot(Formula formula);
}
after that create Shape that get Render instance and write himself through this api.
Shape knows all about what amount of dots, lines etc. need to write himself. Formula is interface that
present mathematic formula. When you need more complex objects further make Render to render
simple triangles, squares, etc.
I just started to write the game of snakes in java. (See this if you don't know what that is: http://codeincomplete.com/projects/snakes/ or http://elgoog.im/snake/). So, when the snake eats an object, its tail grows. In order for the turning physics of the game to work properly, each segment of the tail needs to have its own java.awt.Rectangle hitbox. My question is how can I link these hitboxes/segments of his tail so they always stay together, but are seperate components on my JPanel. Otherwise, if there is a better way to do this then let me know. Thanks.
There s should be a snake object, with a ordered set of simple snake piece, each piece showing type. Practice model view controller, each Snake piece should know nothing about graphics. When you at a segment, put by the last noon trail piece. So, your Snake would contain a list of pieces, like this:
List<SnakePieces> mPieces
SnakePieces should be simple, something like this
public class SnakePieces {
public enum Type {Head,Body,Tail};
public Type type;
}
Feel free to add other functions to SnakePieces as required. When you add a new piece, add it at the location
mSnakePieces.add(mSnakePieces.length()-1,newSnakePiece);
If you can, separate out the model (Snake movement), the view (Puts in the graphics for the piece depending on the type of SnakePiece), and the Controller (Feeds the inputs to the model). That's more advanced than required, but helpful. See Wikipedia on Model View Controller.
Also, see the Android Snake Game, which no doubt has some similarities to your application. Android does it via this:
/**
* mSnakeTrail: a list of Coordinates that make up the snake's body
* mAppleList: the secret location of the juicy apples the snake craves.
*/
private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();
It just knows to draw the first and last tiles slightly differently.
I'm in the process of creating a agent bases modelling program. So far I have the relavent classes to model a simulator, grid, different agents etc. I've also created a 2D array of object e.g. agents moving around the array doing whatever.
I am familary with creating simple GUI's but how do I come about creating a pane\panel which then is added to the GUI. which shows the 2D array on run time with each object with its corresponding colour. Also I want to try and use the MVC pattern to basically display the simulation data differently. Such as one pane shows the different objects colour and another pane showing the same objects but every objects angry levels with different shades of red. Any guidelines would be really helpful also similar tutorials.
Thanks
I'd create a queue (JMS for a very big list of agents, but there are some in-memory queue implementations that are faster to use) and would allow all your agents to write their states in there. Then in another side, I'd write a consumer that listens to the queue to get these states to be processed by your GUI as they're coming.
If there are too many events, you may want to process them in batches, periodically, according to some refresh rate that makes sense for you.
You could use a GUI API like awt and swing (look e.g. at Java 2D game graphics), to create a canvas, upon which you would draw a representation of your system. For example, a set of circles and edges, if the circle is filled, there is an agent there, you can hover mouse over it and or click on it and another panel shows some relevant properties of the agent. Maybe an arrow from a filled circle indicates where the agent is going to go next.
You can instantiate a canvas (like java.awt.canvas), it fits into your GUI as any other widget (panel combo box etc) does it has a size you can add scrollbars etc. As opposed to other controls like combo box, a canvas is a 2d area on which you draw whatever you want.
The MVC is a design structure that separates application concerns along view, control, model axis. Whereas you could put all your control logic such as user input handling, database connection handling, network operations all that could be Don in one place in your canvas class event handling methods, in MVC you would separate all control logic from canvas, canvas event handler would just call the apprpriate controller method (such as handleNewFile). In turn the controller queries the model and tells the view what to show (for instance it loops over all agents in your model and "adds" an agent to the view. The view is where you decide how to represent the agent the controller nothing about representation.
One of the easier ways to go is to create a new Class that extends javax.swing.panel and override the paintComponent()-method.
In the constructor of the new class pass a reference to your 2D-Array.
In your overriden paintComponent()-method do something like this:
public void paintComponent(Graphics g) {
for (int x=0;x<arrayWidth;x++) {
for (int y=0;y<arrayHight;y++) {
switch (array[x][y]) {
case 1: g.setColor(Color.RED);break;
case 2: g.setColor(Color.BLUE);break;
case 3: g.setColor(Color.GREEN);break;
case 4: g.setColor(Color.YELLOW);break;
}
g.drawRect(x*10,y*10,10,10);
}
}
}
Just fit the numbers and colors to your needs.
Edit: if you have some kind of values that can't be used in a switch statement (like e.g. custom classes or Strings in older Java-versions) just replace it with if/elseifs:
public void paintComponent(Graphics g) {
for (int x=0;x<arrayWidth;x++) {
for (int y=0;y<arrayHight;y++) {
if (array[x][y].equals(value1)) {
g.setColor(Color.RED);
} else if (array[x][y].equals(value2)) {
g.setColor(Color.BLUE);
} else if (array[x][y].equals(value3)) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.YELLOW);
}
g.drawRect(x*10,y*10,10,10);
}
}
}
Currently I am having static reference to all my sprites and loading and initializing them in my OnCreateResource mthod of SimpleBaseGameActivity, But now I have to override onAreaTouched listener on spirtes and the way I can override it while Initializing the Sprite. But I have a static method creating Atlas and Texture Region for every sprite. And I am using these sprites in my scene class and I want to override onAreaTouched there. I can registerTouchArea for that specific sprite in my scene so that can be done But I want to Override OnAreaTouched in a way so that Code reusability can be done.
Here is how I am currently creating and loading sprites.
defualtCageSprite = createAndLoadSimpleSprite("bg.png", this, 450, 444);
And this is my Method createAndLoadSimpleSprite.
public static Sprite createAndLoadSimpleSprite(String name,
SimpleBaseGameActivity activity, int width, int height) {
BitmapTextureAtlas atlasForBGSprite = new BitmapTextureAtlas(
activity.getTextureManager(), width, height);
TextureRegion backgroundSpriteTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(atlasForBGSprite, activity, name, 0, 0);
Sprite sprite = new Sprite(0, 0, backgroundSpriteTextureRegion,
activity.getVertexBufferObjectManager());
activity.getTextureManager().loadTexture(atlasForBGSprite);
return sprite;
}
Now How Can I override onAreaTouched for some sprites while not losing the code reusability.
Is there any reason you need to load the textures at runtime? The normal way is to load the required textures all onto a single atlas while loading the application so that you can then quickly use them later.
As for the code reusability, Todilo's idea about enums seems to be pretty much what you need. Say for example that you have two kinds of objects - objects that disappear when you touch them and objects that fly up when you touch them. You enumerate both categories and put a piece of code into the touch event handling code that checks whether the object should disappear or fly up.
If you don't know what the objects should be doing on touch before running the application, there is a more dynamic way of achieving the same result. Just create two lists at runtime and put a reference to the object in one of the lists according to what the object should do when touched. Then in touch event handling do something like this:
if (disappearList.contains(touchedObject)) {
disappear(object)
}
if (flyUpList.contains(touchedObject)) {
flyUp(object)
}
Too bad AndEngine does not allow users to set listeners on sprites, it would make things a bit easier.
EDIT:
Added explanation of the use of BlackPawnTextureBuilder:
Your Atlas must be of type BuildableBitmapTextureAtlas, then you add all textures like this
BitmapTextureAtlasTextureRegionFactory.createFromAsset(buildableAtlas, this, "image.png"));
and after that
try {
this.buildableAtlas.build(new BlackPawnTextureBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(1));
} catch (final TextureAtlasSourcePackingException e) {
Debug.e(e);
}
I don't know whether this will work for animated Sprites or not, you will have to try it.
Also, there is no overriding onTouch, you will have to do that in the onAreaTouched method. One example of such condition is
if (pSceneMotionEvent.getAction() == MotionEvent.ACTION_DOWN && disappearList.contains(pTouchArea)) {disappear();}
Are you sure you dont want more functionality than override ontouch? How about creating a class inheriting for sprite for those that need onarea to be overriden and all other needs.
I have to use a GUI Element that draws a picture at a specific screen position.
If the user selects this picture there is a border drawn around the Image.
Now we want to include another border that identifies pictures with a specific value for the user.
At the moment the Element looks at his internal state if it is selected and then decides how to draw itself.
graphic.drawImage(icon, x, y, null);
if (selected) {
drawBorder();
}
I don't like the idea of adding another if else to this drawing method.
I thought about creating a new class that inherits the behavior of the element and overwrites the draw method but that means duplicating the whole selected code in every inherited class.
Is there a nice possibility so solve this problem without creating a subclass?
Since you tagged this with design-patterns and you seem to be looking for a pattern-oriented approach, I'd suggest taking a look at the state pattern. The example on the wikipedia page even mentions keeping state while drawing a GUI. Unfortunately, this would mean you'd have to create another class with subclasses and overridden methods.
Is this going to be something that is likely to change? I.e. do you realistically think you're going to be adding new behavior to the drawing (e.g. if the user double clicks, draw a different type of border; if the user right clicks, change the color of the border), or is this it? If you see more behavior being added, I think going ahead and taking a more OO approach is wise. If it's just these two cases, I'd say just add and else if statement.
What do you have against if-else?
It makes less sense to me to create a whole new object for the selected item than to check a flag in the drawing function.
one possibility is to allow your drawBorder() method to take parameters:
private void drawBorder(boolean isSelected, boolean hasSpecialValue);
this method can determine which type of border to draw.