Java block not appearing - java

Trying to make a game. Want a yellow block at the bottom of the screen, a dark grey (or black, doesnt really matter) bacground, and blue squares flying from the top of the screen at random times. Have been at it for awfully long but the blue squares do not appear, and I have no idea why. Im a beginner at Java, and have been through many resources - please advise, thanks!
Game Class Below
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.awt.*;
public class Game extends JPanel {
//THIS IS DISPLAY
static int width = 1000;
static int height = 700;
int randNumb = 0;
int squareWidth = 50;
int squareHeight = 50;
int squareYLocation = -squareWidth;
boolean numberCreated = false;
static boolean gameRunning = false;
public Game() {
setBackground(Color.DARK_GRAY);
setPreferredSize(new Dimension(1000, 700));
}
//generates a random Y value inside the window for the square to spawn at
public void generateRandomNumber() {
Random rand = new Random();
randNumb = rand.nextInt(width - squareWidth);
numberCreated = true;
}
public void paintComponent ( Graphics g )
{
//int width = getWidth();
//int height = getHeight();
//g.setColor(Color.DARK_GRAY);
super.paintComponent( g );
//g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLUE);
g.fillRect(randNumb, squareYLocation, squareWidth, squareHeight);
g.setColor( Color.YELLOW );
g.drawRect( 500, 600, 50, 50);
g.fillRect(500, 600, 50, 50);
//g.setColor(Color.blue);
//g.fillRect(100, 200, 32, 32);
}
public void update() {
//calls the generateRandomNumber() method which gives the square a random x value inside the screen
if (!numberCreated) {
generateRandomNumber();
}
//moves the squares y coordinate towards the bottom of the screen and stops once it hits the bottom
if (squareYLocation <= height) {
squareYLocation++;
//resets the x and y location to a new position
} else {
numberCreated = false;
squareYLocation = -squareHeight;
}
}
public void start() {
gameRunning = true;
}
}
Main
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferStrategy;
import java.util.Random;
import javax.swing.*;
public class Main{
public static void main(String[] args) {
//Constructor with frame title
JFrame frame = new JFrame("words");
//Makes frame visible
frame.setVisible(true);
//Size of frame & location
frame.setBounds(240, 80, 1000, 700);
//How to close the window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Game());
}
}

This statement means
int squareYLocation = -squareWidth;
that the Y position is -50 so the blue square will appear off screen. Make it 0 or positive
int squareYLocation = 0;

Related

How to make an array of coins appear for game?

How to make a list or an array of 10 coins appear on the game? It is the same coin image. I want my sprite (Mario) to pick up all 10 coins, but I want them next to each other } maybe I could manually type out the x locations.
Mainly I am not sure how to make the coins appear on the screen.
UPDATE: The coins appear when I manually type out each coin (exp. coins[0]=tool.kit..). It does not work with the for loop though.
public class Action extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
private Image man;
int x=0, y=490, a=(int) (Math.random() * 450 + 1), b=500; // make a random num
Image img;
Image [] coins = new Image [10];
public Action() {
super.setDoubleBuffered(true);
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
img = Toolkit.getDefaultToolkit().createImage("background.png");
}
#Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
ImageIcon ii = new ImageIcon("realmario.png");
man = ii.getImage();
g.drawImage(img,0, 0, null);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(man, x, y, this);
g2d.drawImage(coins[1], a, b, this);
for (int i = 0; i<coins.length; i++) {
coins[i] = Toolkit.getDefaultToolkit().createImage("coin.png");
}
}
If you want to place objects one linked to other you have to work with x-axis and adjust properly.
Eg. img have (3,7) pixels and first will be at (10,10). You need to grab x = 3 and made adjustments in loop.
1: img at 10,10 (initial)
2: img at 10+3,10
3: img at 10+3+3,10 ; etc
//image dimension on x
int image_x = 3;
//initial placement on x,y
int x=10,y=10;
for(int i=0;i<coins.length; i++)
{
//if same image is enough one coin
g2d.drawImage(coin[7],x,y,this);
x=x+image_x;
}
Just check first the coordinates system.
Draw the same image 10 times, each with different coordinates:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SwingTest extends JFrame {
public SwingTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new ImagePanel());
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new SwingTest());
}
}
class ImagePanel extends JComponent {
BufferedImage coin = getImage();
private static final int GAP =2;
public ImagePanel() {
setPreferredSize(new Dimension( 300, 200));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int x=0, y= GAP;
for (int i = 0; i <3 ; i++) {
g.drawImage(coin,x,y, this);
x= x+ GAP + coin.getWidth();
}
}
public static BufferedImage getImage() {
try {
URL url = new URL("http://www.btcwmx.ru/admin/uploads/img/bitcoin-gold.png");
return ImageIO.read(url);
} catch ( IOException ex) { ex.printStackTrace();}
return null;
}
}

