How can I draw a line to an array? - arrays

I'd like to store a mouse trail (or other visual data), without it being drawn to the screen.
How can I do the following, but save the display data to an Arrary so it's not drawn to the stage?
line(mouseX, mouseY, pmouseX, pmouseY);
I have a suspicion I need to toggle between different display data each draw() by:
clearing the screen
loading target display data
drawing to the screen
store back out to target data
I'm not sure how to go about it yet or if there's a better approach.

#Majlik example is really cool (voted up). Just to add that you don't need a PGraphic if you only want to store the data. And you can use PVector to store the data in mouseMoved().
here is my attempt ;)
ArrayList <PVector> points = new ArrayList <PVector>();
boolean print = false;
void setup(){
size(400,400);
background(255);
}
void draw(){
if(print && points.size()>1){
for(int i = 0; i < points.size()-1; i++){
float stX = points.get(i).x;
float stY = points.get(i).y;
float ndX = points.get(i+1).x;
float ndY = points.get(i+1).y;
line(stX, stY, ndX, ndY);
}
print = false;
}
}
void mouseMoved(){
points.add(new PVector (mouseX, mouseY));
}
void keyPressed(){
if(key == ' ' ){
background(255);
print = true;
}
}

Using PGraphics to draw lines to different display (you can switch it on/off by pressing any key) and Arraylist to store position of mouse you can achieve something like this:
PGraphics pg;
ArrayList<Integer> points = new ArrayList();
boolean visible = true;
void setup() {
size(400, 400);
pg = createGraphics(width, height);
}
void draw() {
background(100);
if(points.size() >= 100){
points.remove(0);
points.remove(1);
}
points.add(mouseX);
points.add(mouseY);
pg.beginDraw();
pg.background(100);
for(int i = 2; i < points.size()-4; i += 2){
pg.stroke(255/100*(i+1));
pg.line(points.get(i), points.get(i+1), points.get(i+2), points.get(i+3));
}
pg.endDraw();
if(visible)
image(pg, 0, 0);
}
void keyPressed() {
visible = !visible;
}

Related

Processing - Animation between two points

