I have been working on a Java project for Uni, the classic arcade game Breakout, and so far have managed to create the bat and ball objects and they work as intended. I'd like to implement the brick wall using an array as making each brick its own object will result in inefficient code, but my experience with Java doesn't extend to Arrays and I understand, unlike Python, they are tricky to get working.
I'd like the bricks to be given different positions based on x and y parameters already established.
Here is the Model class where I'd like to add the array;
public class Model
{
// First, a collection of useful values for calculating sizes and layouts etc.
public int B = 6; // Border round the edge of the panel
public int M = 40; // Height of menu bar space at the top
public int BALL_SIZE = 30; // Ball side
public int BRICK_WIDTH = 50; // Brick size
public int BRICK_HEIGHT = 30;
public int BAT_MOVE = 5; // Distance to move bat on each keypress
public int BALL_MOVE = 3; // Units to move the ball on each step
public int HIT_BRICK = 50; // Score for hitting a brick
public int HIT_BOTTOM = -200; // Score (penalty) for hitting the bottom of the screen
View view;
Controller controller;
public GameObj ball; // The ball
public ArrayList<GameObj> bricks; // The bricks
public GameObj bat; // The bat
public int score = 0; // The score
// variables that control the game
public boolean gameRunning = true; // Set false to stop the game
public boolean fast = false; // Set true to make the ball go faster
// initialisation parameters for the model
public int width; // Width of game
public int height; // Height of game
// CONSTRUCTOR - needs to know how big the window will be
public Model( int w, int h )
{
Debug.trace("Model::<constructor>");
width = w;
height = h;
}
// Initialise the game - reset the score and create the game objects
public void initialiseGame()
{
score = 0;
ball = new GameObj(width/2, height/2, BALL_SIZE, BALL_SIZE, Color.RED );
bat = new GameObj(width/2, height - BRICK_HEIGHT*3/2, BRICK_WIDTH*3,
BRICK_HEIGHT/4, Color.GRAY);
bricks = new ArrayList<>();
// ***HERE***
}
And here is the corresponding code I'd like added to View class to draw the bricks in the GUI;
public void drawPicture()
{
// the ball movement is runnng 'i the background' so we have
// add the following line to make sure
synchronized( Model.class ) // Make thread safe (because the bal
{
GraphicsContext gc = canvas.getGraphicsContext2D();
// clear the canvas to redraw
gc.setFill( Color.WHITE );
gc.fillRect( 0, 0, width, height );
// update score
infoText.setText("BreakOut: Score = " + score);
// draw the bat and ball
displayGameObj( gc, ball ); // Display the Ball
displayGameObj( gc, bat ); // Display the Bat
// ***HERE***
}
}
The .jar project file in its current state can be viewed here.
On a side note, there is a slight bug with the bat, it does not stop when it hits either side, not sure what's the best way to go about making it stay within the parameters of the window.
Thanks in advance!!
You already have your ArrayList of bricks. Create a function to convert a row/column co-ordinate into an index for your array. Say you have a grid 3x4 (3 rows, 4 columns):
0 |_|_|B|_|
1 |_|_|_|_|
2 |_|_|_|_|
0 1 2 3
Your ArrayList would be of size 12 (3x4).
private int translateCoordToIndex(int row, int col) {
return row * TOTAL_COLS + col
}
So for the brick at row=0,col=2 in the diagram its position comes out as (0*4)+2 = 2 which means index 2 in your ArrayList bricks.get(2)
You can even just change the ArrayList into a general array of GameObj GameObj[]
Alternatively you can use a 2d array of GameObj to represent a grid of bricks.
GameObj[][] bricks = new GameObj[rows][cols] This way you can access the exact brick using its row and column position - e.g. bricks[0][0] for the first brick.
Both approaches are pretty much the same.
Related
I am trying to write a program in Java that draws trees filling the screen. I have variables set to randomly place a tree on the x-axis and move down 10 steps each time. The problem I am encountering is when the new trees are drawn they overlap the old trees so the fill does not fill the tree. So my question is how can I fully fill a drawn shape filling over what is underneath. I have tried messing with the color I'm using but I just don't know what to do. I am brand new to Java but I have a fair bit of experience in Javascript.
Here is my code so far:
public class Turtle extends TurtleGraphicsWindow
{
public Turtle()
{
super(650, 550);
}
static void PrintTree() {
Turtle t = new Turtle();
t.speed(100);
for (int i = 0; i < 30; i++) { //to move the trees down
//randomizer
int min = -300;
int max = 300;
int random_int = (int)Math.floor(Math.random()*(max-min+1)+min);
var tWx = random_int;
int tWy = -10*i+150;
//trunk
t.pu();
t.setpensize(3);
t.setxy( (tWx-25) , (tWy-100) );
t.setpc(8); //brown
t.pd();
t.fd(50);
t.setx(t.xcor()+50);
t.bk(50);
t.setx(t.xcor()-50);
t.pu();
t.setxy(t.xcor()+5,t.ycor()+5);
t.setpc(9); //tan
t.fill();
//tree
t.setxy((tWx+100),(tWy-50));
t.setpencolor(31);
t.pd();
var tx = 50;
t.setx(t.xcor()-200);
t.setxy(t.xcor()+tx,t.ycor()+(tx+10));
t.setx(t.xcor()-(tx-15));
t.setxy(t.xcor()+(tx-5),t.ycor()+(tx+5));
t.setx(t.xcor()-(tx-20));
t.setxy(t.xcor()+(tx-10),t.ycor()+(tx));
t.setx(t.xcor()-(tx-30));
t.setxy(t.xcor()+(tx-15),t.ycor()+(tx-5));
t.setx(t.xcor()-(tx-35));
t.setxy(t.xcor()+(tx-20),t.ycor()+(tx-10));
//right side of tree
t.setxy(t.xcor()+(tx-20),t.ycor()-(tx-10));
t.setx(t.xcor()-(tx-35));
t.setxy(t.xcor()+(tx-15),t.ycor()-(tx-5));
t.setx(t.xcor()-(tx-30));
t.setxy(t.xcor()+(tx-10),t.ycor()-(tx));
t.setx(t.xcor()-(tx-20));
t.setxy(t.xcor()+(tx-5),t.ycor()-(tx+5));
t.setx(t.xcor()-(tx-15));
t.setxy(t.xcor()+tx,t.ycor()-(tx+10));
t.pu();
t.setpc(FOREST);
t.setxy(t.xcor()-10,t.ycor()+5);
t.fill();
}
}
public static void main(String[] args)
{
PrintTree();
}
}
This is what it has been looking like now:
https://i.stack.imgur.com/ipwhN.png
I am working on a dusk cleaner simulator on Java, in this case the shape of the cleaner is a circular ball.
The program is quite simple, the user puts in the width and length of the "room" and coordinates x and y.
What I want to do and cannot is create a series of commands, each represented by a character. There are three commands that I want to imnplement:
1. char 'A' = Move forward 1 meter
2. char 'L' = Turn left 90 degrees
3. R Turn right 90 degrees
Example of user input AALA, in this case the expected output is that the machine moves 2 meters and then turns left 90 degrees and then moves 1 meter again. Hope I am clear.
As you can see in the code, I have tried to create an array of chars but I dont know what the next step should be...
The code:
public class Cleaner extends JPanel {
/* int lx = 1, ly = 1;
int x = 200, y = 250;
*/
int x, y;
int width = 52, height = 50; // width and height of the "dust sucker"
int lx , ly;
// an array of chars
char[] charArray ={ 'A', 'L', 'R'};
java.util.Timer move; // making the instance of Timer class from the util package
static JFrame frame;
Cleaner()
{
frame = new JFrame ("Cleaner started!"); // passing attributes to our fame
frame.setSize (400, 400); // setting size of the starting window
frame.setVisible (true);
setForeground(Color.black); // setting color
move = new java.util.Timer();
move.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
if(x<0)
lx = 1;
if(x>=getWidth()-45)
lx = -1; // -1 sets boundry for the dusk sucker
if(y<0)
ly = 1;
if(y>=getHeight()-45)
ly = -1; // -1 sets boundry for the dusk sucker
x+=lx; // to make the machine move
y+=ly;
repaint();
}
}, 0, 5// speed of the machine
);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint (Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, width, height);
}
public static void main (String[] args)
{
// lx value
String lxValue =
JOptionPane.showInputDialog( "Enter lx" );
// ly value
String lyValue =
JOptionPane.showInputDialog( "Enter ly" );
String xValue =
JOptionPane.showInputDialog( "Enter x value" );
// ly value
String yValue =
JOptionPane.showInputDialog( "Enter y value" );
// convert String inputs to int values
int firstInput = Integer.parseInt( lxValue );
int secondInput = Integer.parseInt( lyValue );
int thirdInput = Integer.parseInt( xValue );
int forthInput = Integer.parseInt( yValue );
Cleaner cleaner = new Cleaner();
frame.add(cleaner);
cleaner.lx = firstInput;
cleaner.ly = secondInput;
cleaner.x = thirdInput;
cleaner.y = forthInput;
}
}
All help is appreciated!
First some basics:
override paintComponent(), not paint() when doing custom painting.
use a Swing Timer for animation. All updates to Swing components need to be done on the Event Dispatch Thread (EDT).
in this case the shape of the cleaner is a circular ball.
So you need to create a class to represent the ball. It will have basic properties like:
size
location
direction of movement.
speed of movement.
You will then need to create methods to change the properties. Maybe:
move() - move in the current direction at the current speed
turnRight() - adjust direction
turnLeft() - adjust direction
Then you can create an ArrayList to store the moves and a Swing Timer to execute the moves.
Whenever the Timer fires you remove the command from the ArrayList and execute the command. By invoking one of the above 3 methods.
Check out: get width and height of JPanel outside of the class for an example that is similiar (not exact) to what you want. It demonstrates the concept if creating an object with the properties needed to control its motion.
I'm working on a Mario game and am in need of assistance and suggestions on how to go about creating hit detection for a tilemap.
Currently, the player has the ability to walk/jump through the blocks.
I added in a fixed detection to the ground for now which I am hoping to replace with regular hit detection.
I understand that there are four sides to each block and the player. Only some blocks need hit detection and some things you might need to know is that the player stays at 300px(middle of screen) 98% of the time.
The only thing that moves is the map
The map is rendered from a .txt file and is rendered like so:
for(int y=0;y<map.length;y++) {
for(int x=0;x<map[y].length;x++) {
int index = map[y][x];
int yOffset = 0;
if(index>(tileSheet.getWidth() / Engine.TILE_WIDTH) -1) {
yOffset++;
index = index - (tileSheet.getWidth() / Engine.TILE_WIDTH);
}
g.drawImage(tileSheet,
((x * Engine.TILE_WIDTH)*scale)+position,
((y * Engine.TILE_HEIGHT)*scale),
(((x * Engine.TILE_WIDTH) + Engine.TILE_WIDTH )*scale)+position,
(((y * Engine.TILE_HEIGHT) + Engine.TILE_HEIGHT)*scale),
index * Engine.TILE_WIDTH,
yOffset * Engine.TILE_HEIGHT,
(index * Engine.TILE_WIDTH) + Engine.TILE_WIDTH,
(yOffset * Engine.TILE_HEIGHT) + Engine.TILE_HEIGHT,
null
);
}
}
//This code is actually longer(included file later on)
Colour hit detection is too slow and inconsistent for multi coloured tiles
Since the map is moving I suppose I need to move the hit detection boxes with it. As for selecting the boxes that it should detect might be difficult. Maybe it would be a better idea to make the code NOT hit detect certain tiles.
My attempts have ended in obfuscation of code. Can anyone suggest the easiest way to implement the hit detection? (keep in mind I have jumping).
The important codes are listed below:
Board.java(The panel where everything is drawn)
package EvilMario; //Include this class in the EvilMario game package
import java.awt.*; //Imported to allow use of Image
import java.awt.event.*; //Imported to allow use of ActionListener
import javax.swing.*; //Import swing
public class Board extends JPanel implements ActionListener { //Class Board
private TileLayer l; //Instance of TileLayer class
private Menu m; //Instance of menu class
private Player p; //Instance of player class
Timer time; //A timer
public static enum STATE {MENU,GAME}; //The game states
public static STATE State = STATE.MENU; //Set the first state to menu
//END
//GLOBAL
//DECLARATIONS
public Board() {
l = TileLayer.FromFile("D:/ICS3U1/EvilMario/map.txt"); //Tile map data from .txt file
this.addMouseListener(new MouseInput()); //Listen for mouse input
this.addKeyListener(new AL()); //Listen for key input
p = new Player(); //Start running Player class
m = new Menu(); //Start running Menu class
setFocusable(true); //Allows movement
time = new Timer(20,this); //Timer set to update "this" class every 20 milliseconds(Approximately 50fps)
time.start(); //Actually start the timer
}
public void actionPerformed(ActionEvent e) {
p.move(); //Call the move method from the player class
repaint(); //Repaint
}
public void paintComponent(Graphics g) { //Graphics method
super.paintComponent(g); //Super hero?
Graphics2D g2d = (Graphics2D) g; //Cast 2D graphics
if(State==STATE.GAME) {
if(p.distanceTraveled<300)l.DrawLayer(g,0);else l.DrawLayer(g, -(p.distanceTraveled-300)); //Draw the tile map
g2d.drawImage(p.getImage(), p.getX(), p.getY(), 48, 48, null); //Draw the player
if(p.distanceTraveled==3488) System.out.println("You have won the game!"); //Draw the end game screen
} else {
m.render(g); //Render the menu
}
}
private class AL extends KeyAdapter { //Action Listener extends key adapter
public void keyPressed(KeyEvent e) { //On key press
p.keyPressed(e); //Send whatever key was pressed TO the keyPressed method in the player class
}
public void keyReleased(KeyEvent e) { //On key release
p.keyReleased(e); //Send whatever key was released TO the keyReleased method in the player class
}
}
}
Player.java(player logic)
package EvilMario; //Include this class in the EvilMario game package
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Player {
int x, dx, y, distanceTraveled; //x coordinate,change in x coordinate,y coordinate,1st rep bg,2nd rep bg,dist traveled
Image player; //The player variable
ImageIcon walk_L_anim = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/walk_L_anim.gif");
ImageIcon walk_L_idle = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/walk_L_idle.png");
ImageIcon walk_R_anim = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/walk_R_anim.gif");
ImageIcon walk_R_idle = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/walk_R_idle.png");
ImageIcon jump_L_anim = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/jump_L_anim.gif");
ImageIcon jump_L_idle = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/jump_L_idle.png");
ImageIcon jump_R_anim = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/jump_R_anim.gif");
ImageIcon jump_R_idle = new ImageIcon("D:/ICS3U1/EvilMario/images/animatedMario/jump_R_idle.png");
boolean holdingLeft = false;
boolean holdingRight = false;
static boolean jumping = false;
static boolean falling = false;
static int jumpingTime = 350;
public Player() {
player = walk_R_idle.getImage(); //Give the player the image
x = 75; //The original x position of the player
y = 277; //The original y position of the player
distanceTraveled = 75; //Original distance traveled
}
public void move() {
if(x>=0 && x<=300) { //If the player is within the moving area
x = x+dx; //The x position is updated to become itself+the amount you moved
}
if(x<0) //If the player has reached he very left side of the screen(0px)
x=0; //Move him up a pixel so he can move again
if(x>300) //If the player has reached the center of the screen(300px)
x=300; //Move him down a pixel so he can move again
distanceTraveled=distanceTraveled+dx; //Calculate distanceTraveled
if(distanceTraveled<0) //Make sure distanceTraveled isn't a negative
distanceTraveled=0; //Make sure distanceTraveled isn't a negative
if(distanceTraveled>=300) //Keep player at center position once past 300 mario meters
x=300; //Keep player at center position once past 300 mario meters
if(holdingLeft && !holdingRight) {
if(distanceTraveled<300)dx=-5; else dx=-4;
if(jumping && !falling) {
player = jump_L_anim.getImage();
y-=8;
} else {
player = walk_L_anim.getImage();
if(y<277)
y+=8;
}
} else if(holdingRight && !holdingLeft) {
if(distanceTraveled<300)dx=5; else dx=4;
if(jumping && !falling) {
player = jump_R_anim.getImage();
y-=8;
} else {
player = walk_R_anim.getImage();
if(y<277)
y+=8;
}
} else if(!holdingRight && !holdingLeft) {
dx = 0;
if(jumping && !falling) {
player = jump_R_anim.getImage();
y-=8;
} else {
if(y<277)
y+=8;
}
}
if(y==277) {
falling = false;
}
System.out.println("LEFT: "+holdingLeft+" JUMP: "+jumping+" RIGHT: "+holdingRight+" FALLING: "+falling+" Y: "+y);
}
public int getX() { return x; } //This method will return the x. Is used by other classes
public int getY() { return y; } //This method will return the y. Is used by other classes
public Image getImage() { return player; } //This method will return the player. Is used by other classes
public void keyPressed(KeyEvent e) { //Called from the board class, the argument is whatever key was pressed
int key = e.getKeyCode(); //The key originally sent from the board class
if(key == KeyEvent.VK_LEFT && !holdingLeft)
holdingLeft = true;
if(key == KeyEvent.VK_RIGHT && !holdingRight)
holdingRight = true;
if(key == KeyEvent.VK_UP && !jumping && !falling)
new Thread(new JumpThread(this)).start();
}
public void keyReleased(KeyEvent e) { //Called from the board class, the argument is whatever key was released
int key = e.getKeyCode(); //The key originally sent from the board class
if(key == KeyEvent.VK_LEFT) { //If the left or right key was released
dx = 0; //Stop moving
holdingLeft = false;
player = walk_L_idle.getImage();
}
if(key == KeyEvent.VK_RIGHT) {
dx = 0;
holdingRight = false;
player = walk_R_idle.getImage();
}
}
}
TileLayer.java (Rendering of the tile layer)(Probably most important part relating to the question)
package EvilMario; //Include this class in the EvilMario game package
import java.awt.Graphics; //
public class TileLayer {
private int[][] map; //2D array
private BufferedImage tileSheet; //The tile sheet
public TileLayer(int[][] existingMap) { //
map = new int[existingMap.length][existingMap[0].length]; //map initialized
for(int y=0;y<map.length;y++) { //Loop through all boxes
for(int x=0;x<map[y].length;y++) { //Loop through all boxes
map[y][x] = existingMap[y][x]; //Update the map
}
}
tileSheet = LoadTileSheet("D:/ICS3U1/EvilMario/images/tilemap.gif"); //Load the tilesheet
}
public TileLayer(int width, int height) {
map = new int[height][width];
}
public static TileLayer FromFile(String fileName) {
TileLayer layer = null;
ArrayList<ArrayList<Integer>> tempLayout = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
String currentLine;
while((currentLine = br.readLine()) !=null) {
if(currentLine.isEmpty())
continue;
ArrayList<Integer> row = new ArrayList<>();
String[] values = currentLine.trim().split(" ");
for(String string: values) {
if(!string.isEmpty()) {
int id = Integer.parseInt(string);
row.add(id);
}
}
tempLayout.add(row);
}
} catch(IOException e) {
System.out.println("ERROR");
}
int width = tempLayout.get(0).size();
int height = tempLayout.size();
layer = new TileLayer(width,height);
for(int y=0;y<height;y++) {
for(int x=0;x<width;x++) {
layer.map[y][x] = tempLayout.get(y).get(x);
}
}
layer.tileSheet = layer.LoadTileSheet("D:/ICS3U1/EvilMario/images/tilemap.gif");
return layer;
}
public BufferedImage LoadTileSheet(String fileName) {
BufferedImage img = null;
try {
img = ImageIO.read(new File(fileName));
} catch(Exception e) {
System.out.println("Could not load image");
}
return img;
}
int scale = 2;
public void DrawLayer(Graphics g, int position) {
for(int y=0;y<map.length;y++) {
for(int x=0;x<map[y].length;x++) {
int index = map[y][x];
int yOffset = 0;
if(index>(tileSheet.getWidth() / Engine.TILE_WIDTH) -1) {
yOffset++;
index = index - (tileSheet.getWidth() / Engine.TILE_WIDTH);
}
g.drawImage(tileSheet,
((x * Engine.TILE_WIDTH)*scale)+position,
((y * Engine.TILE_HEIGHT)*scale),
(((x * Engine.TILE_WIDTH) + Engine.TILE_WIDTH )*scale)+position,
(((y * Engine.TILE_HEIGHT) + Engine.TILE_HEIGHT)*scale),
index * Engine.TILE_WIDTH,
yOffset * Engine.TILE_HEIGHT,
(index * Engine.TILE_WIDTH) + Engine.TILE_WIDTH,
(yOffset * Engine.TILE_HEIGHT) + Engine.TILE_HEIGHT,
null
);
}
}
}
}
Engine.java (Not as important)(Simple variables for tile sizes)
package EvilMario;
public class Engine {
public static final int TILE_WIDTH = 16;
public static final int TILE_HEIGHT = 16;
}
If you need other pieces of code, just ask for them. I am not asking you to give me a specific answer to the question but simply a method that would work with my following code.
A specific answer would be nice though :)
I also believe the answer to this question will be useful to others because this method was explained in a popular java 2d game tutorial video(They never showed hit detection).
Methods I tried:
Creating a new java file called HitDetectionLayer with the exact code in TileLayer.java that stored positions in arrays. It failed :(
Ok, I'm not entirely sure what you are doing, if you throw up some images it would be more clear.
At any rate, 'hit detection' aka collision detection is a very complex topic, but it depends on what you want to do. If you want everything to be boxes or circles, then it is quite easy. If however you want things to rotate or you want collision for complex shapes it becomes extreme difficult.
Most games use circles or spheres for collision. You put the majority of your graphics (it may not fit perfectly either leaving part of your images in or out of the circle but that's life). Now lets say you have your mario sprite and one of those turtles. Well, you have circles around them both and once the circles touch you trigger your event.
The math for this is very easy because circles are by definition a perimeter around a constant length. Look at this:
You probably already know this, and it may seem obvious, but if you think about it this is what a circle really is: a consistent length in every fathomable direction. The directions are measured in degrees and from there you move on to trigonometry but you don't need that. What you need is coordinance aka vectors. So look at this:
All you need to determine circle collision is the distance between the circles. No matter what angle the circles collide from it does not matter because the distances from the circle's centre are consistent all the way around. Even if the circles are different sizes, it doesn't matter, just account for the radii difference.
Too compute all of this, you would write a method like this:
public boolean testDistanceBetween( float radius1, float radius2,
float x1, float x2, float y1, float y2 ){
double distanceBetween = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
if(distanceBetween < (radius1+radius2) ){
return true;
}
return false;
}
The moral of the story is that circles are just good that way. If you want to do rectangle collision you take the bottom-left and top right point and you test if other rectangles are in between those points. This should be pretty straight forward, each point is a vector, each rectangle has 4 points. If any of the 4 points of one rectangle are between points on the other rectangle, there is collision.
You can use this system to handle ground and walls also. For example, if ground is at Y=300, then if your sprite's y coordinance are == 300, you suspend your gravity.
The main thing I wanted to explain is that if you intend to have rotating rectangles or polygons and you want to detect collision on them... good luck. It can be done yes, but you should understand you are implementing complex physics, especially when/if you implement gravity.
So my answer is cautionary: there is NO easy way to detect collision of rotating rectangles or polygons. Circles and static rectangles are the limits. If you really want to do rotating rectangles/polygons get a physics engine. Box2d is pretty good and has a Java version Jbox2d.
I am trying to diffuse a color in java Draw (which doesn't have the capability to diffuse normally) but I ran into an error and I can't seem to spot it.
The way I went about diffusing was by writing a small script that would draw my shape hundreds of times, each time smaller and slightly varying in color. This is my snippet:
import javax.swing.*;
import java.awt.*;
public class DiffuseDraw extends JFrame
{
//set size of window here
final int length = 350;
final int height = 370;
public DiffuseDraw()
{
super("Graphics Project Window");
Container container = getContentPane();
setBackground(new Color(0,0,0));
setSize(length, height);
setVisible(true);
}
// my problem comes here:
public void paint(Graphics g)
{
Draw.fillRectangle(g,0,0,length,height,new Color(19,24,32));
int rad = 325; // size of the biggest circle
float floatGreen = 0; // Color components for black
float floatBlue = 0;
float floatRed = 0;
int counter = 0; // the counter
while (counter < 290) {
rad = rad - 1; // Here we shrink the by a small incriment
floatRed = floatRed + 87/290; //red component slowly goes brighter
floatBlue = floatBlue + 178/290; // blue component slowly goes brighter
floatGreen = floatGreen + 211/290; // green component slowly goes brighter
int intRed = (int)Math.round(floatRed);
int intBlue = (int)Math.round(floatBlue);
int intGreen = (int)Math.round(floatGreen);
Draw.fillCircle(g,173,307,rad,new Color(intRed,intBlue,intGreen));
counter = counter + 1;
}
}
public static void main(String args[]) {
DiffuseDraw prog = new DiffuseDraw();
prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
When I compile and run, I only get a black screen. I am guessing that the problem is coming from the colors not changing. The number I am adding the float red blue and green by came from me wanting to diffuse a type of blue, so I took the the brightest color of blue that would appear and divided it by 290, the number of times the loop would run.
Instead of
87/290, 178/290, and 211/290,
try using
(float)87/290, (float)178/290, and (float)211/290.
That will, at least, add some color to the window- the problem is that by default, a number like 87/290 will be evaluated to 0; casting it to a float will give the desired result of 0.3 instead.
I need to create a class that displays 10 rectangles on the canvas, each with a random color and position. When it reaches 11, the first rectangle is replaced with a new random color and position. 12th rect replaces the 2nd box, and so on. I am using the acm.jar for this, http://jtf.acm.org/javadoc/student/index.html.
import acm.graphics.*;
import acm.program.*;
import java.awt.Color;
import java.util.Random;
public class Rect extends GraphicsProgram
{
public void run()
{
final int width = 800;
final int height = 600;
final int boxWidth = 50;
final int maxBoxes = 10;
this.setSize(width, height);
Random random = new Random();
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
GRect r = new GRect(x, y, boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
this.add(r);
this.pause(100);
}
}
}
I already figured out how to make the colors random, I cant figure out how I will substitute the boxes with the old ones.
EDIT:::--------------------------------------------------------------------------------
I did manage to get it working with the help of the guys below. Here is what the new for loop looks like:
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
GRect r = new GRect(boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
add(r, x, y);
int n = getElementCount();
if (n>maxBoxes)
{
remove(getElement(0));
}
this.pause(100);
}
One thing I dont understand is why the remove(getElement(0)) works,, how does the element change its index once one is removed? If I have 10 elements 0-9, and I remove element(0) why does the other elements change its index?
This really looks like homework , so I won't do it for you but give some clues.
You can use the getElementCount() method to know the current number of rectangles in your frame.
Create a list of GObjects, and populate it with your rectangles as you create them.
Once you reach ten, the process becomes
remove rectangle from screen using remove(GObject gobj)
remove first element, add to end of list.
And here you are :)
You need to store the list of rectangles drawn so far. Every time you add a new rectangle, if the list is already 10 rectangles long, remove the first rectangle and add a new one. Then you need to redraw ALL rectangles every time you refresh the display, using double buffering to prevent screen flickering.