Draw sine wave curve

Output is a straight line, but should be a curve.
Not sure if the problem is maths or code.
I know the problem is in the bit where it says (Math.sin(sum3.getValue()) however I can't work out what it should be...
I have for some reason got a post it note that say I(V)=SIN(V); which I imagine is what I am trying to implement to get an I(V) curve.
Sum3 is (V) from a different class.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class GraphApp extends JFrame {
int x,y;
int ax,by;
IVChar sum3 = new IVChar();
//create a window in which the graph will be shown
public GraphApp(){
setTitle("Graph App");
setSize(700,700);
setResizable(true);
setVisible(true);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
x = 30;
y = 300;
}
// create the axis
#Override
public void paint(Graphics g){
g.drawLine(300, 30, 300, 600); // y axis
g.drawLine(30, 300, 600, 300); // x axis
g.setColor(Color.blue);//colour of drawLine
g.fillOval(x, y, 3, 3);
g.drawString("I", 310, 40);
g.drawString("V'", 600, 314);
run();
repaint(); //makes it run again
}
// implement and draw graphical functions
public void run(){
try{
Thread.sleep(10); //speed line is drawn
float ax,by;
ax = x-300;
by = y-300;
//specify the function
by = (float) Math.sin(sum3.getValue());//makes a sin wave
x = (int) (ax + 300);
y = (int) (300 - by);
x++;
}catch(Exception e){
System.out.println("Error!");
}
}
public static void main(String[]args){
new GraphApp();
}
}
You can use javax.swing.Timer to animate drawing a curve:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class GraphApp extends JFrame {
public GraphApp(){
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
add(new SineWave());
pack();
setVisible(true);
}
public static void main(String[]args){
SwingUtilities.invokeLater(()->new GraphApp());
}
}
class SineWave extends JPanel{
//use constants for better readability
private static final double W = 600, H = 700, AMPLITUDE = H/3;
private static final int MARGIN =30, GAP = 15,DOT_SIZE = 3, SPEED = 10;
//starting point
private double x = MARGIN;
private final double y = H/2;
private final int dX = 1; //x increment
//you need to use doubles to avoid rounding error and have use non integer coordinates
private final List<Point2D.Double> points;
private final Timer timer;
public SineWave() {
setPreferredSize(new Dimension((int)W, (int)H));
points = new ArrayList<>();
timer = new Timer(SPEED, e->addPoints()); //timer to add sine points
timer.start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Shape xAxis = new Line2D.Double(MARGIN, H/2, W-MARGIN, H/2);
g2.draw(xAxis);
Shape yAxis = new Line2D.Double(W/2, MARGIN, W/2, H-MARGIN);
g2.draw(yAxis);
g.drawString("I", (int)(W/2-GAP),MARGIN);
g.drawString("V'", (int)(W-GAP), (int)(H/2+GAP));
g2.setColor(Color.blue);//colour of graph
for(Point2D.Double p : points){
Shape point = new Ellipse2D.Double(p.getX(), p.getY(),DOT_SIZE , DOT_SIZE);
g2.draw(point);
}
}
private void addPoints() {
double angel = - Math.PI + 2* Math.PI * ((x-MARGIN)/(W- 2*MARGIN));//angle in radians
double newY = y + AMPLITUDE * Math.sin(angel);
points.add(new Point2D.Double(x, newY));
x += dX;
if(x >= W-MARGIN) {
timer.stop();
}
repaint();
}
}

How to use a timer to repaint some swing components

INTRODUCTION
Hi guys, I was learning how to make a little game where you are a racquet (rectangle) and all the asteroids (enemies) are falling down the screen and you have to avoid them
PROBLEM
When the game starts the enemies (asteroids) are paint on the screen in a very high speed, and they occupy all the size of the screen so there is no way to avoid them (try the game), I just want that between painting an enemy and the next one there is a mininum time to delay (for example 0,5 seconds).
But I just don't know how to do that, I tried to use Thread.sleep() and TimeUnit but they just make the game slower.
Surfing on stackoverflow I've find out that I may try to use Swing timers, I've read some stuff on the web but I want to know how can I use swing timers in my code (if they can solve my problem).
Here it is the code:
The main class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class Game extends JPanel {
Racquet racquet = new Racquet(this);
Enemy Enemy = new Enemy(this);
static ArrayList<Enemy> enemyList = new ArrayList<Enemy>();
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
/** TO SET THE RANDOM POSITION ON WHERE THE ENEMIES HAVE TO APPEAR ON THE SCREEN **/
public int random(int x, int y, ArrayList<Enemy> pa){
int r = 0;
for(int i = 0; i<pa.size(); i++){
Random rand = new Random();
r = rand.nextInt(x+y)-1;
return r;
}
return r;
}
/** letting the enemies move on the screen **/
private void move() {
for(int i = 0; i < enemyList.size(); i++){
enemyList.get(i).move();
}
racquet.move();
}
/** Painting on the screen enemies and the racquet **/
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int i = 0; i < enemyList.size(); i++){
enemyList.get(i).paint(g2d);
}
racquet.paint(g2d);
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public void createEnemy(){
enemyList.add(new Enemy(this));
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Asteroids");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.random(200, 300, enemyList);
while (true) {
game.createEnemy();
game.move();
game.repaint();
Thread.sleep(5);
}
}
}
The racquet class:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 30;
private static final int HEIGHT = 6 ;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game = game;
}
/** letting the racquet moves on the screen **/
public void move() {
if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
x = x + xa;
}
/** Creating the rectangle racquet **/
public void paint(Graphics2D g) {
g.fillRect(x, Y, WIDTH, HEIGHT);
}
/** // Setting xa everytime to 0, if we don't do this it just takes a single pression to go to a direction until we press the other key **/
public void keyReleased(KeyEvent e) {
xa = 0;
}
/** Choosing the direction **/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds() {
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY() {
return Y;
}
}
And the enemy class:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.*;
public class Enemy {
private Game game;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
/** Generating a random position where the enemies have to appear **/
public Enemy(Game game){
this.game = game;
x = game.random(0, 320, game.enemyList);
}
/** Paint the enemies **/
public void paint(Graphics2D g) {
g.fillRect(x, y, 20, 20);
}
/** move the enemies and detect collisions **/
public void move(){
y += ya;
if(collision()){
game.gameOver();
}
}
/** returns true if the enemy rectangle touch the racquet **/
public boolean collision(){
return game.racquet.getBounds().intersects(getBounds());
}
public Rectangle getBounds() {
return new Rectangle(x, y, 20, 20);
}
}
Suggestions:
Your game "tick" time is 5 mSecs, a not quite reasonable time. I suggest that
You get rid of the "magic" number, using a constant instead,
and make the tic a little bigger, say 12 to 15 mSec.
Also better to use a Swing Timer or to at least make sure that you do your while loop in a defined background thread.
Most importantly, you're creating a new enemy with each tick of your game loop, and that's too fast. Instead:
Don't create a new Enemy with each tick,
Instead save the time that the last enemy was created in a field,
Check the delta-time, the current system time - lastEnemyCreationTime, inside of your game-loop,
Only create a new enemy if the delta-time is greater than a reasonable value, either a constant value or a field (not a magic number).
On creation of the new enemy, reset the lastEnemyCreationTime to the current system time.
Unrelated recs:
Override the JPanel's paintComponent, not the paint method as this will give you double buffering by default which can lead to smoother perceived graphics.
Favor using Key Bindings over a KeyListener as this will help to easily eliminate focus issues inherent with use of KeyListeners.

