So I'm making a simple pause function in my game, and I want to have a grey transparent background, the problem is, the rectangle keeps overlapping and is just causing a fade out look. I've tried g2.dispose, and it works, but I can't draw anything else over that.
I have my render method, which is being called 60 times a second. (I issume the rectangle is being drawn 60 times a second)
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
}
Thanks!
Edit: I feel like an idiot... I just had to draw my ingame screen underneath that!
If I understand correctly what you mean by "causing a fade out look" (although I'm not sure I do), you want to fill a background with a transparent color without blending the new transparent color with pixels that are already present. You can do this by setting the composite mode to "source":
g2.setComposite(AlphaComposite.Src);
You can set it back to the default "source over destination" rule to return to normal drawing afterwards by doing:
g2.setComposite(AlphaComposite.SrcOver);
Edit: Or perhaps you do want to blend the transparent color, but with the rest of the game graphics and not with itself? In that case, just make sure that you're redrawing the game background each time you draw the transparency over the top, although I'd suggest pausing the 60fps refresh during game pause if nothing on the screen is changing, just to avoid wasting CPU/battery.
Consider trying to create a copy of the Graphics context first and then disposing of it when your finished...
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
g2.dispose();
}
This way, the changes to the Graphics state remain isolated between the create and dispose calls and don't affect anything else painted after it
Also, remember, unless you are clearing what was previously painted to the Graphics context, it will accumulate on repeated calls.
Related
I'm making a game in which there will be red and blue Shapes moving around on screen. I've looked high and low for how to make anywhere they overlap a different color (purple). I am only using Java2D, which to my understanding does not support Shaders. I looked into drawing the red shapes to one BufferedImage and the blue shapes to another, then trying to use AlphaComposite to combine the colors and draw it to the screen, but it never produced correct results. I'm using 127,0,0 and 0,0,127 for red and blue instead of 255 because 255,0,255 looks, in my opinion, terrible for purple. I would effectively like this.
Thanks to copeg's suggestion, I was able to figure it out. Here is the code segment (Context: the shapes I'm drawing are attacks):
//Attacks
BufferedImage attackImg = new BufferedImage(S_WIDTH, S_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D ag = (Graphics2D) attackImg.getGraphics();
//Make all of attackImg a transparent image
ag.setComposite(AlphaComposite.Clear);
ag.fillRect(0, 0, S_WIDTH, S_HEIGHT);
ag.setComposite(AlphaComposite.SrcOver);
//Render red attacks to attackImg
ag.setColor(new Color(127, 0, 0, 255));
for(Shape s : redAttacks)
ag.fill(s);
//Render overlap areas using composites to attackImg
ag.setColor(new Color(127, 0, 127, 255));
ag.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN));
g.setColor(new Color(0, 0, 127, 255));
for(Shape s : blueAttacks)
{
ag.fill(s);
g.fill(s); //Render blue attacks
}
//Render red and purple attacks
g.drawImage(attackImg, 0, 0, null);
in my application I have a cross road picture in the background and I want to draw traffic lights on the top of it (black rectangle with 3 circles)
The problem is, I cannot see the rectangle at all, as if it was under the image or something. And if I switch the order in which the items are painted, I get all black image.
Do you have any idea how this can be solved?I am new to graphics and searched similar questions, but none helped me.
Thank you.
public MainFrame() throws HeadlessException {
super("semafor");
crossroad = new ImageIcon("cross.png");
initFrame();
initComponents();
sem1 = new Semafor(true, 100, 100);
add(sem1);
repaint();
setVisible(true);
}
//here I paint the image
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(crossroad.getImage(), 0, 45, this);
}
//and in class Semafor i paint the actual traffic lights
#Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.darkGray);
//and then the circles
}
The first thing I'm noticing is that you are calling <unknown>.getWidth() and <unknown>.getHeight() for the rectangle size. If it's covering the entire image, this suggests that it is getting that width and height from the panel it is being drawn on.
A simple stack trace,
(new Exception).printStackTrace();
or
Thread.dumpStack();
will tell you as much. You could also query the width and height with a System.out call to verify that you're getting the values you're expecting, or, if this really gets out of control, learn to use JUnit and the assert statement. Honestly, though, it looks like you're just accidentally calling the wrong method.
I have coded a simple Java game where there are two rectangles on the screen, one of the rectangles moves and the other stays still, the moving Rectangle moves with keyboard arrow input and can move either up, down, left or right. The problem I am having is drawing my rectangles on the screen, I mean I have the 2 rectangles set up with my variables as shown:
Rectangle rectOne = new Rectangle(shiftX, shiftY,90,90);
Rectangle rectTwo = new Rectangle(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
I have made a render method to draw the things on the screen which I want shown:
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
}
The problem I am having is showing my rectangles on the screen by writing the code in the render method, I could do the following:
g.fillRect(x, y,90,90);
g.fillRect(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);
Which makes 2 rectangles on the screen but I need the rectangles to be drawn using the Rectangle code written with the variables, I have been told this can be done using Graphics2D but I am wondering if there is a simpler way of just using the graphics function, if not could you please help me set this up?
Thank you in advance.
You can access attributes of the Rectangle instances easily:
g.fillRect(rectOne.getX(), rectOne.getY(), rectOne.getWidth(), rectOne.getHeight());
In any case mind that usually the Graphics object is a Graphics2D instance at runtime so this could work easily too:
Graphics2D g2d = (Graphics2D)g;
g2d.fill(rectOne);
Just use:
g.fillRect(myRect.getX(), myRect.getY(), myRect.getWidth(), myRect.getHeight());
where myRect is the rectangle you want to draw. You could even make a custom method drawRect(Graphics g, Rectangle myRect); if you have lots of rectangles to draw.
Using Graphics2D is not that difficult as well, as the provide Graphics object normally is a Graphics2D object:
Graphics2D g2d = (Graphics2D) g;
g2d.fill(myRect);
I am trying to rotate a player to follow the mouse. To do this I use a Graphics obj casted to a Graphics2D object and use the rotate method. Here is my Panel draw:
public void paint(Graphics g){
g.setColor(Color.white);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
player.draw(g);
enemy.draw(g);
mouseSelection.draw(g);
wallBoard.draw(g);
//draw the existing walls
for(Wall w : walls)
w.draw(g);
//draw the potential wall
potentialWall.draw(g);
//draw the lineWalls
for(Wall w : lineWalls)
w.draw(g);
}
All my rotation stuff is happening in player.draw(g), but I figured it would be better to have more information than less. Here is my player.draw(g)
public void draw(Graphics g){
//draw the player as a circle for now
g.setColor(Color.black);
Graphics2D g2d = (Graphics2D)g;
g2d.drawOval(getX(), getY(), 20, 20);
sword.draw(g2d);
g2d.rotate(rotation);
g2d.rotate(0);
}
I have tried many combinations of the g2d.rotate and drawing the shapes. Any advice as how i can rotate the player and the sword, but not the entire world itself?
I would try drawing your player to its own image (with its own graphics object), rotating THAT image, and then drawing that image on your main graphics.
You'll run into some potentially annoying hurdles to get across, like transparency on the temporary image, but they aren't anything that can't be gotten around with a little blood sweat and tears.
I created an ARGB BufferedImage. Now I'd like to reinitialize it with a transparent background. I tried the following code:
(...)
if( this.offscreen==null ||
this.offscreen.getWidth()!= dim.width ||
this.offscreen.getHeight()!= dim.height )
{
this.offscreen=new BufferedImage(
dim.width,
dim.height,
BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g=this.offscreen.createGraphics();
g.setColor(new Color(255,255,255,0));
g.clearRect(0, 0, dim.width, dim.height);
(...)
but it didn't work.
Any idea on how to do this please ?
Thanks !
g.clearRect(..) fills the selected rectangle with the background colour of the Graphics2D object. You're better off doing g.fillRect(..) which would give the intended result with your code, or set the background colour of the Graphics2D object beforehand (g.setBackground(..)).
Also, you may have to do g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); before the fill so that it sets the buffer properly (ignore destination buffer data, only use source data -- in this case, the fill operation). Not sure what the default is for this value, but you should set it back to that afterwards to ensure proper operation.
I had this problem before and I solved it with a really narrow trick.
Here is the deal:
In the constructor of the paint Class take a screen shot of the System but be careful
BufferedImage image = new Robot().createScreenCapture(new Rectangle(0, 23, xScreen, yScreen));
And where you want to clear the screen
g2D.drawImage(image, null, /*your Image observer*/);