Connect Four Falling Animation - java

I'm currently creating a connect four game for fun and was just about finished when I decided that it would be cool to add a falling animation. I know of a couple different ways to do this, but I'm not sure what would be 'best'.
Since my GUI is made up of JComponents I figured I should use javax.swing.Timer for Thread safety.
ActionListener update = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
};
};
Timer timer = new Timer(10, update);
timer.start();
My real question is what should I do to update my game board?
Would it be better to call repaint() (maybe even repaint(Rectangle rec))and handle everything in paint() or create another class for a connect four piece and add that Component to my GUI.
The other class for my connect four piece is currently this...
public class Piece extends JLabel{
private Color color;
private Ellipse2D circle;
public Piece(Color color, int radius) {
this.color = color;
circle = new Ellipse2D.Float(0, 0, radius, radius);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paintComponent(g2);
g2.setColor(color);
g2.fill(circle);
}
}
If I add the component to the GUI, I would have to call invalidate() and validate() quite often since the timer I have currently is fast, and I'm not sure if that's better or worse than calling repaint().
I've tried both of these ways, and both seem to work fine, I'm just not sure which is more efficient? I'd rather not have it be more taxing that it needs to be - for learning purposes.
Also if there's a better way than what I've thought of please let me know. I'm open to all suggestions

Your Piece is a component. All you have to do is call setLocation(...) and the component will repaint itself automatically. No need for any custom painting.
If I add the component to the GUI, I would have to call invalidate() and validate()
Just set the layout to null. You will need to set the size of the component, but no need to call invalidate() or validate() since those methods are used by a layout manager.

It will depend. The easiest solution (from my perspective) is to use custom painting (use repaint and handle everything in paintComponent, as it will allow you to better control the layers of graphics (IHMO).
You could, as an exercise, do both.
Basically, it would require to you to manage (directly or indirectly) your own layout manager for the pieces and board.

Related

how to call a graphical method in actionperformed?

I am kinda new to java and would like to invoke a graphical method in ActionEvent, for instance let's say I would like a square to be drawn when button b is pressed? Will appreciate any help thanks:
package Mst;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
public class Cours2_2 extends Applet implements ActionListener {
Button a,b,c;
public void init(){
setBackground(Color.pink);
a= new Button("KIRMIZI");
a.addActionListener(this);
add(a);
b= new Button("BEYAZ");
b.addActionListener(this);
add(b);
c= new Button("SARI");
c.addActionListener(this);
add(c);
}
public void paint(Graphics g){
g.drawString("s", 5, 5);
}
public void actionPerformed(ActionEvent e){
String s= e.getActionCommand();
if(s.equals("KIRMIZI")){
setBackground(Color.red);
}
if(s.equals("BEYAZ")){
setBackground(Color.white);
}
if(s.equals("SARI")){
setBackground(Color.yellow);
}
drawStrings(t);
}
public void drawStrings(Graphics t) {
t.setColor(Color.yellow);
t.fillRect(0, 0, 75 ,75);
}
}
I would like to know if I should create this square which I want drawn when a button is pressed as a method or a function. Thanks
Avoid Applet, if you "really" have to, use JApplet instead. Having said that, you should start with JPanel and override it's paintComponent method instead (and make sure you call super.paintComponent before doing any custom painting. Take a look at Painting in AWT and Swing and Performing Custom Painting for more details.
Generally speaking, painting in AWT/Swing is passive, that is, when the system "decides" something needs to be updated, it will then be painted. This means that you (generally) have little control over when something will be painted. You make suggestions, but it's update to the system to decide what and when something is painted.
You paint methods should paint the current state of the component. This means that you will need to provide some information and logic that the paint methods can use to make decisions about what to paint. For example, you could have a flag, which is changed by the ActionListener, which calls repaint on your component and when the component is painted, you would test the state of this flag and make decisions on what should be done (like drawing a square for example).
A more complicated approach might use a List and take advantage of the Shape API, adding or removing shapes to the List which the paint method would then be able to iterate over and paint
Have a look at Collections Trail and
2D Graphics for more details

Strange repositioning using repaint();

I have a JSlider in a JPanel that return me a value of R-G-B .
I create it, in the Costructor of JPanel. I draw in same Panel (using paintComponent) a little circle, and I change his color using the Slider. I want that the color change in contemporany of slider shift.
So, i use the method repaint.. Next to Panel there is another Panel, with two button.. If I use method repaint in first panel , the buttons of second panel duplicated in the topLeft of First Panel. Why? Thank's you.
First Panel:
public class OptionsPanel extends JPanel {
static JSlider RBG = new JSlider(0,255);
OptionsPanel(){
this.setVisible(false);
this.setSize(350,1000);
this.setLayout(null);
this.setBackground(new Color(200,200,0));
Main.f1.add(this);
RBG.setVisible(true);
RBG.setSize(255,50);
RBG.setLocation(30,240);
this.add(RBG);
LotL lotl = new LotL();
Button save = new Button("Save");
save.setVisible(true);
save.setSize(100,40);
save.setLayout(null);
save.setLocation(60,300);
save.addActionListener(lotl);
save.setBackground(Color.yellow);
save.identificatore=3;
this.add(save);
}
boolean draw=false;
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
}
Second Panel:
public class FirstPanel extends JPanel{
FirstPanel(){
this.setVisible(true);
this.setSize(1000,1000);
this.setLayout(null);
this.setBackground(new Color(255,200,180));
Main.f1.add(this);
Button start = new Button("Start Game!");
Button options = new Button("Options");
LotL LotL = new LotL();
start.setVisible(true);
start.setSize(200,80);
start.setLayout(null);
start.setLocation(400,450);
start.addActionListener(LotL);
start.setBackground(Color.green);
start.identificatore=1;
this.add(start);
options.setVisible(true);
options.setSize(200,70);
options.setLayout(null);
options.setLocation(400,550);
options.addActionListener(LotL);
options.setBackground(Color.green);
options.identificatore=2;
this.add(options);
}
}
You've broken the paint chain...
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
Graphics is a shared resource, which gets passed to ALL the components that are painted during a given paint cycle.
One of the jobs of paintComponent is to prepare the Graphics context for painting, but filling with the components background color.
You MUST call super.paintComponent before performing any custom painting.
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
}
Also, there is never any need for paintComponent to be public, no one should ever be calling directly and NEVER modify the state of a component from within any paint method which may trigger a repaint, you will get yourself into a infinite loop which will eventually consume your CPU and make you computer unusable.
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details
You should also avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