How to paint a circle with a random size on a random coordinate such that the circle is fully visible?

Code:
Random rand = new Random();
JPanel mainPanel;
int randomSize = 0;
int randomPositionX = 0;
int randomPositionY = 0;
final static int FRAME_HEIGHT = 500;
final static int FRAME_WIDTH = 500;
final static int TITLE_BAR = 30 ;
final static int MAX_SIZE = 100;
final static int MIN_SIZE = 10 ;
/* All the below code is put into a method */
mainPanel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(randomPositionY, randomPositionX, randomSize, randomSize);
}
};
do{
randomSize = rand.nextInt(MAX_SIZE) + 1;
}while(randomSize < MIN_SIZE);
do{
randomPositionX = rand.nextInt(FRAME_WIDTH);
randomPositionY = rand.nextInt(FRAME_HEIGHT);
}while((randomPositionX + randomSize > FRAME_WIDTH) || (randomPositionY + randomSize > FRAME_HEIGHT - TITLE_BAR));
repaint();
What I want is the circle to have a random size such that it should have a minimum size of 10 and a maximum size of 100. The circle should also be painted in a random coordinate such that the circle is fully visible inside the JPanel mainPanel.
Note that mainPanel will be added to a JFrame whose size is set using setSize(FRAME_WIDTH, FRAME_HEIGHT);.
But the problem is that sometimes, a part of the circle is half outside and half inside the JPanel:
Where did I go wrong?
You're trying to use the frame size when calculating the position of the circle, when the frame includes a variable high title bar AND frame insets
You're trying to use the frame size when it's irrelevant, it's the component's size you should be using, as it's within the mainPanel's coordinate context which you want to paint
So, how do I fix the issues?
Discard ALL the frame "padding"/"offsets". The mainPanel has it's own coordinate context (it's top left corner will be 0x0) and it will be within it's parent's coordinate context, so you don't need to care about the frame or it's insets.
Simplify your calculations, for example...
int randomSize = MIN_SIZE + (rand.nextInt(MAX_SIZE) + 1);
int randomPositionX = rand.nextInt(getWidth() - randomSize);
int randomPositionY = rand.nextInt(getHeight() - randomSize);
Should allow you to produce results which won't fall outside of the viewable area, as the maximum range of the dimensions is the current size of the container minus the desired size, just beware, if the available size is smaller then MAX_SIZE, you will have issues ;)
The example generates a new circle every second
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
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;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public final static int MAX_SIZE = 100;
public final static int MIN_SIZE = 10;
private Rectangle bounds;
private Random rand;
public TestPane() {
rand = new Random();
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int randomSize = MIN_SIZE + (rand.nextInt(MAX_SIZE) + 1);
int randomPositionX = rand.nextInt(getWidth() - randomSize);
int randomPositionY = rand.nextInt(getHeight() - randomSize);
bounds = new Rectangle(randomPositionX, randomPositionY, randomSize, randomSize);
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (bounds != null) {
g2d.setColor(Color.RED);
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
g2d.dispose();
}
}
}

