I am creating objects on a line in a window created by this piece of code:
void createTurtles() {
int nrTurtles = Keyboard.nextInt("Set amount of turtles: ");
w = new GraphicsWindow(500, 300);
drawLinez();
for (int k = 1; k <= nrTurtles; k++) {
Turtle t = new Turtle(w, 50, 50 + k*10);
t.right(90);
t.setSpeed(100);
t.penDown();
turtles.add(t);
}
}
This codeline:
Turtle t = new Turtle(w, 50, 50 + k*10);
Creates one turtle at the time. Right now i have set that the turtles will have the Y coordinat of 50, and the X coordinat of 50+k*10. This is because the line starts at the X coordinat of 50 and stops at the X coordinat of 250.
Now what i want is, based on the nr of turtles created (user inputs this), i want the turtles to be spread on this line evenly. How to do it? It has do to with the line that i wrote and maybe the k value or the 10.
The line is illustrated in the picture (see link below), its the red line, that the number of turtles are created at.
Devide the height - 100 of the window by the number of turtles and you will have your distanceBetweenTurles:
int nrTurtles = Keyboard.nextInt("Set amount of turtles: ");
int height = 300;
w = new GraphicsWindow(500, height);
drawLinez();
double distanceBetweenTurles = (height - 100.0) / nrTurtles;
for (int k = 1; k <= nrTurtles; k++) {
Turtle t = new Turtle(w, 50, 50 + (int) (k * distanceBetweenTurtles));
t.right(90);
t.setSpeed(100);
t.penDown();
turtles.add(t);
}
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>
The assignment is to draw chips on a supposed cookie at random points while counting each chip and storing the coordinates so that each chip doesn't move. Each chip should be a different color and initiated on a mouse press.
I've tried to put the coordinates into an array, multiple arrays a single array list and tried to use if and for loops. The results before were that it would generate a single chip of a different colour each click (sort of because sometimes the random number generated is outside of my specified range). After using and looping through multiple array lists the current behaviour is that it generates a grid and the count is exponentially growing with each click, some points have a lot of overlap and the chips in the grid all ave one colour i.e. The last to be assigned
//Put graphics code here
public void draw(Graphics g){
ArrayList coordinates = new ArrayList();
col1= generator.nextInt(256) + 0;
col2= generator.nextInt(256) + 0;
col3= generator.nextInt(256) + 0;
canvasMaxWidth=800;
canvasMaxHeight=600;
canvasMinWidth=400;
canvasMinHeight=200;
int newX = (int) (Math.random() * canvasMaxWidth) + canvasMinWidth;
int newY = (int) (Math.random() * canvasMaxHeight) + canvasMinHeight;
Point point = new Point(newX, newY);
g.setColor(new Color(205,133,63));
g.fillOval(canvasMinWidth,canvasMinHeight,400,400);
for(Point point : coordinates){
if(point.y > 249 && point.y < 549 && point.x > 449 && point.x < 749){
g.setColor(new Color(col1, col2, col3));
g.fillOval(point.x, point.y, 7, 7);
}
}
g.setColor(Color.black);
g.drawString("Number of Sprinkles: "+ count, 100, 80);
}
//Code to respond to a mouse press
public void mousePressed(MouseEvent mouse){
}
The expected result is essentially a speckled disk that counts each speckle on the disk with each speckle not moving.
At present it appears that no point is moving but there's not a lot of randomness to what is happening. the speckles multiply each click vs iterate and form a grid.
ArrayList<Point> coordinates = new ArrayList<Point>();
is much easier to track coordinates rather than using two separate lists. Everything is happening in a grid format because you are using a nested for loop for i and j.
You are currently performing:
if i = 0, 1, 2 and j = 0 , 1, 2
i j
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
so you can see where the grid-like layout is coming from. Using a Point object, you could instead do:
for(Point point : coordinates){
if(point.y > 249 && point.y < 549 && point.x > 449 && point.x < 749){
g.setColor(new Color(col1, col2, col3);
g.fillOval(point.x, point.y, 7, 7);
}
}
I'm unsure why you are using a counter, as it would be performing for the length of the coordinates. If you would like to add randomness, then you can dynamically create values using the Random class.
int colorValue = (int) (Math.random() * 255);
and if you wanted to perform random positions, you could randomly generate them through:
int newX = (int) (Math.random() * (canvasMaxWidth - canvasMinWidth)) + canvasMinWidth;
int newY = (int) (Math.random() * (canvasMaxHeight - canvasMinHeight)) + canvasMinHeight;
Point point = new Point(newX, newY);
Edit with your code:
int newX = (int) (Math.random() * (canvasMaxWidth - canvasMinWidth)) + canvasMinWidth;
int newY = (int) (Math.random() * (canvasMaxHeight - canvasMinHeight)) + canvasMinHeight;
Point point = new Point(newX, newY);
coordinates.add(point);
counter++;
redList.add((int) (Math.random() * 255));
greenList.add((int) (Math.random() * 255));
blueList.add((int) (Math.random() * 255));
g.setColor(new Color(205,133,63));
g.fillOval(canvasMinWidth,canvasMinHeight,400,400);
for(int z = 0; z < coordinates.size(); z++){
if(coordinates.get(z).y > 249 && coordinates.get(z).y < 549 && coordinates.get(z).x > 449 && coordinates.get(z).x < 749){
g.setColor(new Color(redList.get(z).intValue(), greenList.get(z).intValue(), blueList.get(z).intValue()));
g.fillOval(coordinates.get(z).x, coordinates.get(z).y, 7, 7);
}
}
Edit #2: here is a sample of how you would have the static variables
public class myClass{
static ArrayList<Point> coordinates = new ArrayList<Point>();
static ArrayList<Integer> redList = new ArrayList<Integer>();
static ArrayList<Integer> greenList = new ArrayList<Integer>();
static ArrayList<Integer> blueList = new ArrayList<Integer>();
static int counter = 0;
Background Information:
I am writing a program where I am supposed to graph a data set, which is stored in the following file (input file), called "names.txt", using the class DrawingPanel.
This java file allows you to create a panel of a given size, and draw shapes and lines in this panel. The problems I am encountering with my program are unrelated to the specifications and understandings of the class methods.
The data set that I am supposed to graph using this java file is configured in the following way:
[name] [gender] [ranking] [ranking] [ranking] [ranking]....etc for a total of 14 rankings.
Example:
Jane F 98 108 128 116 48 55 47 39 67 202 312 345 436 384
General goal of program:
The user is supposed to input the name and gender they would like to see graphed. The data is then graphed, rankings representing the y axis and time representing the x axis.
My main problem is drawing the lines that compose the graph. The lines of these graphs are drawn with the method:
g.drawLine(x1, y1, x2, y2)
with g representing a Graphics object. Two points are necessary as two endpoints are necessary to create a line.
This for loop is responsible for printing the lines.
for (int j = 0; j < SECTION_WIDTH * DECADES; j += SECTION_WIDTH){
g.setColor(Color.BLACK);
g.drawLine(j, yCoordinate, i + intervalIncrease, yCoordinate2);
g.setColor(Color.RED);
intervalIncrease += SECTION_WIDTH;
g.drawString(intervalLabel, intervalIncrease , yCoordinate);
}
}
SUMMARY OF PROBLEM: The for loop above is the cause of the bugs in my program. The problem is the incorrect printing of the lines that compose the graph. This is caused by incorrect for loop iterations and conditions, which are complicated by the awkward location of the for loop and the fact that two calls of everything are necessary to correctly run the program. Despite guessing-and-checking for several hours, I cannot figure out how to manipulate the loops to make it work.
It is complicated because the drawString method is dependent on the drawLine method variables.
I've tried implementing this into my code but it hasn't worked.
Specific Requirements and Additional Information on DrawingPanel.java:
Please see this (Specification) for specifications on what the graph should look like and other requirements.
An image of what the graph should look like is also provided below.
public static void drawRanks(String line, Graphics g){
int yearIncrease = 0;
int intervalIncrease = 0;
System.out.println(line);
Scanner lineScan = new Scanner(line);
String name = lineScan.next();
String gender = lineScan.next();
for(int i = 0; i < DECADES/2; i++) {
g.setColor(Color.RED);
int rank = lineScan.nextInt();
int rank2 = lineScan.nextInt();
int yCoordinate = rank/2 + 25;
int yCoordinate2 = rank2/2 + 25;
String intervalLabel = name + " " + gender + " " + String.valueOf(rank);
String intervalLabel2 = name + " " + gender + " " + String.valueOf(rank2);
if (rank == 0){
yCoordinate = 525;
}
if (rank2 == 0){
yCoordinate2 = 525;
}
for (int j = 0; j < SECTION_WIDTH * DECADES; j += SECTION_WIDTH){
g.setColor(Color.BLACK);
g.drawLine(j, yCoordinate, i + intervalIncrease, yCoordinate2);
g.setColor(Color.RED);
intervalIncrease += SECTION_WIDTH;
g.drawString(intervalLabel, intervalIncrease , yCoordinate);
}
}
for(int j = 0; j < DECADES; j++) {
g.setColor(Color.BLACK);
g.drawString(String.valueOf(STARTING_YEAR + yearIncrease), SECTION_WIDTH * j, 550);
yearIncrease += 10;
}
for (int k = DECADES * SECTION_WIDTH; k >= 0; k -= SECTION_WIDTH){
g.drawLine(k, 0, k, 550);
}
}
Image of graph produced:
Expected graph:
Please feel free to comment if my explanation is unclear.
Here is where the DrawingPanel class is located, for compilation purposes, if necessary.
DrawingPanel.java
Here is an API for the methods:
DrawingPanel name = new DrawingPanel(width, height);
Graphics g - name.getGraphics();
panel.setBackground(color); - sets panel's background color
g.setColor(color); - sets Graphics pen color (like dipping a brush in paint)
g.drawLine(x1, y2, x2, y2); - a line from points (x1, y1) to (x2, y2)
g.drawString(text, x, y); - the given text with its lower-left corner at (x, y)
Your general idea, that you have to read the ranks in pairs, is wrong. What you have to do is draw a line from the last rank's coordinates to the current rank's coordinates. Here is my version of your method (mind you, I don't have your whole environment so I can't actually test this):
public static void drawRanks(String line, Graphics g){
int yearIncrease = 0;
System.out.println(line);
Scanner lineScan = new Scanner(line);
String name = lineScan.next();
String gender = lineScan.next();
int lastRank = lineScan.nextInt();
int lastY = lastRank/2 + 25;
if ( lastRank == 0 ) {
lastY = 525;
}
int lastX = 0;
while ( lineScan.hasNextInt() ) {
int rank = lineScan.nextInt();
int y = rank/2 + 25;
if (rank == 0){
y = 525;
}
int x = lastX + SECTION_WIDTH;
String intervalLabel = name + " " + gender + " " + String.valueOf(lastRank);
g.setColor(Color.RED);
g.drawLine(lastX, lastY, x, y);
g.drawString(intervalLabel,lastX,lastY);
lastX = x;
lastY = y;
lastRank = rank;
}
g.drawString(intervalLabel,lastX,lastY);
for(int j = 0; j < DECADES; j++) {
g.setColor(Color.BLACK);
g.drawString(String.valueOf(STARTING_YEAR + yearIncrease), SECTION_WIDTH * j, 550);
yearIncrease += 10;
}
for (int k = DECADES * SECTION_WIDTH; k >= 0; k -= SECTION_WIDTH){
g.drawLine(k, 0, k, 550);
}
}
So at first you read the name and gender, and then you read the first rank, to give you initial coordinates.
Then, in every iteration of the loop, you read just one rank. You draw the line from your previous rank to your new rank. You draw the label that belongs to the previous rank at the previous rank's coordinates. And then you save your current x,y and rank to the lastX, lastY and lastRank respectively, so that you can rely on them in the next iteration.
After the loop is done, you still have one label you haven't drawn so you draw that, and then you go on to draw the black lines (I haven't looked into the correctess of your code there, just left it as is).
I'm learning Java out of The Art & Science of Java by Roberts (Stanford's CS106a text). I'm using NetBeans as my IDE.
Chapter 4, exercise 14 asks you to expand on a Checkerboard program introduced earlier. Specifically, it asks you to center the checkerboard and draw a set of red & white checks corresponding to the initial state of the game.
I've accomplished as much as requested, but have two issues-
The board is not completely centered in the window. It is closer to the left side of the window than the right side. I am not sure how to center it more. Am I doing this right? Is there a setting in NetBeans I can/should change?
The checkers are supposed to take up a large portion of the tiles they sit on. I assigned the size of my checkers to be dependent on the size of tiles so that the setup would be simple and proportionate. Is there a better way to do this to make the checkers bigger?
import acm.graphics.*;
import acm.program.*;
import java.awt.*;
public class Checkerboard extends GraphicsProgram{
public void run(){
double sqSize = (double)getHeight() / N_ROWS;
for (int i = 0; i < N_ROWS; i++){
for(int j = 0; j < N_COLUMNS; j++){
double x = ((j * sqSize) + (getWidth() / N_COLUMNS)); //centers square??
double y = (i * sqSize);
GRect sq = new GRect( x, y, sqSize, sqSize );
sq.setFilled((i + j) % 2 != 0);
sq.setFillColor(Color.GRAY);
add(sq);
double circleCoord = (sqSize * .33);
double xx = ((j * sqSize) + (getWidth() / N_COLUMNS) + circleCoord);
double yy = ((i * sqSize) + circleCoord);
if((i + j) % 2 != 0 && i < 3 ){
GOval red = new GOval( xx, yy, circleCoord, circleCoord);
red.setFilled(true);
red.setFillColor(Color.RED);
add(red);
} else if((i + j) % 2 != 0 && i > 4 ){
GOval black = new GOval( xx, yy, circleCoord, circleCoord);
black.setFilled(true);
black.setFillColor(Color.BLACK);
add(black);
}
}
}
}
private static final int N_ROWS = 8;
private static final int N_COLUMNS = 8;
}
For 1. The center of the board should be in the center of the width, too. So we know that
The left edge of tile N_COLUMNS/2 = getWidth()/2 e.g. tile 4 in 0 indexing has its left edge in the center
And every tile left or right of that will have a movement of sqSize, so:
double x = getWidth()/2 + (j-N_COLUMNS/2)*sqSize
I would like to implement a "grid view" of pixmaps. This is how I would like the UI to behave: You click a button and it shows a QGraphicsView with a QGraphicsScene (done) and then I would like to show all of my QPixmaps in a grid view. I don't actually want to see a grid I just want to organize the pixmaps like 10 columns (pixmaps) pr. row, and then a 10px whitespace in-between each pixmap. (not done). How would this be implemented?
EDIT: Here's what I've done so far (which produces the outcome described in the second comment)
public SpriteScene() {
super(0, 0, 800, 500);
QPixmap[] sprites = GUI.getWInterface().sprites;
List<QPixmap> l = Arrays.asList(sprites);
Iterator<QPixmap> i = l.iterator();
int rows = 10 / sprites.length;
boolean isDone = false;
for(int y = 0; y < rows; y++) {
for(int x = 0; x < 10; x++) {
if(i.hasNext()) {
QGraphicsPixmapItem pixmap = addPixmap(i.next());
pixmap.setPos(x * 64 + 10 , y * 64 + 10);
} else {
isDone = true;
break;
}
}
if(isDone) {
break;
}
}
}
SpriteScene extends QGraphicsScene and is being added to a QGraphicsView like this:
spriteView = new QGraphicsView(new SpriteScene(), this);
spriteView.setGeometry(0, 35, 850, 550);
spriteView.setAlignment(new Qt.AlignmentFlag[]{Qt.AlignmentFlag.AlignLeft, Qt.AlignmentFlag.AlignTop});
spriteView.hide();
Oh and by the way each pixmap is 64x64px :)
pixmap.setPos(x * 64 + 10 , y * 64 + 10);
Write that down on paper for the first few values:
x = 0, y = 0 => pos = ( 10, 10)
x = 1, y = 0 => pos = ( 74, 10)
x = 2, y = 0 => pos = (138, 10)
There's only 64 pixel different between each successive x offset. You need 74 pixels - the size of the pixmap plus the size of the border.
Set a few variables for your image with, height, horizontal and vertical spacing, and your code should look like:
pixmap.setPos(x * (width+hspacing) + offsetx, y * (height+vspacing) + offsety);
The offsetx/y would probably look nicer if they were half the respective spacing valued to get the grid "centered".