I am developing the below code. To give you a brief description, it is allowing the user to click on different points on the screen, then these mouse coordinates and positions are stored in an array and also seen on the screen. When the user clicks enter there is a movement from the first point to the last point, using the linear interpolation technique. I am having difficulty in the for loop as the PVector v is storing the coordinates. Could anyone please guide me accordingly?.
ArrayList vectors;
PVector v = new PVector();
boolean animate = false; //declare a boolean variable you can use to switch from building points to animating the movement
int FirstMouseClick; //declare an int variable to store the frameCount of the first mouseclick
int AnimationStart; //declare an int variable to store the frameCount of the animation start
void setup()
{
size(500, 500);
frameRate(60);
vectors = new ArrayList();
}
void draw()
{
if(!animate)//if the boolean variable animate is true
{
float output = frameCount - AnimationStart; // subract the animation start frameCount from the current frameCount so you know which framecount from the vectors array you should be showing
for(int i=0; i<vectors.size(); i++) //loop through the vectors array
//until you find the (next PVector's frameCount - frameCount of first mouseClick) > above subtraction result
{
v = (PVector)vectors.get(frameCount); //until you find the (next PVector's frameCount)
}
ellipse(v.x,v.y,10,10);// use the current pvector's xpos and ypos to draw the ellipse
}
}
void mouseClicked()
{
frameCount = 0; //if not yet set, set the first frameCount value
vectors.add(new PVector(mouseX, mouseY,frameCount));// <--- store the framecount in the z axis
ellipse(mouseX,mouseY,10,10);
println("Mouse Coordinates are: " + vectors);
}
void keyPressed()
{
if(keyCode == ENTER)
{
animate = true; //set the boolean variable animate to true
AnimationStart = 3; //set the framecount of the animation start
}
}
I'm really not sure, what you were trying to do, but if I got you right you want to do something like this:
Draw some circles, if user clicked on canvas
If user pressed Enter, start animation
Animation means: another circle (v) moves linear from circle to circle
I really don't know, what your frameCount was for. May be you can add it to this code easier now? Note, that you can add new targets by clicking with the mouse, even if animation is true.
You can do this:
ArrayList<PVector> vectors = new ArrayList();
PVector v = new PVector();
boolean animate = false; // true means, the circles moves
int nextTarget = 0; // defines the index of the next circle, the point is going to
void setup()
{
size(500, 500);
frameRate(60);
v = new PVector(width/2, height/2);
}
void draw() {
// draw background to delete old drawings
background(128);
// show all circles
for (int i=0; i<vectors.size(); i++) {
fill(255);
ellipse(vectors.get(i).x, vectors.get(i).y, 10, 10);
}
// if the boolean variable animate is true
if (animate) {
// compute angle to target circle and remaining distance
float diffX = vectors.get(nextTarget).x - v.x;
float diffY = vectors.get(nextTarget).y - v.y;
float angle = atan2(diffX, diffY);
// defines the speed of the circle
float movement = 2;
// compute new position of v
v = new PVector(v.x + sin(angle)*movement, v.y + cos(angle)*movement);
// if v reached the target circle, move on to the next one
if (dist(v.x, v.y, vectors.get(nextTarget).x, vectors.get(nextTarget).y) < 1 && nextTarget < vectors.size()-1) {
nextTarget++;
}
}
fill(0);
ellipse(v.x, v.y, 10, 10); // use the current pvector's xpos and ypos to draw the ellipse
}
void mouseClicked()
{
vectors.add(new PVector(mouseX, mouseY));
ellipse(mouseX, mouseY, 10, 10);
println("Mouse Coordinates are: " + vectors);
}
// toggle animation mode
void keyReleased() {
if (key == ENTER) {
animate = !animate;
println("animation: "+ animate);
}
}

How do I interact with a grid using a 2D array (Proce55ing)

