Java: drawing a feathered shape from an Image on Canvas - java

I'm trying to make a game (2D) where a light source is supposed to light up the surrounding area. I currently have a neon sign with some letters on it, meaning that the light source is the shape of an oval (see image). I want everything to be pitch black except the surroundings of the sign
I've currently made the following class:
public class bgReveal extends GameObject{
private Image bg;
public bgReveal(int x, int y, int radX, int radY, ID id, Image bg) {
super(x, y, id);
this.bg = bg;
this.radX = radX;
this.radY = radY;
}
public void update() {
//this and render gets called 60 times each second
}
public void render(Graphics g) {
//Here I'll draw the background using the elipse radius radX, radY to
//cut out the elipse, then feathering the image
}
}
I'll add this "GameObject" to a handler which will handle the updating and rendering of the image. Any idea on how to get this image thing working?

Related

Java on android studio, why I cant see the Rectangle i drew in canvas?

Hi guys I recently started developing an android game, but i have encountered an issue with drawRectangle.
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
canvas.drawRect(new Rect(100,100,100,100), new Paint(Color.WHITE));
}
this Doesnt seem to work, but i have already drew on screen using another class with a draw method using the same logic but im curious why this doesnt work
private Paint myPaint = new Paint();
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
myPaint.setColor(Color.WHITE);
canvas.drawRect(new Rect(100,100,100,100), myPaint);
}
this doesnt work either
There are three issues in your implementation:-
Paint object doesn't take color in constructor, it takes a flag.
So you could have done something like Paint p = new Paint(Paint.ANTI_ALIAS_FLAG) and then set the color as p.setColor(Color.WHITE).
The Rect object should be something like new Rect(0,0,100,100).
In your case [new Rect(100,100,100,100)] the rectangle will be drawn as a rectangle with 0 width,
0 height and its upper left coordinate will be (100,100) and its
bottom right coordinate will be (100,100).
NEVER create objects in onDraw.
Paint's constructor doesn't take a color. It takes integer flags. So you just made a really weird paint object with every flag set, but you didn't set the color.
See: https://developer.android.com/reference/android/graphics/Paint.html#Paint(int)
This worked
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLACK);
myPaint.setColor(Color.WHITE);
canvas.drawRect(testRect, myPaint);
}
Where
private Rect testRect = new Rect(0,0,100,100}
private Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

How to get if image is touched and not the transparent background? LIBGDX

i have a picture of a head and its on a transparent background and i want to get if the head is clicked not the area behind his head. this is what i had for the entire image not the image withing the box. pretend the grey part is the transparent part. i want nothing to happen when that area is clicked. only his body.
link to picture->link to picture
stage.addListener(new ClickListener()
{
#Override
public boolean touchDown(InputEvent event, float x, float y, int a , int b)
{
if(box.equals(stage.hit(x,y,false)))
{
box.setPosition(100, 100);
point.play();
score++;
}
return true;
}
});

Java - graphics paint

I'm trying to develop a Java brick breaker (like DxBall) game and I want to make the Ball object with its own draw method.
What I'm trying to do:
public class Ball {
private int x, y, diameter;
public void Ball(){
x = 0;
y = 0;
diameter = 20;
}
public void draw(Graphics g){
g.setPaint(Color.red);
g.fillOval(x, y, diameter, diameter);
}
}
Therefore, my game engine extends JFrame and its paintComponent method will call game objects draw method. To sum, is it proper way to do object oriented game in Java? What should my Ball class extend?
Your Ball class seems to look ok. It doesn't need to extend anything. You will need to pass the Graphics object from the paintComponent of your game object to the Ball draw method.
If you wish to make Ball a graphical component, you could extend JComponent:
public class Ball extends JComponent {
private int x;
private int y
private int diameter;
public Ball() {
x = 0;
y = 0;
diameter=20;
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setPaint(Color.red);
g.fillOval(x, y, diameter, diameter);
}
}
and simply call repaint when you wish to paint the component instead of a custom draw method.
Note: There's no return type for constructors.
Your class is fine but I recommend extending a class. This class usually called as Sprite or Action or GameObject contains the basic information like
image (or animation), position, collision rect and some basic functions like get and set it's position, speed and some collision detection functions if you wish.
Some resources.
The Breakout game
GEJ - game-engine-for-java
Java-Gaming.org - Java Gaming Resources
Hope they help. And to draw the object, do
g.drawImage(ball.image, ball.x, ball.y, null);

