Image array p5.js - arrays

I've created some nested arrays to display array of Images, one thing I cant get right it repeats the same image instead of drawing a new one in every loop.
here is my example code simulates my problem
var images = [];
function preload() {
for (var i = 0; i< 3; i++) {
images[i] = loadImage("img/img" + i + ".jpg");
}
}
function setup() {
createCanvas(900, 900);
background(0);
preload();
}
function draw() {
//image(images[0],0,0);
for ( var y= 0; y < height; y=y+300) {
for ( var x =0; x < width; x=x+300) {
for ( var z = 0; z < 3; z++) {
image(images[z], x, y );
}
}
}
}
as images, i just used 300x300 jpgs 3 of them to test out.

I might be wrong, but quickly reading through your code, it looks you're drawing 3 images on top of each other:
image(images[z], x, y );
You can add console.log(x,y); before or after that line to double check.
Overall you're doing a grid, where you might want each element of that grid to be the images you preloaded, but you need to space them out a bit:
image(images[z], x + images[z].width * z, y );
This is quick and hacky, but you can actually work out how much spacing you need: total width / (image width + image spacing) = spacing per image, assuming the loaded images are the same size
Another option might be to cycle through the images from the array:
function draw() {
var i = 0;
//image(images[0],0,0);
for ( var y= 0; y < height; y=y+300) {
for ( var x =0; x < width; x=x+300) {
//using % to loop back to the first element after the array length
image(images[i % images.length], x, y );
i++
}
}
}
Note that the above code hasn't been tested, but hopefully it will be understandable enough to adapt

Related

C - How to check if at least one neighbor of a cell in a matrix respects a predication?