Getting a graph to auto adjust with the screen

I have created a graph in a Java applet and I'm trying to get the g.fillRect to auto adjust with the screen. I want the first bar to be a third of the screen and then to halve in size for each other bar.
g.fillRect(xpos, 550, width, hight);
I seem to have a problem with getting a gap in between each bar. Could you give me a hand with this problem? Thanks in advance.
You have to compute the width of each individual bar, which is
barWidth = availableWidth / numberOfBars - 1
The "-1" will be the space that will be left between the bars, and thus, has to be added again when computing the actual coordinates. You could spend some time with the details there: When the numbers are not "nicely divisble", then the bars either have to have different widths, or you have to add a small margin at the left and right side to compensate for the odd size.
However, here is a quick sketch of one possible solution:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class BarChart
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
final JSlider slider = new JSlider(1, 50, 3);
final BarChartPanel barChartPanel = new BarChartPanel();
slider.addChangeListener(new ChangeListener()
{
#Override
public void stateChanged(ChangeEvent e)
{
barChartPanel.setNumberOfBars(slider.getValue());
}
});
f.getContentPane().add(slider, BorderLayout.NORTH);
f.getContentPane().add(barChartPanel, BorderLayout.CENTER);
f.pack();
f.setSize(600,600);
f.setVisible(true);
}
}
class BarChartPanel extends JPanel
{
private int numberOfBars = 3;
void setNumberOfBars(int n)
{
this.numberOfBars = n;
repaint();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
Random random = new Random(0);
int barWidth = getWidth() / numberOfBars - 1;
int barsWidth = numberOfBars * (barWidth+1);
int offsetX = (getWidth() - barsWidth) / 2;
for (int b=0; b<numberOfBars; b++)
{
int x = offsetX + b * (barWidth + 1);
int barHeight = random.nextInt(500);
int y = getHeight() - barHeight;
g.fillRect(x, y, barWidth, barHeight);
}
}
}

Categories

Resources