Im trying to make a turn-based game, progressing OK so far, however now I came to the part where I want to be able to move units around. I use images to determine different types of terrain, and another image to display a unit, but I can't get the unit to come out OVER the terrain, it only pops up under the terrain. Seems like I'm the first one ever to bump into this problem, so am I going at it the wrong way?
The tile with a terrain-image:
protected void paintComponent(Graphics paintIt) //paints this sexy-hex
{
super.paintComponent(paintIt); //not sure if we need this? lol
paintIt.setColor(is); //sets the color (later not even used, we need pics and shit)
//paintIt.fillPolygon(hex); //fills the hexagon with the desired color, will not be used later on either
if(isExplored)
paintIt.drawImage(image, 0, 0, null);
else
paintIt.fillPolygon(hex); // I want to paint it black
if (hoover) //are we pointing at this cell?
{
paintIt.setColor(Color.WHITE); //we want the nice line around the cell to be white
Graphics2D g2 = (Graphics2D) paintIt;
g2.setStroke(new BasicStroke(3)); //and 3 pixels wide (we are allowed to change it, supposedly in proportion to "rad"
g2.drawPolygon(hex); //draws the line around the hexagon
}
}
The unit:
protected void paintComponent(Graphics paintIt)
{
if(!selected)
{
paintIt.drawImage(image, 0, 0, null);
paintIt.drawImage(image2,0,0,null);
/*
super.paintComponent(paintIt);
paintIt.setColor(Color.BLACK);
paintIt.drawPolygon(shape); */
}
else
{
super.paintComponent(paintIt);
paintIt.setColor(Color.RED);
paintIt.drawPolygon(shape);
}
}
Sorry for the comments, and sorry for some code that's not even used, just think it's best to have it until the project's finished if we need to get back to somewhere.
The unit image is smaller than the terrain, so it fits. I've tested without painting out the terrain so I know the unit is painted under it.
If there's still code you would need to get an idea what I'm doing, tell me, just thought this was the relevant parts.
EDIT #2
The tile is a class created from another class which extends JFrame. The unit-class is created from that JFrame class but is beeing stored in the tile. Both tile and unit are JComponents.
Fix'd, I had to draw the units image within the terrain-class to make it come out on top. Since I already stored the unit in the class I don't know why I didn't do it this way from the beginning.
Thanks anyhoo <3
Related
Very simple question, but I could not find the answer in JavaFX docs or StackOverflow:
I have a JavaFX Canvas filled with a graph (various calls to strokeLine(), not the issue here). I need to be able to draw a rectangle over this graph, then simply clear the rectangle, without affecting the graph in the background. (Like an undo operation).
Code to draw the rectangle ('p' and 'e' are points):
gc.rect(p.getX(), p.getY(), e.getX()-p.getX(), e.getY()-p.getY());
gc.stroke();
The most obvious answer would be to use the clearRect() method, but the problem is that it clears also the portion of the graph in the background...
So the question is: how do I clear a drawing that was made with stroke(), without affecting the other drawings in the background?
You can't do this with one canvas.
Canvas only store the result of your painting operation.
This is the interest of the canvas you can stroke million times the same line and it will only store and represent the result and doesn't consume more memory.
So you if you need to draw Something over your chart you should put an other canvas over the chart and draw on the second canvas.
It might be more straight forward and much more the JavaFX-way of doing things if you just put your canvas into a Group and then just add a Rectangle node to the Group which you can remove at any time if you want.
This can be acheaved by taking snapshot(s) of your Canvas, using the .snapshot(SnapshotParameters params, WritableImage image) method. Basicly, every time you draw something on your Canvas, you take a snapshot of it and store it somewhere (for example in a ArrayList). Then you can use those snapshots to create a 'undo' operation, by using the . drawImage(Image img, double x, double y) method of Canvas's GraphicsContext, in which you would pass the snapshot you want to go back to as the Image parameter.
I have a quadrilateral drawn in Path2D, and I would like for there to be an image on it. More specifically, I am trying to draw an image of my choice to 4 different points on a quadrilateral. In my case, it is a parallelogram. I do not want the image to go over the paralellogram. A better way to see what I am trying to say is to see the screenshot below.
I would like the image to be transformed to fit the green area. Not clipped.
I want the image to be pinned over the green paralellogram. However. I do not want the image to go over into the blue paralellogram, or the white space foe that matter.
So far I have tried
Researching for a way to place images directly onto Path2D.Double() objects. No answer
Rotating the image to fit the paralellogram. Didnt work.
Using AffineTransform in java. Dont get it ;-;
Thanks. I am new to java so do try to be lenient?
One way is to:
create a separate BufferedImage.
Apply a transform to the new image.
Draw your image to that new image.
Use the Shape object for the green area as a clip on the main drawing area
Draw the transformed image onto the main drawing area.
It's been a while since I have done transformations. You may have to set the transformation first and then draw the image after. Transformation has to come first.
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.transform(AffineTransform.getShearInstance(1.0, 0));
g2.drawImage(image, 0, 0, this);
}
Here is a simple example of how transforms work. You will have to spend some time on figuring out what values you need to make it work or if you might need to manually create a transformation matrix yourself.
I'll start off by telling you what Im trying to do if thats OK, as Im not certain the route Im struggling with is even the best way of achieving my ends.
I have a JFrame containing two JPanels. One contains a number of buttons (buttonPanel), the other is, initially, blank (displayPane). When buttons are pressed the stuff shown in displayPanel changes. The way this is working is each press of a button creates a new object that extends JPanel and then adds that to displayPane
So all the above is working fine and dandy (although I freely admit it may not be the best way of doing it) except for one particular case.
In this particular case I need to create a JLayeredPanel and then draw a clipped image on it. JLayeredPanel because I want to draw some stuff on top of it, clipped because I only want to show part of the area (which exact part is passed to the constructor).
Now, the problem Im having is this. The only way I know to draw a clipped image is through g=thingie.getGraphics(), g.setClip(Shape shape), g.drawImage(various). However, all of that relies on being able to get graphics. But because I am assembling the object first there is no graphics object associated with the JLayeredPane (because its not displayed) so getGraphics is returning null and g.setClip() is throwing a Null Pointer Exception.
Obviously I am doing this wrong somehow and somewhere. Any help would be appreciated, sorry if the question is confusing. I tried to include as much detail as possible and now I am a little concerned I've muddied the issue. I'll keep an eye on this and clarify if required.
Warning!: Wrong answer, see below the line
Why don't you just create a new Graphics object, paint on it and then use it with the update() method?
Graphics g = new Graphics();
g.drawStuff();
thingie.update(g);
This showd be correct
As stated on the comments the previous solution was wrong but it can be done with an Double buffer, create a buffered image and draw on it, then override the paint method of the jLayeredPane pane to draw the image.
private void addStuff() {
BufferedImage bi =
new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
Graphics bufferedGraphics = bi.getGraphics();
//Paint stuff
bufferedGraphics.drawLine(0, 0, 50, 50);
javax.swing.JLayeredPane layered;
layered = new JLayeredPane() {
#Override
public void paint(Graphics g) {
g.drawImage(bi, 0, 0, null);
}
};
this.add(layered);
this.validate();
this.repaint();
}
I have image inside the JPanel. I would like to rotate the image. Is it possible to rotate the JPanel using Graphics, Image is rotatable, Just out of curiosity is it possible to rotate JPanel ?
Yes! This is possible and fairly straightforward too. I haven't done rotations but I have done other affine transformations (scaling the entire GUI up and down) very successfully on a project. I cannot see why rotations should be any different.
Instead of trying to scale each component use the fact that you can set a transformation on the Graphics object. Since this is shared between all components being rendered you get all things transformed at once "for free". It is important to realize that the transformation is only a rendering-process-step ... i.e. all components still believe they have the bounds (locations+sizes) which you gave them in the untransformed world. This leaves us with the challenge to deal with mouse-events correctly. To do this you simply add a glass-pane in front of your main-panel. This pane collects all mouse-events and apply a reverse of the transform on the event and then sends the event onward towards all other components.
Conceptually very simple! Still, I remember it took some tweaking to get it all crisp though. Especially the fact that rendered texts (fonts) in java are not correctly linearly scaled (it scales in discrete steps corresponding to font-sizes) imposed a final challenge in my scale-affine-transformation-case. Maybe you don't have to worry about that if you only rotate.
I got my inspiration from JXTransformer: http://www.java.net/blog/alexfromsun/archive/2006/07/jxtransformer_t.html
As far as I know you can't rotate a JPanel itself but you might be able to rotate the image inside the JPanel using Java2D. Here's an article that might help.
Edit:
There might actually be a way to rotate JComponents (such as JPanel) if you override their paintXxx methods and use AffineTransform.
It's not possible to rotate JPanel itself, but it's certainly possible to rotate any image inside. There are quite a few ways to do that, you can - for example - override JPanel's public void paint(Graphics g) and then cast Graphics to Graphics2D. It's very useful class, does rotation and much more ;) Check api docs for more info about this one.
Yes, it is possible. But you won't rotate the panel, but the image:
public void paintComponent(Graphics gg)
{
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTI_ALIAS, RenderingHints.VALUE_ANTI_ALIAS_ON);
AfflineTransform matrix = g.getTransform(); // Backup
float angle = Math.PI / 4.0f; // 45°
g.rotate(angle);
/* Begin */
g.drawImage(yourImage, [your coordinates], null);
/* End */
g.setTranform(matrix); // Restore
}
Everything between /* Begin */ and /* End */ will be drawn rotated.
(I didn't test the code, so, they may be some syntax errors...)
I have a JPanel which draws .png images. each image has 2 copies to signify whether or not it has been selected. One image is normal and one has a colored border to signify the selection has been made. (You can think of these images as simple shapes for the sake of argument)
Which version of the image is drawn is determined via MouseListeners. If the user selects image1, then image1 will display its highlighted version.
In general this is working, however upon repaint() the highlighted version of the image is left behind. Since the highlighted version is slightly larger than the normal version, you can see it sticking out behind the newly drawn normal image (overlapping).
I thought repaint() was supposed to completely dispose of the current drawings and start from scratch, this doesn't seem to be the case here. Below is the general idea, blackClicked is toggled inside a MouseListener.
So my question is how do I make repaint() get rid of its currently drawn images and start from scratch.
Also, if there is a simpler way to achieve all of this please let me know, making 2 copies of images is tedious work.
#Override
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if(blackClicked)
g2.drawImage(blackSelected,0, 0, null);
else
g2.drawImage(black,0, 0, null);
g2.drawImage(green,0, 0, null);
}
how do I make repaint() get rid of its currently drawn images and start from scratch.
You mean, how to make repaint fill the component with it's background color before painting? How about adding
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
in top of paintComponent()?