How to make Circle color light in the Android google map

Below is my code where I am drawing circle on the Google Map in Android. It is working fine for me.
Problem Statement:-
Currently the circle that is getting drawn on the google map is very dark. I need to make that circle little bit light with the same color that I am having currently. Is that possible to make that circle little bit light by tweaking few parameters in the paint or color? It is more darker in the center part, don't know why. I just need to make it light in all the four circles that I have currently.
class MapOverlay extends Overlay {
private GeoPoint pointToDraw;
int[] imageNames=new int[6];
private Point mScreenPoints;
private Bitmap mBitmap;
private Paint mCirclePaint;
public MapOverlay(GPSLocationListener gpsLocationListener, int currentUser) {
imageNames[0]=currentUser;
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setColor(0x30000000);
mCirclePaint.setStyle(Style.FILL_AND_STROKE);
mBitmap = BitmapFactory.decodeResource(getResources(),imageNames[0]);
mScreenPoints = new Point();
}
public void setPointToDraw(GeoPoint point) {
pointToDraw = point;
}
public GeoPoint getPointToDraw() {
return pointToDraw;
}
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
if (pointToDraw == null) {
return true;
}
mScreenPoints = mapView.getProjection().toPixels(pointToDraw, mScreenPoints);
int totalCircle=5;
int radius=40;
int centerimagesize=35;
for (int i = 1; i <= totalCircle; i ++) {
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, i*radius, mCirclePaint);
}
canvas.drawBitmap(mBitmap, (mScreenPoints.x-(centerimagesize/2)),(mScreenPoints.y-(centerimagesize/2)), null);
super.draw(canvas,mapView,shadow);
return true;
}
}
Snapshot of my Circle currently-
Any suggestion will be of great help.
Problem
The reason why it gets darker in the center, is because you are drawing four circles, one over the other. When you draw the second circle, the part that is commoun to both, is painted twice, so it becomes darker. When you draw the tird circle, it becomes even darker ...
Solution
If you want all circles with same color, you should use Style.STROKE for all the circles, except the larger one, which shoud use Style.FILL_AND_STROKE. With that you only draw the lines for the small circles and fill all area when drawing the big one.
Code
mCirclePaint.setStyle(Style.STROKE);
for (int i = 1; i <= totalCircle-1; i ++) {
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, i*radius, mCirclePaint);
}
mCirclePaint.setStyle(Style.FILL_AND_STROKE);
canvas.drawCircle(mScreenPoints.x,mScreenPoints.y, totalCircle*radius, mCirclePaint);
Regards

Creating custom JButton from images containing transparent pixels

