I am working on a game engine mostly using ECS (not pure ECS) and I've run into a problem.
Some entities will need a Bounds component (e.g. a component that has a Rectangle that represents position, width, and height). Like buttons.
Many entities also need a component that contains the position but not necessarily bounds.
How do I reconcile the overlap?
1) If an entity has both a Bounds component and a position component, there will be two positions. Not good
2) Entity only has Bounds component which inherits from position component. Ugly because I have to override the utility methods like translate from the position component and have it update the bounds object's position. Also then the entity won't have a position component, which is weird.
3) Bounds component just contains width and height. I don't like this because then I can't use things like a Rectangle class to represent the bounds.
Any ideas? Thank you.
I would go for 3, with a requirement to have a Transform component if you have a Bound component and express the bounds in local frame.
Using a Rectangle with lower-left and upper-right corners would still make sense since the origin of the bounds are not always the same as the origin of the component.
Related
I want to create a grid type layout in LibGDX that will map to a 2d array. So if a user moves an object on the grid layout, it will check the array to see if the move is legal and then move the object in the layout and grid.
The only way I currently know how to do this, would be to simply calculate the current size of the screen and divide it up accordingly, and then store those values somewhere, but this seems rather tedious. Is there a simpler way of doing so?
Thanks
Use an ExtendViewport with the virtual size of your grid to manage your camera. Then you will know that a movement of 1 equates to one grid space.
You can draw TextureRegions using widths and heights relative to this grid scale. Or if using Sprites you can set the width and height of all your Sprites relative to the grid scale when you load them.
I can't seem to move a rectangle object in JavaFX. I've placed the rectangle inside of a stackpane, but whenever I change the coordinates of the rectangle, it won't move (even if I change the coordinates of initialization). So,
Rectangle rect = new Rectangle(150,150,75,75);
will be in the center of the stackpane, as well as
Rectangle rect = new Rectangle(2043,136,75,75);
Whenever I use
rect.setX();
The rectangle doesn't move at all. I know I'm missing something really simple, I just can't figure it out. I don't want to use a transition, because my goal is to simply move the rectangle a few pixels in the direction of an arrow key press. So what exactly am I doing wrong?
Solution
Use a different container type (e.g. a Pane) if you want to manually specify layout co-ordinates (e.g. the x,y co-ordinates of a Rectangle).
Background
A StackPane is a managed layout pane - it controls the layout of the items you place in it (by default centering items in the stack). So it doesn't matter what co-ordinates you give the Rectangle, when you place it in the StackPane, the layout manager will move your rectangle so that it is in the center of the stack.
JavaFX has two concepts for positioning, one is layout co-ordinates, the other is translation deltas, which are added to the layout co-ordinates. TranslateTransitions work by modifying translation deltas. Translation is meant for animations and temporarily moving things around. Translation is independent of and does not effect layout values, so you could place something in a StackPane and apply a TranslateTransition to it and it would still move, but it would move from the center of the stack, as that is the initial layout position.
I've been looking around and i couldn't find an answer to this but what I have done is create a cube / box and the camera will squash and stretch depending on where I am looking at. This all seems to resolve it self when the screen is perfectly square but when I'm using 16:9 it stretches and squashes the shapes. Is it possible to change this?
16:9
and this is 500px X 500px
As a side question would it be possible to change the color of background "sky"?
OpenGL uses a cube [-1,1]^3 to represent the frustum in normalized device coordinates. The Viewport transform strechtes this in x and y direction to [0,width] and [0,height]. So to get the correct output aspect ratio, you have to take the viewport dimensions into account when transfroming the vertices into clip space. Usually, this is part of the projection matrix. The old fixed-function gluPerspective() function has a parameter to directly create a frustum for a given aspect ratio. As you do not show any code, it is hard to suggest what you actually should change, but it should be quite easy, as it boils down to a simple scale operation along x and y.
To the side question: That color is defined by the values the color buffer is set to when clearing the it. You can set the color via glClearColor().
I realize that there's another question relating to "infinite" JScrollPanes, however I think that what I'm looking for is something that is subtly different.
Basically, I have a collection of objects which can be dragged in any direction, and the extent of the scrolling viewport should always encompass the bounding rect of all those objects. To put it another way, the document has no fixed "origin". Thus, if you drag an object to the left, off the edge of the screen, then the viewport extent should expand in the negative direction to encompass that object's new position. (It should also auto-scroll as you drag, but that's a separate problem I realize.)
I'm not sure how to do this using the JScrollPane API, which seems to want you to set the preferred size of the underlying component, but doesn't seem to have the concept of an offset or origin for that component. (The underlying JViewport seems like it would be able to do it, but I can't really figure out the JViewport API.)
The scroll pane and view port actually have nothing to do with it. What you need to is change the preferred size of the view ports view and let the scroll pane/view port take care of this rest.
Basically, what you need to do, is calculate the widest and highest points on your component and invalidate the view port, to force to recalculate it's layout requirements.
Create yourself a custom component (using a JPanel for example) and override the getPreferredSize method. This method should return the required size of your component.
When the size requirements change, call revalidate()
OK so it turns out that the simple answer is that scroll panes cannot scroll to negative coordinates. What you have to do, as #MadProgrammer suggested, is maintain a separate offset coordinate which is a Point. The offset stores the top/left coordinates of the entire document. When rendering individual objects, set the transform of the Graphics2D object such that they are shifted down and to the right by the offset amount, so that all object are drawn at coordinates that are positive numbers even though in reality they may be located at negative coordinates. Similarly, when calculating the preferredSize for the scroll pane, add in the offset to the document width and height. Coordinates from scroll bar events also need to be offset as appropriate.
This allows you to maintain the illusion that the document bounds are not constrained to be positive numbers, and the document's boundary can expand infinitely in any direction.
How to place LayoutPanel in the middle center of parent LayoutPanel (RootLayoutPanel, screen, browser page)? Assuming the inner panel is of fixed size, outer panel is flexible and does resize (with the browser window).
In Vaadin it is one line command:
(VerticalLayout)outerPane).setComponentAlignment(innerPane,
Alignment.MIDDLE_CENTER);
What is the GWT equivalent?
The GWT Layout.Alignment enum provides only BEGIN END STRETCH.
Inadequate. Screen centered placement is essential for displaying smaller forms, dialog boxes, warning messages, login screens etc.
Details on my post on the GWT forum
Thank you
--- UPDATE (27.2.2012) ---------------
To use suggested technique - using setWidgetLeftRight() and setWidgetTopBottom() - I need to compute in fact NW position (x,y) of inner component relative to outer component and do it after every resize of outer container or inner container (content height).
So if GWT does not support centering, and it seems that even in the latest version it does not, there is more coding involved:
outerComponent.setWidgetLeftRight(innerComponent, x, PX, x, PX);
outerComponent.setWidgetTopBottom(innerComponent, y, PX, y, PX);
x,y to be computed as:
x = (w1 – w2) / 2
y = (h1 – h2) / 2
where:
w1 - outer component width (variable, easy to obtain?)
h1 - outer component height (variable, easy to obtain?)
w2 - inner centered component width (fixed)
h2 - inner centered component height (variable, depending on content, potentially tricky to obtain)
All preferably in pixels (PX?) or EM. When mixed with %, more conversion would have to take place.
With every resize event happens the coordinates has to be recalculated (w1, h1 change).
With every change of the internal content the coordinates has to be recalculated (h2 changes).
It is pretty much absolute layout (AbsolutePanel) in disguise.
CSS solution? I found several examples on this server, but none marked as solved. None with both vertical and horizontal centering and flexible inner component height.
Why I don't prefer CSS based layout solution:
Prone to cross browser issues. GWT doesn't help you here.
I consider mixing layout in code and in CSS a bad design decision. CSS is best to be left for “decorative” declarations (font sizes and colors, margins, paddings).
My own bad experience with CSS layouts; easy to break, difficult to debug, lot's of headaches before you put everything together. Best to avoid. I had great hopes towards GWT.
I am thinking about this code based solution:
new subclass of Widget? Panel? Layout? Component? (the inner component)
implement RequiresResize expect, implement onResize() callback method
obtain actual values for variable dimensions (w1, h1, h2). How?
set new coordinates for the inner component. How?
Points to anyone providing solution based on these premises :)
Well you could use a VerticalPanel and set the HorizontalAlignment field or in case you want to use LayoutPanels you can adapt the solution in the GWT docs which you posted in the google groups thread.
LayoutPanel p = new LayoutPanel();
Widget centercontent;
p.add(centercontent);
p.setWidgetLeftRight(centercontent, 5, EM, 5, EM); // Center panel
p.setWidgetTopBottom(centercontent, 5, EM, 5, EM);
This will create a a center panel with 5 em margins left, right, top and bottom like below (only the white panel in the middle will be visible). EM is a fixed size similar to pixel but depends on the base font size. If your base font size (the one defined for your body) is set to 16 px then 1 EM = 16 px (see here for conversion infos).
You could also use relative values for the margins:
p.setWidgetLeftRight(centercontent, 5, PCT, 5, PCT); //5 % left and right margin
p.setWidgetTopBottom(centercontent, 5, PCT, 5, PCT); // 5 % top and bottom margin.
However this way you wont be able to solve your problem entirely (different form sizes -> see screenshots in the google thread) because the center panel will always have fixed margins (5 EM or 5 %) independent of the vertical size of the center panel.
Furthermore the center panel's content will be clipped if it is taller than the available screen size and will be resized when you resize your browser.
So I think the better approach is to put a FlowPanel/HTMLPanel inside a LayoutPanel and apply CSS styles to allow natural resizing.
What if you added a ResizeListener to your center panel (I'm not sure this works, will try it now). Basically, whenever the window resizes, the panel centers itself (by calculating it's height relative to the height of its parent).
EDIT
I ended up getting what I wanted by letting my panel implement ResizeHandler and having the following:
#Override public void onResize(ResizeEvent event) {
// for my case, this is the first parent element with the full height.
Widget parent = getParent().getParent();
int height = parent.getOffsetHeight();
// could make this more exact by including height of this panel.
getElement().getStyle().setPaddingTop((int)((height - 80)/2), Unit.PX);
}
// my panel is not initially visible
#Override public void onAttach() {
super.onAttach();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override public void execute() {
onResize(null);
}
});
}