I have to randomly generate a cityscape with 3 layered functions in processing. I'm doing so by drawing each floor in a loop that runs until a random integer, and doing the same thing with floors per building. Currently, the floors are initially randomly generated, but then they eventually fill out to the maximum of the random function. How do I get it so they stay random? Thanks, code is below.
int boxX = 0;
int boxY = 479;
void setup() {
size(1000, 500);
background(255);
frameRate(10);
}
void draw() {
for (int i = 0; i < 8; i++) {
building(boxX, boxY);
translate(150, 0);
}
}
void room(int boxX, int boxY) {
rect(boxX, boxY, 20, 20);
}
void floor(int boxX, int boxY) {
int randomNum = (int)random(3, 5);
for (int i=0; i<= randomNum; i++) {
room(boxX, boxY);
boxX += 20;
}
}
void building(int boxX, int boxY) {
int randomNum = int(random(10, 20));
for (int i = 0; i < randomNum; i++) {
floor(boxX, boxY);
boxY -= 20;
}
}
The problem is that you're generating a random cityscape every single frame, but you're never clearing out old frames. That means that your new frames are just drawn right on top of your old frames.
To better see what I'm talking about, clear out the old frames by adding a call to background() as the first line in your draw() function:
void draw() {
background(200);
for (int i = 0; i < 8; i++) {
building(boxX, boxY);
translate(150, 0);
}
}
You need to take a step back and ask yourself exactly what you want to happen. Do you want to generate a new cityscape every frame? If so leave the call to background() in. Do you just want to generate a single cityscape? If so then call noLoop() to prevent the draw() function from being called more than once, or store your cityscape in a data structure that you redraw every frame instead of regenerating.
Related
I want to make random rectangles on Processing. So far, I used for loops for making window size rectangle but I can't figure out how to make only 10 rectangle randomly. Here is my sample code for you:
void setup()
{
size(400, 400);
}
void draw()
{
background(0); // Black Background
stroke(255); // White lines
for (int j = 0; j <= height; j += 40)
{
for (int i = 0; i < width; i += 40)
{
fill(0);
rect(i, j, 40, 40);
}
}
}
It shows 100 black rectangles but I want to see only 10 black rectangles. For example: The first line will get random 1 rectangle, second line will get 2 , third line will get 1 and it goes till the 10.
There are multiple ways to solve this fun homework/exercise.
First thing is drawing the right number of boxes per column:
void setup()
{
size(400, 400);
background(0); // Black Background
fill(0);
stroke(255); // White lines
int boxSize = 40;
int maxBoxes = 1;
for (int j = 0; j <= height; j += boxSize)
{
// box count per row
int boxCount = 0;
for (int i = 0; i < width; i += boxSize)
{
// only draw the max number of boxes
if(boxCount < maxBoxes){
rect(i, j, 40, 40);
// increment per row box count
boxCount++;
}
}
// increment max boxes per box
maxBoxes++;
}
}
Secondly the positions for the drawn boxes per column need to be randomized, but ideally not overlap. One option is to split the full solution space to sections: each section having it's own range of positions so it won't overlap the next.
void setup()
{
size(400, 400);
background(0); // Black Background
fill(0);
stroke(255); // White lines
int boxSize = 40;
int maxBoxes = 1;
int totalBoxes = width / boxSize;
for (int j = 0; j <= height; j += boxSize)
{
// box count per row
int boxCount = 0;
// a list of box indices of where to draw a box (as opposed
int[] randomXIndices = new int[maxBoxes];
// how many index ranges to span per row
int indexRangePerBox = totalBoxes / maxBoxes;
// for each random index
for(int k = 0 ; k < maxBoxes; k++)
{
// pre-calculate which random index to select
// using separate ranges per box to avoid overlaps
randomXIndices[k] = (int)random(indexRangePerBox * k, indexRangePerBox * (k + 1));
}
for (int i = 0; i < width; i += boxSize)
{
// only draw the max number of boxes
if(boxCount < maxBoxes)
{
int randomX = randomXIndices[boxCount] * boxSize;
rect(randomX, j, 40, 40);
// increment per row box count
boxCount++;
}
}
// increment max boxes per box
maxBoxes++;
}
}
void draw(){
}
void mousePressed(){
setup();
}
Click to reset. Notice that the bottom rows almost always look the same:
there is less wiggle room to pick a random position
random() is a rough pseudo-random number generator, but there are better ones out there like randomGaussian(), noise(), etc.
overall there are other strategies to explore picking random positions and avoiding overlaps
Live demo bellow:
function setup()
{
createCanvas(400, 400);
reset();
// reset once per second
setInterval(reset, 1000);
}
function reset(){
background(0); // Black Background
fill(0);
stroke(255); // White lines
var boxSize = 40;
var maxBoxes = 1;
var totalBoxes = width / boxSize;
for (var j = 0; j <= height; j += boxSize)
{
// box count per row
var boxCount = 0;
// a list of box indices of where to draw a box (as opposed
var randomXIndices = new Array(maxBoxes);
// how many index ranges to span per row
var indexRangePerBox = totalBoxes / maxBoxes;
// for each random index
for(var k = 0 ; k < maxBoxes; k++)
{
// pre-calculate which random index to select
// using separate ranges per box to avoid overlaps
randomXIndices[k] = floor(random(indexRangePerBox * k, indexRangePerBox * (k + 1)));
}
for (var i = 0; i < width; i += boxSize)
{
// only draw the max number of boxes
if(boxCount < maxBoxes)
{
var randomX = randomXIndices[boxCount] * boxSize;
rect(randomX, j, 40, 40);
// increment per row box count
boxCount++;
}
}
// increment max boxes per box
maxBoxes++;
}
}
function draw(){
}
function mousePressed(){
reset();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
I am making a programm that should display 10 images next to each other with the loadImages(int i) function and the output to that is in the void setup() function , but the problem is it only loads up the 10th picture and not the others before that (1-9). I know it is probably only a minor modification to the code but i dont get it. Thanks in advance!
import java.util.Random;
Random Random = new Random();
PImage img;
int[] cakes = new int[10];
int W, H;
void setup() {
for( int i=0 ;i<=cakes.length;i++){
img =loadImages(i);
}
W = img.width;
H = img.height;
surface.setSize(10 * W, 2 * H);
}
void mouseClicked() {
scramble(cakes);
}
PImage loadImages(int i) {
return loadImage("images/" + i + "_128x128.png");
}
void draw() {
background(255);
image(img, 0, 0);
}
void scramble(int[] a) {
for (int i = 0; i < a.length; i++) {
int rd0 = Random.nextInt(i+1);
int rd1 = Random.nextInt(i+1);
int temp = a[rd0];
a[rd0] = a[rd1];
a[rd1] = temp;
}
}
EDIT: as pointed out by #Rabbid76, it would be MUCH BETTER to avoid loading the image at every iteration of the draw loop. Consider this carefully.
You can get your images in a loop. As you guessed, it's only a minor modification:
void draw() {
background(255);
for (int i = 0; i < 10; i++) {
image(loadImages(i), i*128, 0); // i * 128 to draw the image side by side, or else you'll only see the last one you draw
}
}
Have fun!
You've to create an array of images:
PImage[] img = new PImage[10];
Load the images to the array:
void setup() {
for( int i=0 ;i<img .length;i++){
img[i] = loadImages(i);
}
// [...]
}
Finally draw the array of images. e.g.:
void draw() {
background(255);
for( int i=0 ;i < img.length; i++){
image(img[i], i*W, 0);
}
}
I am trying to make a simple version of Conway's Game of Life where the computer generates a grid of rectangles and fills in the rectangles that represent "live" cells. The problem I am having is that I cannot get the grid to clear after the first pattern, so all the patterns are generated on the same grid and it looks like a big blob of colored rectangles.
Here is my code:
public class GameofLife {
static JPanel panel;
static JFrame frame;
public static void main(String[] args) throws InterruptedException{
int [][] array = new int [17][17];
/*
* Set the pattern for Conway's Game of Life by manipulating the array below.
*/
array[2][4]=1;
array[2][5]=1;
array[2][6]=1;
panel = new JPanel();
Dimension dim = new Dimension(400,400);
panel.setPreferredSize(dim);
frame = new JFrame();
frame.setSize(1000, 500);
Container contentPane = frame.getContentPane();
contentPane.add(panel);
frame.setVisible(true);
/*
* Runs the Game of Life simulation "a" number of times.
*/
int [][] end = new int [array.length][array[0].length];
int a=0;
while(a<4){
for(int i=1; i<=array.length-2; i++)
{
for(int j=1; j<=array[0].length-2; j++)
{
int counter = surround(array,i,j);
if(array[i][j]==1 && counter<=2)
{
end[i][j]=0;
}
if(array[i][j]==1 && counter==3)
{
end[i][j]=1;
}
if(array[i][j]==1 && counter>4)
{
end[i][j]=0;
}
if(array[i][j]==0 && counter==3)
{
end[i][j]=1;
}
if(array[i][j]==1 && counter==4)
{
end[i][j]=1;
}
}
}
Graphics g = panel.getGraphics();
Graphics(array,g);
a++;
for(int i=0; i<array.length; i++)
{
for(int j=0; j<array[0].length; j++)
{
array[i][j]=end[i][j];
end[i][j]=0;
}
}
Thread.sleep(1000);
g.dispose();
}
}
public static int surround(int[][] initial, int i, int j){
int[][] surrounding = {{initial[i-1][j-1],initial[i-1][j],initial[i-1][j+1]},
{initial[i][j-1],initial[i][j],initial[i][j+1]},
{initial[i+1][j-1],initial[i+1][j],initial[i+1][j+1]}};
int counter = 0;
for(int a=0; a<=2; a++)
{
for(int b=0; b<=2; b++)
{
if(surrounding[a][b]==1)
{
counter ++;
}
}
}
return counter;
}
public static void Graphics(int[][] array, Graphics g)
{
int BOX_DIM=10;
for(int i=0; i<array.length; i++)
{
for(int j=0; j<array[0].length; j++)
{
g.drawRect(i*BOX_DIM, j*BOX_DIM, 10,10);
g.setColor(Color.BLACK);
if(array[i][j]==1)
{
g.fillRect(i*BOX_DIM, j*BOX_DIM, 10, 10);
}
}
}
}
}
Any help is much appreciated!
You need to draw rectangles for both "alive" and "dead" cells but color them differently. Live cells could be black and dead cells white but if you don't redraw every cell during every iteration you'll run into the issue you've described. That being said...you seem to have answered your own question.
You COULD fix this immediate concern by clearing grid at the top of the Graphics() function:
g.setColor(Color.??); // Choose desired background color here
g.fillRect( 0, 0, array.length * BOX_DIM, array[0].length * BOX_DIM);
BUT, consider that your approach is fighting against the natural way of handling graphics in Java. Any time your window gets clipped, it may not repaint in a timely manner.
You might want to consider sub-classing JPanel and overriding its onPaint() method, then invalidating the panel whenever the data model changes.
Ok so i am creating a Breakout game and i need to create a method that creates rectangle objects for each of the bricks so i can implement hit detection, i already have a method so the bricks can be drawn out like this:
public void drawBricks(Graphics g)
{
g.setColor(brickColor);
for(int i = 0; i<10; i++)
{
for(int a = 0; a<121; a+=30)
{
g.fillRect(x+(width*i)+(spacer*i), y +a, width, height);
// spacer = 10, x and y = 5, width = 50, height = 20, if you need this...
}
}
}
Now to the part I cant figure out. I want to create rectangle objects with the exact corresponding coordinates as drawn above and add them to an multidimensional array, but i need the y to start at 5 and increment by 30 for each row at a time. This is what i have so far:
* Also I'm not sure if this is actually possible or not so let me know if you have an idea for another way i could do it.
public void setBricks()
{
for(int i= 0; i<10;i++)
{
for(int a=0; a<5; a++)
{
bricks[i][a] = new Rectangle(x+(width*i)+(spacer*i), y +a, width, height);
} // any ideas how to get each y ^ coordinate equal to the one above
} // i need the int variables to stay at 10 and 5 because of the size of the array.
}
Well, if you want y to start at 5 and increment by 30, use 5+a*30 :
public void setBricks()
{
for(int i= 0; i<10;i++)
{
for(int a=0; a<5; a++)
{
bricks[i][a] = new Rectangle(x+(width*i)+(spacer*i), 5 + a*30, width, height);
}
}
}
What I'm trying to accomplish is adding 1 to the all the numbers in shipX array list, question is, how? I want to do this when the method move() is called, but how would I make this happen, as I'm new with arrays
class Ship
{
public void paint(Graphics g)
{
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
}
}
To start, you will have to move your arrays for points outside the local scope of paint() and into the class so that move() has access to the current values. You would increment in the move() method and call whatever routine you use to redraw your component.
class Ship
{
//make your polygon points members of the class
//so that you can have state that changes
//instead of declaring them in the paint method
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
//set these to the amount you want per update. They can even be negative
int velocityX = 1;
int velocityY = 1;
public void paint(Graphics g)
{
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
//add 1 to each value in shipX
for (int i=0; i<shipX.length; i++)
{
shipX[i] += velocityX;
}
//add 1 to each value in shipY
for (int i=0; i<shipY.length;i++)
{
shipY[i] += velocityY;
}
//call whatever you use to force a repaint
//normally I would assume your class extended
//javax.swing.JComponent, but you don't show it in your code
//if so, just uncomment:
//this.repaint();
}
}
Although I should point out that the repaint() method on JComponent does need to be called from the correct Swing thread, as pointed out in this answer.
If you are also trying to animate the movement, you can check out the Java Tutorial on Swing timers to call your move() method on a schedule. You could also use an ActionListener on a button to either control the Timer or on a button to move the object manually once per click.
All you have to do is iterate through the array and modify the value of each index:
for (int i = 0; i < shipX.length; i++)
{
shipX[i]++;
}
Increase the numbers one by one...
for (i=0; i<shipX.length; i++)
{
shipX[i]++; // same as shipX[i] = shipX[i] +1
}
for (i=0; i<shipY.length;i++)
{
shipY[i]++;
}