For a project I need to create Connect Four using Processing, I have created the grid which the game will be played in however I am lost when it comes to players interacting with it.
I have been told to use a 2D array however my knowledge of arrays is very limited. I am currently trying to code the bit where the program detects where a player has clicked and spawning a coin there.
int c = 8;
int r = 10;
int[][] grid = new int [c][r];
int CoinSpawn = -1;
void setup () {
size(1000, 800);
}
void draw () {
background(1, 1, 1);
translate(100, 100);
noStroke();
drawColumns();
drawRows();
}
void keyPressed () {
for (int i=0; i<grid.length-1; i++) {
grid[i][i] = grid[i+1][i+1];
}
}
void drawRows(){
for (int i=0; i < r; i++){
int x = 80;
x = x * i;
translate(x,0);
drawColumns();
translate(-x,0);
}
}
void drawColumns(){
for (int i=0; i < c; i++){
int y = 80;
y = y * i;
translate(0,y);
drawCell();
translate(0,-y);
}
}
void drawCell(){
fill(0,0,255);
rect(0,0,80,80);
noFill();
fill(0);
ellipseMode(CENTER);
translate(40,40);
ellipse(0,0,75,75);
noFill();
translate(-40,-40);
}
Would I be able to assign the 2D array to the grid? so that each slot in the grid represents an element from the array? That is the best option I can see at the moment however I have no idea how to do it.
I really appreciate any replies as I am completely lost at the moment.
You have a pretty good start, I made a lot more changes than I had planned... got a little into it!
Let me know if you have any questions, I did use one simple OOP class called cell that tracks the value and the cell's position, as well as provides a display function, I converted a lot of your variables and hard coded numbers to constants (starts with final and has the same value for the entire program)
you will notice I left the win conditions to you!
I hope this is helpful, I feel like seeing 2D arrays used in a context you are familiar with might help you understand them!
My normal process using 2D arrays for processing:
use Setup() to set initial array values
use Draw() to call each of the item's display function
use other functions to modify the array data, which the display function of the cell knows how to display
Main File
// Grid Size constants
final int GRID_COLUMNS = 10;
final int GRID_ROWS = 8;
// Display constants
final int CELL_SCALE = 80;
final int COIN_RADIUS = 75;
final int BOARD_PADDING = 100;
final color[] PLAYER_COLORS = new color[]{color(0), color(200, 10, 10), color(200, 200, 10)};
// cell values
final int EMPTY_CELL = 0;
final int PLAYER_1 = 1;
final int PLAYER_2 = 2;
// game data
Cell[][] grid = new Cell [GRID_COLUMNS][GRID_ROWS];
int currentPlayer;
void setup () {
size(1000, 800);
ellipseMode(CENTER); // only needs to be set once per sketch
setupBlankBoard();
}
// method to populate the array with blank cells, used to initiate and reset the game
void setupBlankBoard() {
currentPlayer = PLAYER_1; // reset game and start with first player
// populate array
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
// rather than translates I prefer to calculate the actual x,y position and just display it there,
// we add the padding offset to every cell, and then take the column/row times the width of the square cell
grid[x][y] = new Cell(BOARD_PADDING+x*CELL_SCALE, BOARD_PADDING+y*CELL_SCALE);
}
}
}
void changePlayers() {
if (currentPlayer == PLAYER_1) {
currentPlayer = PLAYER_2;
} else {
// already was player 2, so change to 1
currentPlayer = PLAYER_1;
}
}
boolean placeCoin(int column) {
boolean coinPlaced = false;
// now we know the column, we need to find the lowest cell in that column that is empty
for (int y = GRID_ROWS-1; y >= 0; y-- ) { // let's start at bottom and move up to reduce computations
// for every cell, test if it is empty
if (grid[column][y].isEmpty()) {
// if found a valid cell, place current players token and exit the loop (break)
grid[column][y].setValue(currentPlayer);
coinPlaced = true;
break;
}
}
return coinPlaced;
}
void checkCoins() {
// scan the array for 4 of the same value in a row
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
//grid[x][y]
// I will leave this to you ;)
// keep in mind to check neighbors all you need to do is add or subtract 1 from the x or y value
// however when you are at the edge of the board be careful not to try and look at a neighbor that is off the edge, you will get a null pointer or an array out of bounds exception
if (x+1<GRID_COLUMNS) {
Cell toTheRight = grid[x+1][y];
}
// for each cell you could look at the 3 above the current, 3 below the current, 3 to the right and 3 to the left, 3 diagnal in each direction and then manually try and find 4 adjacent same color cells
// or a bit more complicated is a recursive solution that checks its 8 immediate neighbor and for each that match the center cell run the same function to test its 8 neighbors keeping track of the current inARowCount and returning true when it is found.
// would be a bit hard because you would need to make sure the second cell doesn't follow back to the original cell, and start an endless loop
}
}
}
void draw () {
background(1, 1, 1);
noStroke();
// draw all cells
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
grid[x][y].display(); // draw this cell
}
}
// draw next coin floating above the board, contrain its positon to above the board
fill(PLAYER_COLORS[currentPlayer]);
int currentMouseX = constrain(mouseX, BOARD_PADDING+COIN_RADIUS/2, BOARD_PADDING+(GRID_COLUMNS*CELL_SCALE)-COIN_RADIUS/2);
//currentMouseX = 40*(ceil(abs(currentMouseX/40)));
ellipse(currentMouseX, BOARD_PADDING/2, COIN_RADIUS, COIN_RADIUS);
}
// press any key to rest the game, probably want to test for a certain key here!
void keyPressed () {
setupBlankBoard();
}
// on press attempt to place a coin
void mousePressed() {
int currentMouseX = constrain(mouseX, BOARD_PADDING+COIN_RADIUS/2, BOARD_PADDING+(GRID_COLUMNS*CELL_SCALE)-COIN_RADIUS/2);
// determine what column we are over
int column = (currentMouseX - BOARD_PADDING)/CELL_SCALE;
// if choice is a valid coin placement
if (placeCoin(column)) {
// toggle players if a coin was placed
changePlayers();
// after each placement check win conditions
checkCoins();
}
}
Cell Class
class Cell {
int x, y;
int value; // 0 for empty, 1 for team 1, 2 for team 2 (constants defined at top of main file)
Cell(int x, int y) {
// default constructor to create empty cell
this(x, y, EMPTY_CELL);
}
// allows cell value to be set at creation
Cell(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
boolean setValue(int value){
value = constrain(value, EMPTY_CELL,PLAYER_2); // keeps it from setting a value outside of our range
if(this.value == EMPTY_CELL){
this.value = value;
return true; // placed
}
return false; // was not able to place it as there is already a value
}
boolean isEmpty(){
return this.value == EMPTY_CELL;
}
void display() {
fill(0, 0, 255);
rect(this.x, this.y, CELL_SCALE, CELL_SCALE);
// Draw Circle color based on current value, could simply just put fill(playerColors[this.value]); but this seems a bit more clear
if(this.value == EMPTY_CELL){
fill(PLAYER_COLORS[EMPTY_CELL]);
}else if(this.value == PLAYER_1){
fill(PLAYER_COLORS[PLAYER_1]); // red
}else if(this.value == PLAYER_2){
fill(PLAYER_COLORS[PLAYER_2]); // yellow
}
ellipse(this.x + CELL_SCALE/2, this.y + CELL_SCALE/2, COIN_RADIUS, COIN_RADIUS);
}
}

Array of text don't fade out until the last one is appended

I want to make a group of array fade out until the last array in this group was appended. for example, I use append to create zoog[0], zoog[1], zoog[2], and I want these three objects not fadeout until zoog[2] is created and wait for a second, the same situation with zoog[3], zoog[4],zoog[5], these three objects don't fadeout until zoog[5] is created. But now what I can do is make each object fadeout as soon as it is created.
Zoog[]zoog = new Zoog[1];
float count=0;
int xpos =0;
int ypos =0;
String message="haha";
int ntextsize = 20;
int nopacity =200;
int thistime = 0;
int thiscount = 0;
//Zoog zoog;
void setup() {
size(400, 400);
xpos = int(random(width/2-200, width/2+40));
ypos = int(random(height/2, height/2-40));
zoog[0] = new Zoog(xpos,ypos,message,nopacity);
}
void draw(){
background(255,255,255);
for(int i=0; i<zoog.length; i++){
// if(millis()-thistime>4000){
// zoog[i].disappear();
// }
zoog[i].jiggle();
zoog[i].display();
}
}
void mousePressed(){
count = count + 1;
// int thiscount = 0;
if(count%3 ==0){
xpos=int(random(30, width-30));
ypos=int(random(10, height-10));
}
else{
ypos = ypos+50;
// thiscount = thiscount +1;
// thistime = millis();
// }
}
nopacity = int(random(100,255));
// text(message, xpos, ypos);
Zoog b = new Zoog(xpos,ypos,message,nopacity);
zoog =(Zoog[]) append(zoog,b);
}
Zoog class
class Zoog {
int x;
int y;
String thatmessage;
int opaci =0;
Zoog(int xpo, int ypo, String thismessage, int opa) {
x = xpo;
y = ypo;
thatmessage = thismessage;
opaci = opa;
}
void jiggle() {
x = x+int(random(-2, 2));
y = y+int(random(-2, 2));
}
void display() {
fill(0, opaci);
text(thatmessage, x, y);
print("x position is "+ x);
print("y position is "+y);
}
void disappear() {
for (int j=0; j<255; j++) {
opaci = opaci -j;
}
}
}
If I understand correctly you want to make 3 zoogs and then start fading those three out until they're gone. If this is correct there are a couple of ways I'd go about doing this.
First, I wouldn't use an array especially if you're dynamically updating the amount inside it. If you want to do that I'd use, arraylists. Here's the javadocs reference. Basically you'd initialize an arraylist of Zoogs and put the zoog.add(new Zoog...) in the mousepressed. The good thing about arraylists is that they have a number of member functions that can help you manipulate them. For instance, you can check the size of the arraylist in your draw function instead of the time. Once you're above 3 start fading the first 3 out until they're dead (using a Zoog member function to say they're dead). You can check that "isDead" member function in your draw loop and remove the correct dead Zoog while in your for loop.
Here's a rough implementation, assuming you created an isDead function in your Zoog class that just returns whether the opacity is greater than 0:
void Draw()
{
for (Zoog zoog : zoogs) //for each statement simplifying the code -
//says for each Zoog in zoogs do
{
zoog.jiggle();
zoog.display();
}
if(zoogs.size() >= 3) {
for(int i = 0; i < 3; i++) {
zoogs.get(i).disappear();
}
}
if (zoogs.get(0).isDead() && zoogs.get(1).isDead() && zoogs.get(2).isDead()) {
zoogs.remove(2);
zoogs.remove(1);
zoogs.remove(0);
}
}
This is by no means a perfect example but it shows how to remove 3 zoogs at a time by lessening their opacity and checking whether they are dead. If you're clicking a million times then it will take a while for each chain of three to die.