Read edit 2 for what I'm actually missing to make it work
I'm currently trying to create some custom JButtons using images created in photoshop that have an alpha parameter.
So far, overriding the paint() method to draw the image has worked in the sense that the button is drawn showing the correct image. I'd like to improve it, though, by making its shape (clickable area) the same as the visible pixels on the image (right now if I draw the button's border, it's a square).
Is there an easy way to do that or do I have to parse the image and find the alpha pixels to make a custom border?
Which methods would I have to override to make it work the way I want?
Also, another question I'm going to have later: would it be better to use some kind of algorithm to change the images' colors to make it seem like it is being clicked when people click on it or am I better off creating a second image and drawing that one while the button is active?
Edit: I just read on some other question that I should redefine paintComponent() instead of paint(), I'd like to know why since redefining paint() works fine?
Edit 2: I changed everything to make sure my JButtons are created using the default constructor with an icon. What I'm trying to do is get the X and Y position of where the click was registered and grab the icon's pixel at that position and check its alpha channel to see if it is 0 (if it is, do nothing, else do the action it is supposed to do).
The thing is, the alpha channel always returns 255 (and blue, red and green are at 238 on transparent pixels). On other pixels, everything returns the value it should be returning.
Here's an example (try it with another image if you want) that recreates my problem:
public class TestAlphaPixels extends JFrame
{
private final File FILECLOSEBUTTON = new File("img\\boutonrondX.png"); //My round button with transparent corners
private JButton closeButton = new JButton(); //Creating it empty to be able to place it and resize the image after the button size is known
public TestAlphaPixels() throws IOException
{
setLayout(null);
setSize(150, 150);
closeButton.setSize(100, 100);
closeButton.setContentAreaFilled(false);
closeButton.setBorderPainted(false);
add(closeButton);
closeButton.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
System.out.println("Alpha value of pixel (" + e.getX() + ", " + e.getY() + ") is: " + clickAlphaValue(closeButton.getIcon(), e.getX(), e.getY()));
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
});
Image imgCloseButton = ImageIO.read(FILECLOSEBUTTON);
//Resize the image to fit the button
Image newImg = imgCloseButton.getScaledInstance((int)closeButton.getSize().getWidth(), (int)closeButton.getSize().getHeight(), java.awt.Image.SCALE_SMOOTH);
closeButton.setIcon(new ImageIcon(newImg));
}
private int clickAlphaValue(Icon icon, int posX, int posY)
{
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage tempImage = (BufferedImage)createImage(width, height);
Graphics2D g = tempImage.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
int alpha = (tempImage.getRGB(posX, posY) >> 24) & 0x000000FF;
return alpha;
}
public static void main(String[] args)
{
try
{
TestAlphaPixels testAlphaPixels = new TestAlphaPixels();
testAlphaPixels.setVisible(true);
testAlphaPixels.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
This is just a wild guess, but is it possible that when my image gets cast to an Icon, it loses its Alpha property and thus doesn't return the correct value? Anyway, I'd really appreciate it if someone could actually help me out and tell me what I should be changing to get the correct value.
I'm guessing that because when I try it with the original image, the alpha channel's value is fine, but I can't actually use that BufferedImage because I resize it, so I actually get the channel values of the image with the original size...
I think you are on the wrong way. You do not have to override neither paint() nor paintComponent() methods. JButton already "knows" to be shown with image only:
ImageIcon cup = new ImageIcon("images/cup.gif");
JButton button2 = new JButton(cup);
See the following tutorial for example: http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JButton.html
Moreover swing is fully customized. You can control opacity, border, color etc. You probably should override some mentioned methods to change functionality. But in most cases there is better and simpler solution.
Since there were good elements in multiple answers, but none of the answers were complete on their own, I'll answer my own question so other people that have the same problem can try something similar.
I created my buttons using a new class which extends JButton, with a new constructor that takes a BufferedImage as parameter instead of an icon. The reason for that is that when I did something like myButton.getIcon(), it would return an Icon, then I'd have to make various manipulations on it to make it a BufferedImage of the right size, and it ended up not working anyway because it seems like the first cast to Icon made it lose the alpha data in the pixels, so I couldn't check to see if the user was clicking on transparent pixels or not.
So I did something like this for the constructor:
public class MyButton extends JButton
{
private BufferedImage bufImg;
public MyButton(BufferedImage bufImg)
{
super(new ImageIcon(bufImg));
this.bufImg = bufImg;
}
}
Then I created an accessor for my bufImg that resized the image to fit the JButton using the getSize() method and then returned an image resized at the right size. I do the transformations in the getBufImg() accessor because the image size might change when the window gets resized. When you call the getBufImg(), it's usually because you clicked on the button and thus you're not currently resizing the window.
Something a little bit like this will return the image at the right size:
public BufferedImage getBufImg()
{
BufferedImage newImg = new BufferedImage(getSize().getWidth(), getSize().getHeight(), BufferedImage.TYPE_INT_ARGB); //Create a new buffered image the right size
Graphics2D g2d = newImg.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(bufImg, 0, 0, getSize().getWidth(), getSize().getHeight(), null);
g2d.dispose();
return newImg;
}
With that buffered image, you can then code a method like this:
private int clickAlphaValue(BufferedImage bufImg, int posX, int posY)
{
int alpha;
alpha = (bufImg.getRGB(posX, posY) >>24) & 0x000000FF; //Gets the bit that contains alpha information
return alpha;
}
That you call on the button that implements a MouseListener, like this:
myButton.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
if(clickAlphaValue(((myButton)e.getSource()).getBufImg(), e.getX(), e.getY()) != 0) //If alpha is not set to 0
System.exit(0); //Or other things you want your button to do
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
});
And voila! The button will only do the action if you clicked on non-transparent pixels.
Thanks for the help everyone, I couldn't have come up with this solutions on my own.
If you want to have shape-specific click points, you're better off using Shape and their contains method. If you want, you can create a shape when creating your custom button class as part of it, and implement a contains method by wrapping around the shape's contains method.
As for the custom JButton, create a class that extends JButton, like this:
import java.awt.*;
import javax.swing.*;
public class CustomButton extends JButton{
/** Filename of the image to be used as the button's icon. */
private String fileName;
/** The width of the button */
private int width;
/** The height of the button. */
private int height;
public CustomButton(String fileName, int width, int height){
this.fileName = fileName;
this.width = width;
this.height = height;
createButton();
}
/**
* Creates the button according to the fields set by the constructor.
*/
private void createButton(){
this.setIcon(getImageIcon(filename));
this.setPreferredSize(new Dimension(width, height));
this.setMaximumSize(new Dimension(width, height));
this.setFocusPainted(false);
this.setRolloverEnabled(false);
this.setOpaque(false);
this.setContentAreaFilled(false);
this.setBorderPainted(false);
this.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
}
}
Here's how you can load the ImageIcon, if you want to do it like this.
public ImageIcon getImageIcon(String fileName){
String imageDirectory = "images/"; //relative to classpath
URL imgURL = getClass().getResource(imageDirectory + fileName);
return new ImageIcon(imgURL);
}
This will give you a button that will at least look like your image.
I asked a similar question regarding Image-based events on click, and Shapes helped wonders.
I guess it comes down to how complex your button images are.
Here's reference anyway:
How can you detect a mouse-click event on an Image object in Java?
PS: Maybe look into generating shapes from images, that go around all the pixels that aren't transparent. No idea if this is possible, but it would mean that a button would only be "pressed" if the user clicks on the image part of it. Just a thought.
If you want your button layout to be that of the non-transparent pixels in your image, then you should redefine the paintComponent() method. It is the most correct way of doing it (overriding paint() worked in old times but is now discouraged).
However I think it is not exactly what you want: you want a click on the button to be detected only if it is on a non-transparent pixel, right? In that case you have to parse your image and when clicked compare mouse coordinates to the pixel alpha channel of your image as JButton does not have such a feature.
If you have a round button, this is exactly what you need:
public class RoundButton extends JButton {
public RoundButton() {
this(null, null);
}
public RoundButton(Icon icon) {
this(null, icon);
}
public RoundButton(String text) {
this(text, null);
}
public RoundButton(Action a) {
this();
setAction(a);
}
public RoundButton(String text, Icon icon) {
setModel(new DefaultButtonModel());
init(text, icon);
if(icon==null) return;
setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
setContentAreaFilled(false);
setFocusPainted(false);
initShape();
}
protected Shape shape, base;
protected void initShape() {
if(!getBounds().equals(base)) {
Dimension s = getPreferredSize();
base = getBounds();
shape = new Ellipse2D.Float(0, 0, s.width, s.height);
}
}
#Override public Dimension getPreferredSize() {
Icon icon = getIcon();
Insets i = getInsets();
int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
return new Dimension(iw+i.right+i.left, iw+i.top+i.bottom);
}
#Override public boolean contains(int x, int y) {
initShape();
return shape.contains(x, y);
//or return super.contains(x, y) && ((image.getRGB(x, y) >> 24) & 0xff) > 0;
}
}
JButton has a contains() method. Override it and call it on mouseReleased();
paintComponent() instead of paint() depends if you paint() inside XxxButtonUI or just override paintComponent(), but there exists the option JButton#setIcon.

Categories