I'm on a project where I have to code a little game named "recolor", basically it's grid of a certain size, the grid is divided in cells (we have size*size cells), I can play a color (the color have to be in the grid or in the authorized colors) and each time I'm playing a color the grid will change from the top letf corner to color each cells directly connected to the top left corner that has the same color.
That's for the global context, now I already have all the functions to play this game but I have some problems with the function I use to play a move:
The game is defined using this type :
struct game_s
{
color **grid;
color **initial_grid;
uint width;
uint height;
uint nmb_cur_mv;
uint nmb_mv_max;
};
/*
* Def :
* - neighbour_of_origin checks if a cell is in the neighborhood of the (0,0) of the game grid, to be in the neighborhood
* the cell should have the same color as the (0,0) and the cell and (0,0) have to be connected by a path of cells that have the same
* color as (0,0).
* Param :
* - cgame g : the game grid
* - int x, y : coordinates of the cell we are currently checking
* - bool** to_change_tab : 2D array of boolean that represent the game grid and have the same size as it. It is used to mark all the cells to
* modify. By default the whole grid is set to false except (0,0) which is changed no matter what.
* Ret :
* - void function, nothing to return.
*/
void neighbour_of_origin(cgame g, int x, int y, bool **to_change_tab)
{
assert(g);
assert(g->grid);
assert(to_change_tab);
color origin = g->grid[0][0];
int offset[4][2] = {
{-1, 0}, /*W*/
{0, 1}, /*S*/
{1, 0}, /*E*/
{0, -1} /*N*/
};
int off_x;
int off_y;
for (int elem = 0; elem < 4; elem++)
{
off_x = x + offset[elem][0]; /*takes the 'x' coord in the offset matrix and add it to the current x*/
off_y = y + offset[elem][1]; /*takes the 'y' coord in the offset matrix and add it to the current y*/
if (((off_x >= 0 && off_x < SIZE) && (off_y >= 0 && off_y < SIZE)) && (to_change_tab[off_x][off_y] == true) && (g->grid[x][y] == origin))
{
to_change_tab[x][y] = true;
break;
}
}
}
/*
* Def :
* - game_play_one_move will change all the cells that are neighbors of the (0,0)that have the same color as it. The changing always begin
from the (0,0) and then it expands in all directions.
* Param :
* - game g : the game grid that will be modified.
* - color c : the color that will be applied to all the cells we have to change.
* Ret :
* - void function, nothing to return.
*/
void game_play_one_move(game g, color c)
{
assert(g);
assert(g->grid);
bool **to_change_tab = (bool **)malloc(sizeof(bool *) * SIZE);
assert(to_change_tab);
for (int i = 0; i < SIZE; i++)
{
to_change_tab[i] = (bool *)malloc(sizeof(bool) * SIZE);
assert(to_change_tab[i]);
for (int j = 0; j < SIZE; j++)
{
to_change_tab[i][j] = false;
}
}
/*getting all the cells we have to change*/
to_change_tab[0][0] = true; /*(0,0) is always modified */
printf("mark tab : \n");
for (int x = 0; x < SIZE; x++)
{
for (int y = 0; y < SIZE; y++)
{
neighbour_of_origin(g, x, y, to_change_tab);
printf("%d ", to_change_tab[x][y]); /*debbuging purpose*/
}
printf("\n");
}
/*modification of the game grid */
for (int x = 0; x < SIZE; x++)
{
for (int y = 0; y < SIZE; y++)
{
if (to_change_tab[x][y] == true)
{
g->grid[x][y] = c;
}
}
}
g->nmb_cur_mv += 1;
/*free the temporary array of bools*/
for (int x = 0; x < SIZE; x++)
{
free(to_change_tab[x]);
to_change_tab[x] = NULL;
}
free(to_change_tab);
to_change_tab = NULL;
}
above we have the two functions I've made to change the color as described in the rules, It actually works pretty well but I have a big issue on it.
This is my grid at the very begining :
each number corresponds to a color, the grid is 12*12 cells.
000202101030
033111132010
101232320332
231032111220
212333320100
033011233213
112220013112
131310101333
030100211130
131000323100
133112232002
202301112301
Here is my grid when I play the following colors : 3 1 3 0
000202101030
000000002010
000202020332
230002111220
212300020100
033011233213
112220013112
131310101333
030100211130
131000323100
133112232002
202301112301
if I play any color (except 0 of course) as my next move I expect every 0 connected to the top left to change but i got this instead:
333202101030
333333332010
333232320332
233332111220
212333320100
033011233213
112220013112
131310101333
030100211130
131000323100
133112232002
202301112301
the 0 on the first line didn't changed whereas they were connected to the origin, I suspected that the bug is in my condition in neighbour_of_origin(cgame g, int x, int y, bool **to_change_tab) because i'm using a for on x and y so the first line is evaluated first and the 0 on the first line did not have any neighbor that corresponds to the if condition at this state, is there a way to evaluate in "the order of propagation",I wanted to rewrite it recursively but I'm really bad in recursion.
Very sorry for the long post, I wish someone could help me, have a good day.
edit : I got a ''''fix'''' I duplicate my for loops in the game_play_one_move() function so it will loop again and again to find each cells he couldn't find before, I know it's not a real fix because in the future i don't know how the grid will be displayed exactly, but i guess that a loop that will check again and again until it can't find any neighbor could be a solution too, in terms of colplexity it would be a real problem since i'm looping in the grid again and again and again

How can I fix this error : 'Cannot invoke loadPixels() on the array type PImage[]'?