Array displaying images, need to make another method that takes a paramter NUM to order how many pictures are shown

I explained that horridly in the title, and I apologize, am very new to java and don't quite understand some of it yet.
Anyway,
My cat animation runs to the middle of the screen, scratches twice, then continues to run to the end, is there anyway to write a method that will take an INT NUM and make the cat scratch x amount of times? Not sure how to go about doing this.
Any help would be much appreciated
Here is my current code
/** Run the animation. */
public void nekoRun() {
moveIn();
scratch();
//scratch2(5);
moveOut();
}
/* Move Neko to the centre of the panel. */
private void moveIn() {
for (int i = 0; i < getWidth()/2; i+=10) {
xPos = i;
// swap images
if (currentImage == nekoPics[0])
currentImage = nekoPics[1];
else
currentImage = nekoPics[0];
repaint();
pause(150);
}
}
//neko stops and scratches in the middle of the panel twice
private void scratch() {
for (int i = 0; i < 10; i++) {
// Swap images.
currentImageIndex = nextImageList[currentImageIndex];
currentImage = nekoPics[currentImageIndex];
repaint();
pause(150);
}
}
//Neko runs to the end of the panel
private void moveOut() {
for (int i = xPos; i < getWidth(); i+=10) {
xPos = i;
// swap images
if (currentImage == nekoPics[0])
currentImage = nekoPics[1];
else
currentImage = nekoPics[0];
repaint();
pause(150);
}
}

