I am learning the basics of java games programming and I am confused about a few things. I know you use the "canvas" class to create a blank canvas and then use the paint method to create stuff.
But what does Graphics2D
? I have seen people using the grahpics2d class to create a canvas for example
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
Now why did they use the grahpics2d and not the canvas?
Also I have seen people creating shapes like a rectangle by using:
Rectangle r = new Rectangle();
but some people have created them like:
Shape shape = new Rectangle2D.Double(value1,valu2,valu3,valu4);
What's the difference between these two?
Thanks in advance.
regards,
First, no I wouldn't use a Canvas object but rather a JPanel, and I'd draw in the paintComponent method override, not the paint method. Think of the JPanel as if it were a paint canvas and the Graphics or Graphics2D as if it were the brush that you were using to paint with. So in other words, you would need them both to create your drawing.
As for Rectangle vs. Rectangle2D, the 2D shapes are part of a newer addition to Graphics, when Graphics2D came about. These are based on the Shape interface, one that allows you a little more flexibility and OOPs to your drawing.
For greater detail, please have a look at:
Edit
Re your questions:
Q: So you would use JPanel as my empty canvas and the Graphics2D g2d = (Graphics2D) g; create a brush kind of thing that you can use to change the JPanel. Hence this g2d.setColor(Color.BLACK); changes the background colour of our JPanel canvas. Is this right?
Yes. And you can even change the Graphics2D object's Stroke via
g2d.setStroke(new BasicStroke(...));
Q: Also can you explain to me what is "Shape" and what do you use it for?
Please look at the 2nd tutorial that I've linked to above as it will go into a fair bit of detail on what Shape represents and how to use it. It is in sum an interface used by all of the Xxxxx2D classes such as Rectangle2D and Ellipse2D. And it allows them all to share certain properties including being fillable, drawable, transormable, and more.
Edit 2
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.*;
@SuppressWarnings("serial")
public class RotateFoo extends JPanel {
private static final int PREF_WIDTH = 800;
private static final int PREF_HEIGHT = 600;
private static final Color STAR_COLOR = Color.red;
private static final int ROTATE_TIMER_DELAY = 20;
private static final int POINTS = 5;
private static final int RADIUS = 50;
private static final String TITLE = "Press \"r\" to rotate";
private static final float TITLE_POINTS = 52f;
private Path2D star = new Path2D.Double();
private Timer rotateTimer = new Timer(ROTATE_TIMER_DELAY, new RotateTimerListener());
public RotateFoo() {
double x = 0.0;
double y = 0.0;
double theta = 0.0;
for (int i = 0; i <= POINTS; i++) {
x = RADIUS + RADIUS * Math.cos(theta);
y = RADIUS + RADIUS * Math.sin(theta);
if (i == 0) {
star.moveTo(x, y);
} else {
star.lineTo(x, y);
}
theta += 4 * Math.PI / POINTS;
}
double tx = (getPreferredSize().getWidth() - star.getBounds().getWidth()) / 2;
double ty = (getPreferredSize().getHeight() - star.getBounds().getHeight()) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
star.transform(at );
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
String rotateOn = "rotate on";
String rotateOff = "rotate off";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, false), rotateOn);
actionMap.put(rotateOn, new AbstractAction() {
public void actionPerformed(ActionEvent arg0) {
if (rotateTimer != null && !rotateTimer.isRunning()) {
rotateTimer.start();
}
}
});
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, true), rotateOff);
actionMap.put(rotateOff, new AbstractAction() {
public void actionPerformed(ActionEvent arg0) {
if (rotateTimer != null && rotateTimer.isRunning()) {
rotateTimer.stop();
}
}
});
//rotateTimer.start();
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, TITLE_POINTS));
add(titleLabel);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(STAR_COLOR);
if (star != null) {
g2.draw(star);
}
}
private class RotateTimerListener implements ActionListener {
private static final double BASE_THETA = Math.PI / 90;
@Override
public void actionPerformed(ActionEvent e) {
double anchorx = getPreferredSize().getWidth() / 2;
double anchory = getPreferredSize().getHeight() / 2;
AffineTransform at = AffineTransform.getRotateInstance(BASE_THETA, anchorx, anchory);
star.transform(at);
repaint();
}
}
private static void createAndShowGui() {
RotateFoo mainPanel = new RotateFoo();
JFrame frame = new JFrame("RotateFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}