I'm kind of a beginner with Processing and I've been having difficulty with my pixel array. I have 10 images numbered from 0-9 that are being shown one after another... What I am trying to do on top of that is take each image and change its brightness level, turning it either white or black.
I've already tried to just change the brightness using one image, so not an array of images which works perfectly! But when joining those two together it doesn't work for me.
int maxImages = 10; // The number of frames in the animation
int imageIndex = 00; //initial image to be displayed first
PImage[] picture = new PImage[maxImages]; //the image array
void setup() {
size(500, 500); //size of sketch
frameRate(1); //frames processed per second
//loading images with numbered files into the array
for (int i = 0; i< picture.length; i++) {
picture[i] = loadImage("spast_" + i + ".jpg");
}
}
void draw() {
image(picture[imageIndex], 0, 0); //dispaying one image
loadPixels(); //accessing pixels
picture.loadPixels(); //accessing the image pixels too
//THIS is where it stops me and gives me 'Cannot invoke loadPixels() on the array type PImage[]'
for (int x = 0; x < width; x++) { //loops through every single x value
for (int y = 0; y < height; y++) { //loops through every single y value
int loc = x + y*width; // declare integer loc
float b = brightness(picture.pixels[loc]); //give me the brightness of pixels
if (b < 150) { //if the pixel is lower than 150
pixels[loc] = color(0); //then make those pixels black
} else { //otherwise
pixels[loc] = color(255); //make pixels white
}
}
}
imageIndex = (imageIndex + 1) % picture.length; //increment image index by one each cycle
updatePixels(); //when finished with the pixel array update the pixels
}
I'm expecting as each image is displayed it brightness value is changed and then it goes on to image 2 and so on...
Your picture variable is an array of PImage instances. You can't call loadPixels() on the array itself. You have to get a PImage at a specific index of the array, and then call the loadPixels() function on that instance.
Here's an example:
picture[0].loadPixels();
This line of code gets the PImage at index 0 and calls the loadPixels() function on it.
Note that you're already doing something pretty similar with this line:
image(picture[imageIndex], 0, 0);
Shameless self-promotion: here is a tutorial on arrays in Processing.
This is the updated and working code:
int maxImages = 10; // The number of frames in the animation
int imageIndex = 0; //initial image to be displayed first
PImage[] picture = new PImage[maxImages]; //the image array
void setup() {
size(500, 500); //size of sketch
frameRate(1); //frames processed per second
//loading images with numbered files into the array
for (int i = 0; i< picture.length; i++) {
picture[i] = loadImage("spast_" + i + ".jpg");
}
}
void draw() {
loadPixels(); //accessing pixels
image(picture[imageIndex], 0, 0); //dispaying one image
imageIndex = (imageIndex + 1) % picture.length; //increment image index by one each cycle
picture[imageIndex].loadPixels(); //accessing the image pixels in the array
for (int x = 0; x < width; x++) { //loops through every single x value
for (int y = 0; y < height; y++) { //loops through every single y value
int loc = x + y*width; // declare integer loc
float b = brightness(picture[imageIndex].pixels[loc]); //give me the brightness of pixels
if (b < 150) { //if the pixel is lower than 150
pixels[loc] = color(0); //then make those pixels black
} else { //otherwise
pixels[loc] = color(255); //make pixels white
}
}
}
updatePixels(); //when finished with the pixel array update the pixels
}

Extracting an image from an array in Processing

Does anyone have any suggestions on what might be going wrong with this code? I'm trying to load tiles of images into a large array and then display them. Later on I'll shuffle the pieces. The issue I'm running into is seen near the bottom. I have a for loop that should plug the value of i into the output array and display the relevant image at that index value. Instead I get a null pointer exception. If I replace the letter i with an integer it works perfectly. What could be preventing processing from passing that value if i into the array? Any thoughts? Thanks.
int tileSize = 100;
PImage out; PImage sample;
PImage img;
PImage img2;
String[] imageNames = {"arctic_fox.jpg", "bbridge_in_the_am.jpg", "Kali2.jpg"};
PImage[] images = new PImage[imageNames.length];
//PImage[] output = new PImage[((1440/tileSize)*imageNames.length)*(900/tileSize)];
PImage[] output = new PImage[2000];
int tintScale = 200;
void setup() {
fullScreen();
for (int i=0; i < imageNames.length; i++) {
String imageName = imageNames[i];
images[i] = loadImage(imageName);
}
out = createImage(width, height, RGB);
noLoop();
println("test");
}
void draw() {
background(0);
println(width, height);
println(output.length);
int counter=0;
for (int i = 0; i < imageNames.length; i++) {
img = loadImage(imageNames[i]);
img.resize(0,900);
for (int y=0; y<img.height; y+=tileSize) {
for (int x=0; x<img.width; x+=tileSize/3) {
sample = img.get(x, y, tileSize, tileSize);
output[counter] = sample;
tint(255, tintScale);
counter++;
//println(counter);
//image(out, random(0, width-img_x), random(0, height-img_y));
}
//image(output[i],30,30);
}
}
for (int i=0;i<output.length;i++){
image(output[30],i*tileSize,i*tileSize);
}
//for (int y=0; y<out.height; y+=tileSize) {
// for (int x=0; x<out.width; x+=tileSize) {
// i = 800;
// //tint(255, tintScale);
// image(output[i], x, y);
// }
//}
}
I hope you solved it, but this is the problem:
PImage[] output = new PImage[2000];
You are initializing the array with 2000 null values, and then enter less then 300 tiles. That's why you get a null pointer error. You have to calculate how large your array will be before you initialize it. Or perhaps better, use an arraylist:
ArrayList<PImage> output = new ArrayList<PImage>();
//to add a tile:
output.add(sample);
//to draw all tile:
for(int i = 0; i< output.size();i++)
{
image(output[i],i*tileSize,i*tileSize);
}
You can read more about arraylists here
Final note: as Kevin Workman says, loadImage() and this process of dividing into tiles does not belong in 'void draw()'. It should be in setup() or in a separate function, called from setup().

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);
}
}