how to use ArrayList in Processing?

The official explanation is here: ArrayList
However, it uses iteration and confuses me.
I am trying to make a drawing pen but something is wrong here:
drawings.get(i) = drawing.get(i-1);
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup(){
size(400,400);
background(255);
colorMode(HSB);
}
void draw(){}
void mouseDragged(){
drawings.add(new Drawing(mouseX,mouseY));
for(int i = drawings.size()-1;i>0;i--){
drawings.get(i) = drawing.get(i-1);
}
for(int i=0;i<drawings.size;i++){
fill(c,100);
drawings.get(i).display();}
}
class Drawing{
float x,y,r;
color c;
Drawing(float ax,float ay){
x=as;
y=ay;
r=random(2,20);
c=color(random(100,200),255,255);
}
void display(){
fill(c,100);
ellipse(drawing[i],r,r);}
}
I still don't know how to use ArrayList.
Does anyone know?
Thank you.
You mentioned iteration confuses you. It's a simple for loop. In case you're having trouble understanding those, they look harder compared to other statements, but that's just because a loop does 3 things at once:
Initialize a counter
Compare the current counter value to a limit (boolean expression)
Increments a counter
In your code, there are two loops:
for(int i = drawings.size()-1;i>0;i--)
and
for(int i=0;i<drawings.size();i++)
The first loop counts backwards, therefore:
the counter is initialized with the highest value (i =
drawings.size())
the limit is 1 (i>0)
the counter is decremented (i--) (or incremented by -1 if you like)
drawings.size() simply retrieves the size of the array list (similar to the length property of an array). So in simple terms, the first loop starts with the last element added to the list (the most recent), who's index is equal to the list size -1 and it stops at the 2nd element, who's index is 1 (since arrays/array lists start indexing from 0).
The second loop is simpler, since is counts from 0 to the size of the array list, basically all the elements of the list in the order they were stored (oldest to newest).
In the first loop, it looks like you're shifting all the elements except the first by one.
You should try it like so:
for (int i = drawings.size()-1;i>0;i--) {
Drawing current = drawings.get(i);//store the current drawing
Drawing previous = drawings.get(i-1);//store the previous drawing
current = previous;//point the current to the previous
}
And here is your code listing with the errors fixed:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
color c = color(0,0,192);
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
for (int i = drawings.size()-1;i>0;i--) {
Drawing current = drawings.get(i);//store the current drawing
Drawing previous = drawings.get(i-1);//store the previous drawing
current = previous;//point the current to the previous
//drawings.get(i) = drawing.get(i-1);
}
for (int i=0;i<drawings.size();i++) {
fill(c, 100);
drawings.get(i).display();
}
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
// ellipse(drawing[i], r, r);
ellipse(x,y,r,r);
}
}
UPDATE
Because of the reverse loop I assumed you needed to store a list of drawing and offset it, like so:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
smooth();
noStroke();
colorMode(HSB);
}
void draw() {
background(0,0,255);
for (int i=0;i<drawings.size();i++){
drawings.get(i).display();
}
}
void mouseDragged() {
for (int i = drawings.size()-1;i>0;i--) {
drawings.get(i).copy(drawings.get(i-1));
}
drawings.add(0,new Drawing(mouseX, mouseY));
}
class Drawing {
float x, y, r;
color c;
void copy(Drawing copyFrom){
x = copyFrom.x;
y = copyFrom.y;
r = copyFrom.r;
c = copyFrom.c;
}
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
If you simply want to draw a line between Drawing objects based on distance, you can do it without the reverse loop:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
for (int i=0;i<drawings.size();i++) {
Drawing curr = drawings.get(i);
if(i > 0){ //if the current index is greather than 0
Drawing prev = drawings.get(i-1); //we can access the previous
if(dist(curr.x,curr.y,prev.x,prev.y) < 20) {//check the distance, if it's within a certain threshold
line(curr.x,curr.y,prev.x,prev.y); //draw the line
}
}
curr.display();
}
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
In fact, since you're not clearing the background, you don't need a list at all. All you need is a reference to the previous Drawing object so you can check the distance and draw a line:
Drawing prev;//variable to store the previous drawing
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
}
void mouseDragged() {
Drawing curr = new Drawing(mouseX, mouseY);//create a new drawing
curr.display();//display it
if(prev != null){//check if there was a previous one
if(dist(curr.x,curr.y,prev.x,prev.y) < 20) {//if so, check if the distance is within the threshold
line(curr.x,curr.y,prev.x,prev.y);//then simply draw a line
}
}
prev = curr;
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255);
}
void display() {
fill(c, 100);
ellipse(x,y,r,r);
}
}
HTH

Resources