I'm new to java and I am trying to make a row of squares using Java that I can use later as a border.
When I run the program the squares appear but either move across the window or disappear.
This is the code below:
public int tileSize = 25;
public int row;
public int x = 0, y = 0;
public void draw(Graphics g){
`g.setColor(new Color(38, 127, 0));`
g.fillRect(0, 0, 650, 550);
g.setColor(Color.black);
for(int row = 0; row <= 650; row++) {
g.drawRect(x, y, tileSize, tileSize);
row = row + 25;
x = x + 25;
y = y + 0;
}
}
There are multiple things wrong with your code.
First of all
When you iterate through your for loop, row get incremented at two different places: at row = row + 25; and when the for loops enters its next iteration (by i++). That way your row isn't 651 - because you used <= instead of <. I suggest you just get rid of row = row + 25;
Second
You declare your x globally and only increment it. That way your row gets shifted each time your Frame gets redrawn. You could declare your x locally in the for-loop, or you could set x back to zero after or before the for-loop.
So a solution could be:
public int tileSize = 25;
public int y = 0; // y doesn't gets changed
public int x = 0;
g.setColor(Color.BLACK);
for(int row = 0; row < 650; row++) {
g.drawRect(x, y, tileSize, tileSize);
x += 25;
}
x = 0;
Related
So I found Conway's Game of Life recently, so I'm naturally addicted. It hasn't taken me long to find out that I am very limited by my computer's CPU. I've also found that, for whatever reason, I cannot add a JPanel with many JComponents to a JFrame.
So I have a loop that adds 86,400 JLabels to a JPanel, which happens in ~1 second, but adding this JPanel to a JFrame takes ~2 minutes.
I understand I could use java.awt.Graphics, but I'd prefer to use JLabels because they automatically resize.
So my question: Why does this take so long to add the JPanel to the JFrame, and how do I fix it?
Using java.awt.Graphics, I was able to remove this long period of lag:
public void render(int[][] cells) {
int cellHeight = image.getHeight() / cells.length;
int cellWidth = image.getWidth() / cells[0].length;
for (int y = 0; y < cells.length; y++) {
for (int x = 0; x < cells[y].length; x++) {
int col = colors[cells[y][x]].getRGB();
fillSquare(x * (cellWidth), y * (cellHeight), cellWidth, cellHeight, col);
}
}
}
// Could pass a java.awt.Rectangle here
private void fillSquare(int xPos, int yPos, int width, int height, int col) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[(x + xPos) + (y + yPos) * image.getWidth()] = col;
}
}
}
#Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
For this method, it's important to keep the JFrame's size proportional to the number of cells, this way there is no unused space within the JFrame.
i'm testing a code in Processing with Java for my school.
I try to create a game and i have a problem to draw an eclipse or to load a picture.
I think the picture or the eclipse is drawing under my game board .. I don't know how to solved it.
I have a txt file for the game board ( by level).
An example :
110000000
000000031
000000000
100000000
000000000
000000000
200000001
Please, can you help me
thank you
int cols, rows, w, x, y,level;
String lines[];
PImage flag;
void setup() {
size(460,360);
cols = 9;
rows = 7;
w = 50 ;
x= 0;
y = 0;
level = 1;
lines = loadStrings("../../data/niveau"+level+".iwk");
flag = loadImage("../../data/flag.png");
ellipseMode(CORNER);
}
void draw() {
String lines[]= loadStrings("../../data/niveau"+level+".iwk");
loadCard(cols,rows,w,x,y,lines,flag);
}
void loadCard(int cols, int rows, int w, int x,int y,String lines[],PImage flag) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if(lines[i].charAt(j) == '1'){
fill(156, 158, 162);
}
else if(lines[i].charAt(j) == '2'){
fill(225, 169, 26) ;
ellipse(x,y,w/2,w/2);
}
else if(lines[i].charAt(j) == '3'){
image(flag,x,y,w/2,w/2);
}else {
fill(23, 159, 215);
}
rect(x, y, w, w);
x = x + w ;
}
y = y + w ;
x = 0 ;
}
}
It is indeed drawn under the game board.
Check the loadCard function. First the ellipse / image is draw, then a rect is draw with the same x / y, ergo on top of it.
A modified your code a little, it should show the ellipses / image
void loadCard(int cols, int rows, int w, int x,int y,String lines[],PImage flag) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
//draw default so ellipse / img has a background
fill(23, 159, 215);
rect(x, y, w, w);
//draw other cases on top of default
if(lines[i].charAt(j) == '1'){
fill(156, 158, 162);
rect(x, y, w, w);
}
else if(lines[i].charAt(j) == '2'){
fill(225, 169, 26) ;
ellipse(x,y,w/2,w/2);
}
else if(lines[i].charAt(j) == '3'){
image(flag,x,y,w/2,w/2);
}
x = x + w ;
}
y = y + w ;
x = 0 ;
}
}
Since you're learning, allow me to give you 2 tips:
loadStrings() needs to happen only once per level. You should not put it in draw(), because draw() is called every frame. It is already called in setup, that is fine for now. Eventually you can put it in a separate function, and call this function at the beginning of a new level.
If you use a double for loop to draw a game board, you can use the iterators (int i and int j) as x/y variables. Instead of rect(x, y, w, w); you can use rect(i*w, j*w, w, w);. This way you'll have fewer variables to manage.
How does one go about coloring an individual rectangle when it's hovered over? The specific method used below really doesn't give me any ideas on how to solve this problem. It generates a grid in the window using individual rectangles. How would it be possible to listen for mouseX and mouseY and color one rectangle without disrupting this code? Thanks.
int cols,rows;
int scl = 20;
int gridsize = 0;
void setup(){
size(400,400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
//mouseX, mouseY
background(r,g,b);
for (int x = 0; x < cols; x++){
for (int y = 0; y < rows; y++){
stroke(55);
//noFill();
fill(50,50,50);
rect(x*scl,y*scl,scl,scl);
}
}
}
For reference, I am using Processing 3 for Java.
You can always check if the mouse is within the bounds of a rectangle:
you know the mouseX,mouseY values
you know the x,y and size of each box
if mouseX is within x and x+size and mouseY is within y and y+size you're over a box.
Here's the above applied to your code (if condition formatting for easy visibility, feel free to re-format):
int cols, rows;
int scl = 20;
int gridsize = 0;
void setup() {
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
//mouseX, mouseY
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if(
(mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)
){
fill(90);
}else{
fill(50);
}
rect(xpos, ypos, scl, scl);
}
}
}
For more info also checkout the Processing Button example
George's answer works nicely for this scenario, but there is another, a little more complex way too if might want to go Object Oriented here. For this little example, you could have a Grid class which holds and manages an array of Cell objects. Or you can just skip the Grid class and manage the Cells in your main sketch. You could give the Cell class a function to render itself and you could give each cell a color and a size too, it's totally up to you. Also, it could have a function which tells you if your mouse is over it and a function to change its color. A skeleton would look like this:
class Cell {
float x,y;
float length, breadth;
color col;
Cell(float x, float y) {
this.x = x;
this.y = y;
length = 10;
breadth = 10;
col = color(0);
}
void render() {
fill(col);
rect(x, y, length, breadth);
}
void setColor(color col) {
this.col = col;
}
boolean mouseOver() {
if(mouseX > x && mouseX < x+length) {
if(mouseY > y && mouseY < y+breadth) {
return true;
}
}
return false;
}
Now you could just use this class and its methods in your main sketch to find the cell with the mouse over it and call setColor on it to change its color.
George's answer is correct. I upvoted it and I believe you should mark it as the correct answer. Yushi's answer is basically just George's answer, moved into a class.
They both use point-rectangle collision detection, which checks whether the point is inside the rectangle. You just check each rectangle against the point (in your case the mouse position), and that allows you to determine which rectangle the mouse is in. This will work even if you have a bunch of rectangles of different shapes, and will even work with overlapping rectangles.
The other way to do it is using grid-based collision detection which takes advantage of the fact that you have a bunch of evenly spaced rectangles that don't overlap. You'd just use division to figure out which cell the mouse was in, and then you'd convert that cell to coordinates, and you'd use those coordinates to draw the rectangle. That might sound confusing, but it looks like this:
int cols;
int rows;
int scl = 20;
void setup() {
size(400, 400);
cols = width / scl;
rows = height / scl;
}
void draw() {
background(100);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
stroke(55);
fill(50, 50, 50);
rect(x*scl, y*scl, scl, scl);
}
}
int hoveredRectColX = int(mouseX / scl);
int hoveredRectRowY = int(mouseY / scl);
float rectX = hoveredRectColX * scl;
float rectY = hoveredRectRowY * scl;
fill(255, 0, 0);
rect(rectX, rectY, scl, scl);
}
The last block of code is the meat and potatoes. First it figures out which row and column the mouse is in, then figures out the position of that cell, and uses that to draw a rectangle. If this doesn't make sense, the best thing you can do is get out a piece of paper and a pencil and draw a bunch of examples to see the pattern of what's going on.
Shameless self-promotion: I wrote a tutorial on collision detection in Processing, including both point-rectangle and grid-based collision detection, available here.
I have a script that draws a game board of hexagon shaped tiles. I want to add an InnerShadow effect to each tile but I also want each tile to have a semi-transparent background. The normal shadow should be on top of the transparent background(if that makes sense). For some reason unknown to me, the shadow shows up as artifacts. If I remove setFill from the tile, it automatically has a black background. In the screenshot, the little white dots are what I am referring to as artifacts. What am I doing wrong?
Update
After further investigation, I realized that the white dots are actually part of the image. But the problem of the InnerShadow not showing up remains. So I have changed the title of the question. How can I add an InnerShadow and a transparent background to my polygon?
private void drawHexGridLoop(GraphicsContext g, Point origin, int size, int radius, int padding, boolean blank) {
String rsrc;
double ang30 = Math.toRadians(30);
double xOff = Math.cos(ang30) * (radius + padding);
double yOff = Math.sin(ang30) * (radius + padding);
int half = size / 2;
int i = 0;
for (int row = 0; row < size; row++) {
int cols = size - java.lang.Math.abs(row - half);
for (int col = 0; col < cols; col++) {
int xLbl = row < half ? col - row : col - half;
int yLbl = row - half;
int x = (int) (origin.x + xOff * (col * 2 + 1 - cols));
int y = (int) (origin.y + yOff * (row - half) * 3);
Hexagon hex = new Hexagon(x, y, radius);
int diceNum = diceSpaces.get(i);
if(!blank){
rsrc = resources.get(i);
} else {
rsrc = null;
}
//hex.draw(g, x, y, diceNum, rsrc);
Polygon tile = new Polygon();
for(int p = 0; p < hex.xpoints.length; p++){
double xpoint = hex.xpoints[p];
tile.getPoints().add(xpoint);
double ypoint = hex.ypoints[p];
tile.getPoints().add(ypoint);
}
tile.setFill(Color.web("rgba(255, 255, 255, 0.3)"));
InnerShadow innerShadow = new InnerShadow(5, Color.WHITE);
innerShadow.setOffsetX(4);
innerShadow.setOffsetY(4);
tile.setEffect(innerShadow);
wrapperPane.getChildren().add(tile);
tiles[i] = new Tile(i, xLbl, yLbl, rsrc, diceSpaces.get(i), hex.xpoints, hex.ypoints);
i++;
}
}
}
I am new with programming. I am not sure how to put an object in the center of a frame. This is how far i got:
public class LetSee extends JPanel {
public void paintComponent(Graphics g) {
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x,y; // Top-left corner of square
for ( row = 0; row < 5; row++ ) {
for ( col = 0; col < 5; col++) {
x = col * 60;
y = row * 60;
if ( (row % 2) == (col % 2) )
g.drawRect(x, y, 60, 60);
else
g.drawRect(x, y, 60, 60);
}
} // end for row
}
}
public class LetSeeFrame extends JFrame {
public LetSeeFrame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1900, 1000);
setVisible(true);
LetSee let = new LetSee();
let.setLayout(new BorderLayout());
add(let,BorderLayout.CENTER);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
LetSeeFrame l = new LetSeeFrame();
}
}
Actually your panel is centered in the frame, but what it draws isn't.
You should make use of the width and the height of the JPanel to center the drawing .
Also put your sizes and numbers into variables, it is less error-prone when you use them several times in your code .
Finally as #MadProgrammer said in the comments :
Don't forget to call super.paintComponent before you doing any custom
painting, strange things will start doing wrong if you don't. Also
paintComponent doesn't need to be public, no one should ever call it
directly
import java.awt.Graphics;
import javax.swing.JPanel;
public class LetSee extends JPanel {
public void paintComponent(final Graphics g) {
super.paintComponent(g);
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x, y; // Top-left corner of square
int maxRows = 5;
int maxCols = 5;
int rectWidth = 60;
int rectHeight = 60;
int maxDrawWidth = rectWidth * maxCols;
int maxDrawHeight = rectHeight * maxRows;
// this is for centering :
int baseX = (getWidth() - maxDrawWidth) / 2;
int baseY = (getHeight() - maxDrawHeight) / 2;
for (row = 0; row < maxRows; row++) {
for (col = 0; col < maxCols; col++) {
x = col * rectWidth;
y = row * rectHeight;
if ((row % 2) == (col % 2)) {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
} else {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
}
}
} // end for row
}
}