I am trying to make a basic tetris game, first I am looking to draw a grid to make sure that I am creating blocks as I want to, however I can't get my program to access my paintComponent method.
package tetris;
import javax.swing.*;
import java.awt.*;
public class TetrisMain extends JFrame {
final int BoardWidth = 10;
final int BoardHeight = 20;
public static int HEIGHT = 400;
public static int WIDTH = 200;
Timer timer;
boolean isFallingFinished = false;
boolean isStarted = false;
boolean isPaused = false;
int score = 0;
int curX = 0;
int curY = 0;
int[][] grid = new int[BoardWidth][BoardHeight];
public static void main(String[] args) {
JFrame frame = new JFrame("Charles Walker - 1504185");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.repaint();
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.BLACK);
for (int i = 0; i < BoardWidth; i++) {
for (int j = 0; j < BoardHeight; j++) {
curX = grid[i][curY];
curY = grid[curX][j];
g.fillRect(WIDTH / BoardWidth, HEIGHT / BoardHeight, curX, curY);
}
}
}
}
Here is a basic code to do what you want :
import javax.swing.JFrame;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.*;
public class Name extends JFrame {
public Name() {
super("Name");
setTitle("Application");
setContentPane(new Pane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setResizable(true);
setVisible(true);
while (true){
try { //Update screen every 33 miliseconds = 25 FPS
Thread.sleep(33);
} catch(InterruptedException bug) {
Thread.currentThread().interrupt();
System.out.println(bug);
}
repaint();
}
}
class Pane extends JPanel {
public void paintComponent(Graphics g) { //Here is were you can draw your stuff
g.drawString("Hello World",0,20); //Display text
}
}
public static void main(String[] args){
new Name();
}
}
I think you forgot that line to set the content pane :
setContentPane(new Pane());
and, important, you need a while loop to redraw :
while (true){
try { //Update screen every 33 miliseconds = 25 FPS
Thread.sleep(33);
} catch(InterruptedException bug) {
Thread.currentThread().interrupt();
System.out.println(bug);
}
repaint();
}
Related
I wrote some code to create a little square on the screen, but when I press the left button, nothing seems to happen. The rectangle doesn't move, and "Move Left." doesn't get printed out in the console. Here's the code.
package game;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings({ "serial" })
public class Game extends Canvas implements Runnable, KeyListener{
public static final int WIDTH = 400;
public static final int HEIGHT = WIDTH/12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";
//Size, scale, and name of window.
boolean running = false;
public int tickCount = 0;
//X and Y coordinates of the rectangle on the screen.
private static int rectX = 10;
private int rectY = 10;
JFrame f;
Canvas can;
BufferStrategy bs;
Controls c;
public Game(){
f = new JFrame(NAME);
f.setSize(400, 400);
f.setVisible(true);
//Sets the size of the window and makes it visible.
JPanel panel = (JPanel) f.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
//Sets preferred size and layout to null.
can = new Canvas();
can.setBounds(0, 0, 400, 400);
can.setIgnoreRepaint(true);
//Creates new canvas.
panel.add(can);
//Adds the canvas to the JPanel.
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setResizable(false);
//Makes the window packed, nonresizable, and close the program on exit.
can.createBufferStrategy(3);
bs = can.getBufferStrategy();
//Creates buffer strategy for the canvas.
System.out.println("Window created.");
addKeyListener(this);
}
public synchronized void start(){
running = true;
new Thread(this).start();
//Starts thread
}
public synchronized void stop(){
running = false;
//For stopping the program.
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000.0/60.0;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while(running)
{
long now = System.nanoTime();
delta += (now - lastTime)/nsPerTick;
lastTime = now;
boolean shouldRender = true;
while(delta>=1)
{
ticks++;
tick();
delta -= 1;
shouldRender = true;
//Creates 60fps timer. Not in use.
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(shouldRender)
{
frames++;
render();
//Renders the image.
}
if(System.currentTimeMillis() - lastTimer >= 1000)
{
lastTimer += 1000;
System.out.println(frames + " frames, " + ticks + " ticks");
frames = 0;
ticks = 0;
//Resets timer. Not in use.
}
}
}
public void tick(){
tickCount++;
//Not in use, yet.
}
public void render(){
Graphics2D g = (Graphics2D)bs.getDrawGraphics();
//Sets g to the buffer strategy bs.
g.setColor(Color.BLACK);
g.fillRect(rectX, rectY, 100, 100);
//Creates black rectangle.
g.dispose();
bs.show();
//Puts the rectangle on the screen.
}
public static void main(String [] args){
new Game().start();
//Starts thread.
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_LEFT)
{
--rectX;
System.out.println("Move left.");
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Because at your constructor, you create a new Canvas,and don't use the Game canvas and your rectangle is drawn at the new Canvas, not Game canvas, so your listener has no effect.
Please see the the follow new constructor, I tested it, it works fine.
public Game() {
frame = new JFrame(NAME);
frame.setSize(400, 400);
frame.setVisible(true);
// Sets the size of the window and makes it visible.
JPanel panel = (JPanel) frame.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
// Sets preferred size and layout to null.
//can = new Canvas();
//can.setBounds(0, 0, 400, 400);
//can.setIgnoreRepaint(true);
setBounds(0, 0, 400, 400);
setIgnoreRepaint(true);
// Creates new canvas.
panel.add(this);
// Adds the canvas to the JPanel.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(false);
// Makes the window packed, nonresizable, and close the program on exit.
//can.createBufferStrategy(3);
createBufferStrategy(3);
bs = getBufferStrategy();
// Creates buffer strategy for the canvas.
System.out.println("Window created.");
addKeyListener(this);
}
http://www.youtube.com/watch?v=M0cNsmjK33E
I want to develop something similar to the link above using Java Swing. I have the sorting method and did while repaint but when I triggered the sorting, instead of showing the bars slowly sorting itself, it freezes and then unfreezes when the array has been fully sorted.
How do I fix this?
Edit: sorry forgot about the codes. its a very simple gui. and another class for sorting which sorts the whole array
public class SortGUI {
JFrame frame;
int frameWidth = 1000, frameHeight = 1000;
int panelWidth, panelHeight;
DrawPanel panel;
JPanel panel2;
JScrollPane scroll;
JViewport view;
static int[] S = new int[50000];
public static void main(String[] args) throws InterruptedException {
SortGUI app = new SortGUI();
initializeArray();
app.go();
}
public static void initializeArray()
{
for (int i = 0; i < S.length; i++) {
S[i] = (int) (Math.random() * 16581375);
}
}
public void go() throws InterruptedException {
//Frame
frame = new JFrame();
frame.setSize(frameWidth, frameHeight);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//panel
panel = new DrawPanel();
scroll = new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
//Layout
frame.add(scroll);
frame.addKeyListener(new keyListener());
while(true)
{
panel.repaint();
}
}
public class DrawPanel extends JPanel
{
public DrawPanel()
{
this.setPreferredSize(new Dimension(50000,930));
}
public void paintComponent(Graphics g)
{
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
for(int i = 0; i < S.length; i++)
{
int red = S[i] / 65025;
int green = (S[i] > 65025)? S[i] % 65025 : 0;
int blue = green;
blue %= 255;
green /= 255;
g.setColor(new Color(red,green,blue));
g.fillRect(i, 900 - (S[i] / 18500), 1, S[i] / 18500);
}
}
}
public class keyListener implements KeyListener{
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent ke) {
if(ke.getKeyChar() == '1')
{
sorter.bubbleSort(S);
}
}
public void keyReleased(KeyEvent ke) {
}
}
}
Note: I started writing this before the question was deleted
Most likely your using some looping mechanism and praying that each iteration, the ui with be updated. That's a wrong assumption. The UI will not be update until the loop is finished. What you are doing is what we refer to as blocking the Event Dispatch Thread(EDT)
See How to use a Swing Timer. Make "iterative" updates in the ActionListener call back. For instance, if you want to animate a sorting algorithm, you need to determine what needs to be updated per "iteration" of the timer callback. Then each iteration repaint the ui.
So your Timer timer could look something like
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (sortingIsDone()) {
((Timer)e.getSource()).stop();
} else {
sortOnlyOneItem();
}
repaint();
}
});
Your sortOnlyOneItem method should only, well, perform a sort for just one item. And have some sort of flag to check if the sorting is done, then stop the timer.
Other notes:
You should be calling super.paintComponent in the paintComponent method, if you aren't going to paint the background yourself. Generally I always do though.
Here's a complete example. I'm glad you figured it out on your own. I was working on this example before I saw that you got it.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SelectionSortAnimate extends JPanel {
private static final int NUM_OF_ITEMS = 20;
private static final int DIM_W = 400;
private static final int DIM_H = 400;
private static final int HORIZON = 350;
private static final int VERT_INC = 15;
private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;
private JButton startButton;
private Timer timer = null;
private JButton resetButton;
Integer[] list;
int currentIndex = NUM_OF_ITEMS - 1;
public SelectionSortAnimate() {
list = initList();
timer = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isSortingDone()) {
((Timer) e.getSource()).stop();
startButton.setEnabled(false);
} else {
sortOnlyOneItem();
}
repaint();
}
});
startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
list = initList();
currentIndex = NUM_OF_ITEMS - 1;
repaint();
startButton.setEnabled(true);
}
});
add(startButton);
add(resetButton);
}
public boolean isSortingDone() {
return currentIndex == 0;
}
public Integer[] initList() {
Integer[] nums = new Integer[NUM_OF_ITEMS];
for (int i = 1; i <= nums.length; i++) {
nums[i - 1] = i;
}
Collections.shuffle(Arrays.asList(nums));
return nums;
}
public void drawItem(Graphics g, int item, int index) {
int height = item * VERT_INC;
int y = HORIZON - height;
int x = index * HOR_INC;
g.fillRect(x, y, HOR_INC, height);
}
public void sortOnlyOneItem() {
int currentMax = list[0];
int currentMaxIndex = 0;
for (int j = 1; j <= currentIndex; j++) {
if (currentMax < list[j]) {
currentMax = list[j];
currentMaxIndex = j;
}
}
if (currentMaxIndex != currentIndex) {
list[currentMaxIndex] = list[currentIndex];
list[currentIndex] = currentMax;
}
currentIndex--;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < list.length; i++) {
drawItem(g, list[i], i);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DIM_W, DIM_H);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Sort");
frame.add(new SelectionSortAnimate());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
So I have this JPanel Graphics code:
public void paint(Graphics g){
super.paint(g);
for(int y=0 ;y < 50; y++){
for(int x = 0; x < 50; x++){
if(m.getMaze(x, y).equals("g")){
g.drawImage(m.getGround(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("w")){
g.drawImage(m.getWall(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("S")){
g.drawImage(m.getStart(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("E")){
g.drawImage(m.getEnd(), x * 16, y * 16,null);
}
}
}
}
And inside the for loop (the second one) I would like to pause it for half a second, so you can see it drawing each tile. The thing is, is when I use
Thread.sleep(500);
After the second for loop, it just stops the whole thing forever. If I use
g.wait(500);
it keeps spamming
java.lang.IllegalMonitorStateException
in the console. And yes, it is surrounded with try/catch. How can I pause this?
On a swing Timer call repaint(50L, x*16, y*16, 16, 16);. Use fields for the current state (x, y),
and on every paintComponent draw only that state/tile.
1) use paintComponent() method for custom paintings intead of paint(). Read about custom paintings in java
2) Don't block EDT with Thread.sleep(500); or g.wait(500);.
Seems you need to use swing Timer for loading. Here is simple example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class TestFrame extends JFrame {
private Timer timer;
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
final DrawPanel p = new DrawPanel();
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(p.drawingTiles < 16){
p.addDrawingTile();
p.repaint();
} else {
timer.stop();
System.out.println("done");
}
}
});
timer.start();
add(p);
}
public static void main(String args[]) {
new TestFrame();
}
private class DrawPanel extends JPanel{
protected int drawingTiles = 0;
private int tiles[][] = new int[4][4];
public DrawPanel(){
Random r = new Random();
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
tiles[i][j] = r.nextInt(5);
}
}
}
public void addDrawingTile() {
drawingTiles++;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int curTiles = 0;
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
if(curTiles <drawingTiles){
curTiles++;
g.drawString(tiles[i][j]+"", (j+1)*10, (i+1)*10);
}
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50,50);
}
}
}
I want to add an object to a JPanel then after a time limit repaint that JPanel and add new object.
package papProject;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Animation extends JPanel{
private static boolean loop = true;
private static int frameTimeInMillis = 10;
public static void main(String[] args){
JPanel Ani = new JPanel();
Ani.getParent();
setup(Ani);
while (loop) {
Ani.repaint();
try {
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {
}
}
}
public static void setup(JPanel Panel)
{
Circle circle[] = new Circle[10];
JFrame jf = new JFrame();
jf.setTitle("Falling Shapes Animation");
Panel.setLayout(new BorderLayout());
jf.setSize(600,400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().add(Panel);
for(int i = 0; i < circle.length; i++ )
{
Panel.add(circle[i] = new Circle());
}
}
}
This code draws the JPanels and add the circle objects to it and is supposed to repaint that component and then add a new object. I believe my problem is with the main() method.
#SuppressWarnings("serial")
public class Circle extends Animation implements ActionListener
{
int ranNum = 0;
int y = 0;
int x = (int) Math.random();
int velY = 2;
Circle()
{
x = getRanNum();
}
public int getRanNum() {
Random rand = new Random();
for (int j = 0; j<10; j++)
ranNum = rand.nextInt(300);
return ranNum;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(x, y, 30, 30);
}
public void actionPerformed(ActionEvent e)
{
if (y>370){
velY =-velY;
}
y = y + velY;
}
}
This code draws the Cirlce object from a random x position and moves it in the y direction.
Thank you for any help you can give.
It looks like you are calling everything from the EDT (Event Dispatching Thread).
If then you use something like
while (loop) {
Ani.repaint();
try {
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {
}
}
}
That actually blocks your thread, and you're not seeing anything. Better create a new Thread or Runnable for your Animation, then start the new threads.
I am not sure but in main method you repaint a JPanel but not the JFrame who is the window that show. I leave an example of your code in which I repainted the JFrame and the cirlce move!
#SuppressWarnings("serial")
public class Animation extends JPanel{
private static boolean loop = true;
private static int frameTimeInMillis = 100;
static JFrame jf;
public static void main(String[] args){
JPanel Ani = new JPanel();
Ani.getParent();
setup(Ani);
jf = new JFrame();
while (loop) {
jf.add(new Circle());
jf.repaint();
jf.setVisible(true);
try {
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {
}
}
}
I was wondering if anybody here knows how to make a seamlessly endless loop with shapes using a timer. Basically I'm trying to make a new set of moving shapes while the current set of shapes is moving so that it looks like it's just infinitely moving along the top of the screen. I have tried the if statements alongside the public int getX(){return x;)}, but I have not succeeded in doing so. Maybe it's possible to have a second timer linked with a second set of shapes and set a delay time? (However, I do not know how to go about writing a second timer and I do not know how to set a delay, help me??)
Any solutions or suggestions?
Here is an example, notice how the set of shapes is redrawn after all of the shapes pass the screen. This is not what I want. I want it to appear as if it were infinitely running along the top of the screen in smooth succession.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ExampleLoop extends JPanel implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ExampleLoop());
frame.setVisible(true);
}
Timer timer = new Timer(50, this);
int x = 0, velX = 7;
// CHRISTMAS THEME :D
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.GREEN);
for (int z = 0; z <= 500; z += 100)
g.fillRect(x + z, 0, 20, 20);
timer.start();
}
public void actionPerformed(ActionEvent e) {
if (x < 500) {
velX = velX;
x = x + velX;
}
else {
x = 0;
}
repaint();
}
}
I can't really figure out what going on in your code, but I reproduce the effect you're looking for. You can examine it. It runs.
What i did was make 5 different xPoints. You could have done this by using an array of int but I thouhgt it would be easier to read this way.
For each xPoint, I incremented each timer iteration. If the xPoint reached the screen width, I made it equal 0. Then repaint. I did that for all the points.
Code Edited: to use arrays and loops
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class GreenRects extends JPanel {
private static final int SCREEN_WIDTH = 500;
private static final int SCREEN_HEIGHT = 500;
private static final int OFFSET = 100;
private static final int SIZE = 20;
private static final int INC = 5;
int[] xPoints = new int[5];
public GreenRects() {
int x = 0;
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] = x;
x += OFFSET;
}
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < xPoints.length; i++) {
if (xPoints[i] + INC < SCREEN_WIDTH) {
xPoints[i] += INC;
} else {
xPoints[i] = 0;
}
}
repaint();
}
});
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g.setColor(Color.green);
for (int i = 0; i < xPoints.length; i++) {
g.fillRect(xPoints[i], 0, SIZE, SIZE);
}
}
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new GreenRects());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can try this code in if clause
if (x < 80)
{
velX = velX;
x = x + velX;
}