Custom Drawing loop in Swing

I'm trying to learn how to do custom GUI stuff in Java for a group project I'm working on. I've done user form type GUIs in the past so I know the gist of what I'm doing here, but the custom drawing stuff still confuses me.
I copied this code from online and I've been trying to figure out how it works, but I don't get why I can't loop the drawing method. As a simple test I'm trying to make the program draw an oval on my cursor. It draws the oval on the cursor, but only once on runtime and then does nothing.
How can I make this loop so I can continue to draw things? Or is there a different way I need to call/use the methods?
public class BombermanGUI extends JFrame {
public static final int CANVAS_WIDTH = 640;
public static final int CANVAS_HEIGHT = 480;
private DrawCanvas canvas;
public BombermanGUI() {
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
Container cp = getContentPane();
cp.add(canvas);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setTitle("......");
this.setVisible(true);
}
private class DrawCanvas extends JPanel{
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
setBackground(Color.BLACK);
int x, y;
x = MouseInfo.getPointerInfo().getLocation().x - this.getLocationOnScreen().x;
y = MouseInfo.getPointerInfo().getLocation().y - this.getLocationOnScreen().y;
g.setColor(Color.YELLOW);
g.drawOval(x, y, 10, 10);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BombermanGUI();
}
});
}
}
Painting a complex series of callbacks and responses to changes within the system. The first thing to remember is that you don't control the painting process, but rather make suggestions to the system so that it can make decisions about what and when it should repaint...
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details.
Painting is a destructive process. It is assumed that when a repaint occurs, that you will repaint the entire state of the current component. This means that you will need some kind of model which maintains all the content that needs to be painted...
Have a look at 2D Graphics, in particular, have a look at the section on Shape
MouseInfo is a seriously crappy way to detect the location of the mouse for this purpose, instead, you should be using a MouseListener and/or MouseMotionListener to detect mouse events.
Basically, when the user presses a mouse button, you would record the location of the mouse press. When the mouse is moved, you would calculate the width and height of the movement relative to the mouse press and update the "current" shape. You would call repaint to request that the UI be updated and paint this shape via the paintComponent method (painting all the previous shapes first).
When the mouse button is released, you would commit the "current" shape to the model, so it will be painted every time paintComponent is called.
THIS IS tobais_k ANSWER IM ANSWERING TO CLOSE THE QUESTION!
Either add an event listener and have it call the repaint method, e.g. a mouse motion listener for tracking your mouse cursos, or have some thread run your game and trigger repaint in regular intervals.

