When to use actors in libgdx? What are cons and pros? - java

I'm writing simple solar system simulator.
This is my first libgdx project. I'm using a Stage and Actors for the main menu and is pretty handy especially touch events handling. But ... looking at the examples i see nobody uses actors in actual game logic. I wander if i should use actor as a parent of planet class or just write my own class tor that.
The planets won't be touchable and they will be moved only between the frames so the third parameter of action MoveBy will have to be time between frames.
That are the cons. What are the pros for using Actors?

The main pros for Actors are Actions, Hit testing and touch events, and Groups of Actors.
Actions make quick and easy tweening if your game logic needs that.
You can call stage.hit(x, y) at any time to return the first actor that returns true to whatever hit logic you wrote for it (usually checking bounds with x, y, width, height). return this actor or null to keep iterating through the actors' hit methods looking for a hit actor. Null is returned if no actor is hit.
Hit is used for the Stage's touch events. The actor's touch methods are passed local coordinates, and the Stage handles overlapping of objects, e.g. if an actor covers another actor such that the other actor shouldn't receive touchDown, return true on the covering actor to stop the calling of touchDown on actors "beneath". This also sets 'focus' on the actor that returns true so that Actor's touchUp will be called.
You can group actors together to perform Actions, touch events, etc on the entire Group of Actors as a single unit.
Some Cons:
Actors require a stage which limits functionality somewhat. Many coders use other logic to determine game object state, rather than the scene2d Actions (e.g. box2d). If you use Actors for game objects, you will probably want two Stages, one for ui and one for game world. If you don't use them you'll probably be using your own SpriteBatch and Camera anyway though. And keep in mind that Actors only have an abstract Draw method so you will still need to create draw logic anyway. You'll probably keep a TextureRegion or Sprite as a private field for the Actor. If you want to use your own update logic, you can override the act(float delta) method to get the delta time (call super.act(delta) if you use Actions).
So if you have your own logic and won't use much of what Stage has to offer, save some resources and roll your own application-specific solution. If you can use some of the pros without limiting needed functionality then go for a second Stage for the game logic.

Related

how to seperate view and model in java game?