Float / Array error reading from CSV

I'm missing something fundamental here but I can't seem to find out what from all my research.
I have imported a csv file, split the string into floats, and now wish to connect all points to all other points with a line. My code is as follows:
String [] data;
void setup () {
size(300, 300);
background(255);
data = loadStrings("points.csv");
for (int i = 0; i < data.length; i++) {
String [] fields = split(data[i], ',');
float t = float(fields[0]);
float n = float(fields[1]);
float x = float(fields[2]);
float y = float(fields[3]);
ellipse(x, y, 10, 10);
line(x, y, x[i], y[i]);
}
}
The error message is "The type of expression must be an array type but it resolved to float"
I'm sure this is extremely basic but, I dont understand why x[i] or y[i] are not seen as an array type.
I would really appreciate any help with this. Many thanks in advance.
Sam
*UPDATE***
An exract from the points.csv file is as follows:
219185750 rabih_takkoush 20.88521 19.49821
219185716 MoustaphaAjram 100.870896 59.515259
219185709 jinanejghosh 56.886441 35.489087
219185557 MoustaphaAjram 34.870904 78.515243
219185555 Mohammad8Itani 12.8946 49.48179
What I am trying to accomplish is plotting the various geolocations (whereby col 3 = x, col 4 = y) and then connecting all points with all other points with a line.
The following script works plotting all locations specified in the array within the script:
float[] x = { 50, 100, 150, 200,20,20 };
float[] y = { 10, 30, 20, 250,20,90 };
void setup () {
size(300, 300);
background(255);
}
void draw() {
for (int i = 0; i < x.length; i++) {
ellipse(x[i], y[i], 10, 10);
for (int j = 0; j < x.length; j++) {
line(x[j], y[j], x[i], y[i]);
}
}
}
What I wish to do is do the same, but reading columns 3 and 4 of the csv file.
You're splitting your data into iteration-scoped floats, then you try to access them as if they're both floats as well as arrays in your line() call. Try this:
String[] data;
float[] x, y, t, n;
void setup () {
size(300, 300);
data = loadStrings("points.csv");
int len = data.length;
x = new float[len];
x = new float[len];
t = new float[len];
n = new float[len];
for (int i=0; i<len; i++) {
String line = data[i];
String[] fields = split(line, ',');
t[i] = float(fields[0]),
n[i] = float(fields[1]),
x[i] = float(fields[2]),
y[i] = float(fields[3]);
}
// don't put draw instructions in setup,
// put them in draw. if you want to run once,
// issue a noLoop() so that happens.
noLoop();
}
void draw() {
float prevx = x[0], prevy = y[0];
for (int i=0, last=x.length; i<last; i++) {
ellipse(x[i], y[i], 10, 10);
line(prevx,prevy, x[i],y[i]);
prevx=x[i];
prevy=y[i];
}
}
Now we're storing the data from CVS in linked arrays that we can access throughout the sketch, rather than throwing them away after setup().
ok so if you go with the first code you made, you only need to change a few things, here is what you can do:
float[] x;
float[] y;
string[] data;
void setup () {
size(300, 300);
background(255);
data = loadStrings("points.csv");
x = new float[data.length];
y = new float[data.length];
for (int i = 0; i < data.length; i++) {
String [] fields = split(data[i], ',');
float t = float(fields[0]);
float n = float(fields[1]);
float x = float(fields[2]);
float y = float(fields[3]);
}
}
void draw() {
for (int i = 0; i < x.length; i++) {
ellipse(x[i], y[i], 10, 10);
for (int j = 0; j < x.length; j++) {
line(x[j], y[j], x[i], y[i]);
}
}
}
As you can see nothing really new, it's a mix between your initial code and the one you made for the csv.
And actually you mainly needed to declare your x and y variables as float[] instead of just float. But also there were some changes to make in the loop.
In this code you load the data in your arrays first (exactly like you did by declaring array's values in your code, but this time you read these values from your file), and then call your draw method as before.
hope it works now

Resources