Clearing drawings on Jframe

I am making a game in which I move a square with my mouse, but when I move my mouse the old squares do not delete, which results in a trail of squares. I would like it to only have the one square which is following my mouse. This is currently my code. I have read to use paintcomponents but I am not sure how to use it since I am still a beginner.
This is in my "GamePanel" Class
public void mouseMoved(MouseEvent m) {
Graphics g= this.getGraphics();
h.changeX(m.getX());
h.changeY(m.getY());
h.drawHero(g);
}
This is in my "Hero" Class
public void drawHero(Graphics g){
g.drawImage(heroPic,stX,stY,null); //heroPic is a picture I imported
Don't use the this.getGraphics(). That is something you will definitely not want to to do, since it produces artifacts (as you mentioned).
It would be better to store the mouse position as a variable, then handle all the rendering when the paintComponent(Graphics) method has been called. Be sure to also call super.paintComponent(Graphics) to get rid of artifacts.
Generally, you should only handle graphics inside the paintComponent(Graphics) method and in any methods that are called only from the paintComponent(Graphics) method.
Here is a question which touches on why you should avoid Component#getGraphics(): Drawing an object using getGraphics() without extending JFrame
Here is another question I answered revolving around rendering with graphics: Java JFrame draw
Use a seperate class that extends JPanel :
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(heroPic, x, y, this);
}
}
Then create a variable that will hold this class object :
DrawPane dp = new DrawPane();
after that set the variable to the contence pane. :
JFrame.setContencePane(dp);
Now to repaint this do :
dp.repaint();
Do not worry about the 'Graphics g' you wont have to input anything.

Drawing graphics on top of a JButton

I have a situation wherein I have a bunch of JButtons on a GridLayout. I need each of the JButtons to have:
a background image (but retain the ability to keep the default button look if needed)
custom graphics drawn on top by other classes
I have no trouble with the background image, since I am using setIcon() but I am having problems drawing things on top of the background. At one point I was able to draw on top of the button, but after the button was clicked, the drawings disappeared. How can make the button keep this drawing state?
Basically, I need a way for my JButtons to have public methods that would allow another class to draw anything on it such as:
public void drawSomething() {
Graphics g = this.getGraphics();
g.drawOval(3,2,2,2);
repaint();
}
or
public Graphics getGraphics() {
return this.getGraphics();
}
then another class could do this:
button.getGraphics().drawSomething();
The latter is more what I am looking for but the first is equally useful.
Is there any way to go about this? Also, overriding the parent class method paintComponent() doesn't help since I need each button to have different graphics.
you can subclass JButton and override paintComponent().
you can handle each button having a different graphic by providing an external 'painter' to the subclass. Or just have a different subclass for each different graphic.
public class MyButton extends JButton {
private Painter painter;
public void paintComponent(Graphics g) {
super.paintComponent(g);
painter.paint(g);
}
}
public interface Painter {
public void paint(Graphics g);
}
you cannot just paint on the button as you are doing as the painting will get lost when the button is next repainted.
You can create a BufferedImage and do custom painting on it and then draw the image in your custom paintComponent(...) method.
Look at the DrawOnImage example from Custom Painting Approaches.

Categories

Resources