I am making a game in java using the MVC design pattern (with swing) and I do not know how to make the Controller class separate from the view Class.
until now I have a model that contains all the data, a controller which in charge of all the logic and now I think about how to separate the view.
I have the GameView which extends the Jpanel and has a paintComonent:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
draw(g2D);
}
public void draw(Graphics2D g2D){
drawComponent(background, g2D);
drawComponent(arenaController.getArena().getPlane(), g2D);
drawComponent(arenaController.getArena().getPlayer().getBoat(), g2D);
ArrayList<PlaneDrop> planeDrops = arenaController.getArena().getPlaneDrops();
for(PlaneDrop planeDrop : planeDrops){
drawComponent(planeDrop, g2D);
}
g2D.drawString("Life: " + arenaController.getArena().getPlayer().getLife(), 10, 30);
g2D.drawString("Score: " + arenaController.getArena().getPlayer().getScore(), GAME_WIDTH - 50, 30);
}
but on the other hand, I have the GameEngine which in charge of the configuration and run
#Override
public void run() {
arenaController.init();
long waitTime = 0;
Graphics g = this.getGraphics();
gameViewer.paintComponent(g);
while(arenaController.isRunning()){
long startTime = System.currentTimeMillis();
gameViewer.paintComponent(g);
update(); // update game
gameViewer.repaint();
long endTime = System.currentTimeMillis() - startTime;
waitTime = (MILLISECOND / FPS) - endTime / MILLISECOND;
try{
Thread.sleep(waitTime);
} catch (Exception e){}
}
}
the run() method in the engine invokes the paintComponent() method of the view (which for me sounds like the controller --> invokes the viewer) but I find it is not the best way to do that and it is not recommended to invoke the paintComponent() directly.
So I want a clear separation of the controller and the view but I having trouble finding the appropriate way to do that.
Okay, so you're running into a series of problems.
First
Swing is already a MVC
Second
The form of "MVC" which is taught and discussed today isn't actually how the original intent of MVC was meant to be used. It was considered more of guide line or recommendation than a stead fast rule or paradigm.
The problem is, you end up with "purests" who insist on an absolute separation of all models, controllers and views, in some cases, to the detriment of the API or solution (this when you end up with "massive view controller" problems).
Why? Consider a button. It's a view, it has a model and it can act as a controller.
You don't need a seperate "controller" to control the button. It can register the keyboard and mouse actions it needs to monitor with the underlying system. It can coordinate changes between the model and itself (the view) and it becomes a self contained unit of work.
Seriously, could you imagine having to create a seperate controller every time you created a button or any other UI component ... 😱😓
When you add the button to another container (view), the button is acting as it's own view/controller. The parent container may then have a larger model and a number of sub views which it is "controlling" or coordinating.
The container may also be controlled via an external controller which is acting to coordinate the changes between the container and the large model, allowing it to be decoupled, but in this case, I would design it in such away so that the implementation logic was decoupled, so that the outter controller didn't care about "how" stuff got done, just that there was a contract in place to allow of the passage of information between these layers.
So, what's the point?
Don't get hung up on trying to produce a "clean" MVC, especially in Swing, you're going to be tearing your hear out.
Also remember, you can have a controller talk to another controller, this allows it to disseminate information where sub controllers don't need or want all the information which might be available to the parent controller. It also allows it to control distinctly different controllers, allowing for a greater decoupling of elements and a nice plug and play approach.
So, how does this help you?
This should provide you with some places to jump off from.
If you don't want the GameEngine to talk directly to the view, you could establish a "rendering" controller. Who's responsibility would be to coordinate changes made by the game engine to the model with the underlying view (ie, schedule a rendering pass).
This would allow the GameEngine to "control" one or more "rendering" controllers and allow for a separation in how the underlying rendering is actual done from the GameEngine
You can do this because a controller can be responsible for other controllers - it's just a coordinator between the model and the next layer (typically a view)
In this example, you could change the rendering system simply by changing the implementation of the "rendering" controller (and if you're using interfaces, this becomes much simpler) without effecting the GameEngie, which, at the end of the day is the benefit of following this type of design - separation of responsibility through de-coupling.
Passing thoughts...
Don't, ever, call paintComponent directly. There is a reason why it's protected
Don't use getGraphics. This isn't how custom painting is done in Swing. getGraphics is at best just a snapshot of the last paint pass made by Swing. Remember, in Swing, you don't control the painting process, this is taken care of for you, instead, you schedule a paint pass (ie repaint) and let the system take care of the reset
If you want/need control over the painting process, then you need to use a java.awt.Canvas and a BufferStrategy instead.
Solution:
A good way to split data and logic in a Game is using an Entity Component System.
LibGDX's Ashley is what I use.
These Systems help keeping even the largest games relatively clean and understandable.
However there is some initial work required, so for small games you might just be better off with mixing logic and data in classes like Player or Enemy, put all instances of your Game Objects into a List and have a Canvas that paints them all ordered by their Z-Index.
Brief explanation of an Entity Component System:
In an Entity Component System you Entities as your Game Objects. These Entites are like empty objects, but with the capability to take posess an indefinite amout of Components (one per Component Type). These Components give the Entity the ability to be something (like extending an Class, but not limited to one).
So if your Entity has a TextureComponent it is displayable, but without giving it a TransformComponent it cannot yet be drawn at a specific location. If you now also give it a BodyComponent it can have a physical body in your world and can be pushed around. The TransformComponent will be updated everytime the Body is moved.
All the Logic is performed by Systems. The process all Entites with specific Component Types.
A self drawn visualization (I apologize for the looks, I'm not an artist):

LibGDX Stage vs SpriteBatch to draw the Game

I have a big problem with the drawing in LibGDX. First I don´t use every physics or other complicate things in my game. I only draw sprites and put Rectangles at this for Collision Detection. I have 3 Screens in my game: splash, menu and game. So I use a Stage in the splash and menu screen but I don´t really if I use Stage in the game too or I draw with SpriteBatch? The Stage have really pros with Actions but it a little bit more complicate to use Actors. Are there other ways to do this? I don´t want to use World, because its to complicate for the beginning of game developing.
What I want to use for the game?
Actually you always draw with SpriteBatch, as Stage uses its own SpriteBatch. If you think you could need some of the advantages of Scene2ds Stage, like Actions, Groups or other things, you should use Stage. In my opinion it is really easy to use. You have your own objects, which extend Image or Actor, override their update(delta) methods, where you check if the Actor should move (Keypressed or an event for the AI). Also you should detect collisions there and take care about them. Then, if you are extending Image you don't need to care about drawing (but Image needs Drawables so you will have some problems with Animations), if you are extending Actor override the draw(SpriteBatch batch), where you call batch.draw(...).
Thats it.
A big disadvantage of Stage is the sorting. The Actor, which is drawn as first is in the background. The last Actor overdraws all others and is in foreground. You can sort them by using the z-Index, but it is not really sure.
So you may decide to use your own kind of Stage (it is more or less a list, containing all Actors, and when updateor draw is called, it is called for every Actor in this list), and add your own sorting there.
It depends on your game design, on your opinion and on your style. Look at some tutorials/examples and decide how you want to create your game.
You can use either, it depends on what kind of game are you creating. But anyway, don't create multiple instances of SpriteBatch — instead create only one and pass it to Stage constructor, because it's heavy object. (Yes, Stage uses a SpriteBatch under the hood)
Also, Stage may be extremely useful if you need any on-screen controls (buttons, joystick, etc), because you can use classes from scene2d.ui and don't reinvent the wheel (some wheels are not very easy to reinvent properly)

Scene2d suitable for non-UI display?

I'm using LibGDX (and subsequently Scene2d) to develop a sidescroller game. I know there's a lot of user interface things built into it (buttons, text fields, labels, tables, etc.), but I was wondering, is it suitable to render my actual 2-dimensional game in Scene2d?
I like the way it handles groups and actors, but I wasn't sure if the built-in collision detection would interfere with my Box2d physics simulation.
I wouldn't use Actors to represent sprites, but rather the Sprite class, as the Actor class is more for receiving input and animating, and most your background will likely be static in a sidescroller.
Collision detection outside your Box2D simulation should be unnecessary I think. The physics engine is there to simulate collision detection and response for you.
It's a matter of taste.
Collision handling should be done by Box2D as it was already pointed out, but you might still use scene2d in combination with a custom "PhysicsActor" to bridge between the user input and the Box2D bodies.
But that's only useful if you really want to be able to click on and interact a lot with your bodies.
On the other hand you might just go with a List of custom Entities which you will update and render yourself. That's the way I preferred so far.

Click through an Actor in libGDX

I have an overlay in my game that consists of an image of a screen, and a set of buttons that are "on" the screen.
Screenshot:
My Screen has one Stage. The Stage has a set of Group objects, which I think of as layers. The first group has the backgrounds, the groups in the middle has the game elements, and the frontmost group has the screen overlay.
The overlay layer consists of one Image, the screen itself, and four TextButton (one in each corner).
This would work great, if it weren't for the fact that I can't click on anything in the game layer as long as the image in the overlay layer is in front of it. Even if the image is transparent, it still interecepts all touch events before they reach the game layer.
So my questions is: How can I make the image in the overlay layer ignore all touch events, so that the game layer will get them and one can actually play the game?
I tried one idea myself, but I'm not sure this is the right way to do it:
I tried creating the image as a custom Actor that always had height/width set to 0, but still (by overloading the draw() method) drew the image on the entire screen. This works very well, except for the fact that the image for some reason gets drawn behind elements in lower layers.
Screenshot: https://dl.dropboxusercontent.com/u/1545094/Screen2.png
In this screenshot, I have opened a instruction messagebox, which adds itself to one of the game layers (group 6).
Note that all the buttons in the overlay layer (which is group 7) is in front of the messagebox, but the screen frame (which is a custom Actor) somehow gets drawn behind the messagebox. Why is that?
Note: If I take this exact same case, and change my custom actor into a regular Image, everything is drawn correctly, but then I can't click anything in the lower layers anymore, as described above.
This is my custom actor, if anybody can make any sense of it:
public class ClickThroughImage extends Actor {
BaseDrawable d;
public NonexistingImage(BaseDrawable d){
this.d = d;
setSize(0, 0);
}
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
d.draw(batch, 0, 0, 1024, 768); //Yes, I tried swapping these two lines.
super.draw(batch, parentAlpha); //It had no effect.
}
}
In addition to the other methods note you can also call:
setTouchable(Touchable.disabled);
Which is documented as:
No touch input events will be received by the actor or any children.
Method is n the Actor class.
Use an InputMultiplexer. The InputMultiplexer class allows you to share user input among multiple input processors. Create your own class extending InputProcessor, and put that in InputMultiplexer with your Stage. That way you can respond to user input in a custom way, and still be able to use your stage.
InputMultiplexer multiplexer = new InputMultiplexer();
Array<InputProcessor> processors = new Array<InputProcessor>();
MyInputProcessor myInputProcessor = new MyInputProcessor();
processors.add(myInputProcessor);
processors.add(stage);
this.multiplex.setProcessors(processors);
//...
//and in your show method in your Screen class
Gdx.input.setInputProcessor(this.multiplex);
Also, be sure to return null from Actor.hit. This should cause the actor to not respond to any user interaction.
This is how I solved this problem in my game.
Yes, Pool is right.
Just set touchable to disabled.
It is questionable, whether it is a "good" default of the engine to make all actors touchable in a stage, because in most of my games the majority of actors is _not_ touchable, and there are only few elements the user can/shall interact with. Therefore I always create a base class of "nonTouchableActor" where I derive all my Actors from that shall not react on clicks/taps and this base class sets touchable(disabled) in the constructor. That way you no longer have to think about it.

How should objects be in a Java game

EDIT: i just deleted the entire post and reformulated the question to be more generic.
I want to do a simple strategy game: map, units.
Map: one class. Units: another class, self drawn.
Simple questions:
How does an unit should redraw itself on the map.
A unit should be a JPanel or similar Swing component (just to be able to manage them as an entity with its own mousehandlers) or can be another thing, without neglecting the fact that it should be an autonomous object with its own action handlers and fields.
Is this map-units model correct of a simple game that would help me to learn in a fun way Java and OOP fundamentals.
Thats it!
There are 2 ways.
Either have a Map class which is the main JPanel, to maintain the collection of units, but keep the Unit class as non-Swing. When the Map's paint() method is called, ask each Unit to redraw itself by calling a method in each visible Unit. The Unit could be inherited from any base class, for example Rectangle, or some other data structure you use in the program. In this case, the Unit class handles painting and calculations, but the Map handles the clicks and events for each Unit. It could pass the message on to the Unit if needed; however, if the unit itself doesn't need to know about these things, this method works well. The Unit class is light and economical. You can also decide whether the Unit knows its position in the Map or not.
Or have each unit as a JComponent, and handle its own events separately. The disadvantage is that each instance of a Unit creates a pile of data for drawing it as well. So if you have hundreds of units, only a couple of which are drawn, this way is not efficient. The advantage is each unit can handle its own GUI events without translation etc. This assumes also a 1:1 mapping of actual units in the game and graphical units on the screen. Also it is trickier to implement certain event handlers in the Unit, if a Unit needs to know about what other Units are around!
A third and arguably better way is to have a purely data Unit class, containing the game information about the unit, as in (1), but which has a method to create the JComponent when needed. The JComponent could, for example, be an inner class in the Unit - it could then access the Unit data. This is great if a unit may need to be displayed in 2 places (e.g. on 2 screens or views).
--
Addendum to address comments
That is correct, in (1) the Map (main JPanel) implements the mouse handler, and asks each unit in turn if it is 'hit'. This allows you to do more complex things, such as have 2 units overlapping/on top of each other, and both could respond to the click.
Also, for example, they may not be rectangular, or may be drawn with an alpha channel (if the Units were JComponents, they will by default grab any mouse event over their whole rectangle, to themselves). If your units don't overlap and are in their own rectangles, then JComponent's own mouse handler is enough.
If you use approach (1), the Map can ask each unit whether it contains a clicked point, and the Map can then handle the 'selection' process. Remember, a unit on its own won't be able to work out what other units are selected - selection may involve deselecting another unit. In that case, the selection operation is really a Map operation, not a Unit operation, although it may change the appearance or function of the Unit as well.
If you use separate JComponents for the Units, you can override contains(Point) to determine if the mouse hits the item, but this won't let other Units also respond to the click. But each Unit could 'select itself' (set a flag used when drawing) then notify the Map (it will need to find it using getParent or by a preset property).
Key things you need to know before deciding on this design would be:
Will you ever need more than one 'Map' panel per game?
Will you ever need more Unit objects than are to be displayed?
Will you ever need to display a Unit more than once?
If the answers are yes, you should separate the 'Data' classes from the 'View' classes, as suggested in 3.
then: What does a Unit need to 'do' and what does it need to know about the Map and other Units in order to do this? e.g. moving is usually done by the Map class in this situation, as it depends on the Map and on other Units; drawing is best done by the Unit because there may be many unit subtypes with different data structures that may need to be drawn; Unit selection operations as you have pointed out lie somewhere in between. If you see how Swing implements this (e.g. ButtonGroup, ListSelectionModel), the 'selection' itself can be though of as a separate class.
I made a peg solitaire game a few years ago which was pretty much just a JPanel that extended MouseListener and MouseMotionListener. The pegs were primitive circles drawn in the paint method, but you could track where they landed by taking the cursor position and mathematically working out the square in which it landed. That lined up with an array that stored either a 1 or 0 for each square on the board depending if anything was there. You could also drag each piece by finding the current cursor position then calling repaint() in the mouseDragged method you get from implementing MouseMotionListener.
I'd probably suggest doing it that way to begin with. Create an array of whatever size and use that to track the units. Then each time you make a move just check that array and redraw your units in the paint method. If you're using mouse movement then you can get the current position of the unit on mouseDown then do what I mentioned before with mouseDragged, and then get your final location on mouseUp and also do your calculations in regards to legal moves etc in mouseUp.
In the paint method you'll just loop over the array that defines the map and if there is a unit at the current position on the array then do something like g.fillOval(x,y,x_dimension,y_dimension). That array could just have its elements set to 0 for no unit at the current position, or 1 for a team 1 unit at the current position, 2 for team 2 etc. The paint method will take those numbers and draw pieces accordingly (change color for each type or whatever).
I hope that makes a bit of sense.

Categories