I'm trying to make a grid where each individual cell contains one random image from my data folder.
So far, I've accomplished having a different image in every cell, but it doesn't randomize
instead of randomly picking one from the 600+ from the folder, it places every image in order 1 to 27.
Apart from that, I want it to randomize every time I click with the mouse instead of just randomizing when its closed and played again. The code:
PImage img[];
int nPics;
int w;
int h;
int rand;
void setup(){
size(1500,500);
nPics=27;
img = new PImage[nPics];
w=width/9;
h=height/3;
for (int i = 0; i <nPics; i++) {
img[i] = loadImage("img_" +nf(i,3)+ ".jpg");
imageMode(CORNERS);
}
//rand = int(random(0,687));
//img[0]=loadImage("img_" + nf(rand,3)+ ".jpg");
}
void draw(){
background(0);
for(int i=0;i<nPics;i=i+3){
int col = i/3;
for(int row=0;row<3;row++)
image(img[i+row],col*w,row*h,(col+1)*w,(row+1)*h);
}
}
When you are loading your images you are using i instead of rand. In order to randomize the images when you click the mouse, you can use the mousePressed() to reload different images into your array.
This should work:
PImage img[];
int nPics;
int w, h;
void loadImages(){
for (int i = 0; i < nPics; i++) {
img[i] = loadImage("img_"+ nf(int(random(0, 687)), 3) + ".jpg");
imageMode(CORNERS);
}
}
void setup() {
size(1500, 500);
nPics=27;
img = new PImage[nPics];
w=width/9;
h=height/3;
loadImages();
}
void mousePressed(){
loadImages();
}
void draw() {
background(0);
for (int i=0; i<nPics; i=i+3) {
int col = i/3;
for (int row=0; row<3; row++)
image(img[i+row], col*w, row*h, (col+1)*w, (row+1)*h);
}
}
I'm making a game that flips a tile in a grid board to flip between images and the user wins when all the tiles become the same image. My current issue is in mousepressed() with the if statement that swaps the tiles around based on what tile the user clicked. I get an error complaining about incompatible types and I am not sure how to work around this error. I will add the images I used for the tiles.
final int NUM_TILES = 4;
PImage image1, image2;
PImage [][] imageShown;
PImage [][] board;
int sqSide;
float randValue = random(1,2);
void setup(){
size(500, 500);
sqSide = width/NUM_TILES;
imageShown = new PImage[NUM_TILES][NUM_TILES];
board = new PImage[NUM_TILES][NUM_TILES];
image1 = loadImage("helloseal.jpg");
image2 = loadImage("very-rotund.jpg");
displayPuzzle();
}
void draw(){
}
void displayPuzzle(){
for(int i=0; i<NUM_TILES; i++){
for(int j=0; j<NUM_TILES; j++){
image(board[i][j], j*sqSide, i*sqSide);
}
}
}
int clickedRow, clickedCol;
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
if(board[clickedRow][clickedCol] == 1){
board[clickedRow][clickedCol] = 2;
image(image2, clickedCol*sqSide, clickedRow*sqSide);
}else if(board[clickedRow][clickedCol] == 2){
board[clickedRow][clickedCol] = 1;
}
if (checkGameOver() == true){
System.exit(0);
}
}
boolean checkGameOver(){
for(int row=0; row<NUM_TILES; row++){
for(int col=0; col<NUM_TILES; col++){
int randValue = int(random(1,2));
if( randValue == 1){
imageShown[row][col] = 1;
return false;
}
}
return true;
}
}
Looks like you're trying to compare a PImage to an integer, replacing the 1 and 2 with "image1" and "image2" should fix it.
I am working on an ascending order puzzle that records the time it takes the user to complete the puzzle and once the puzzle is completed it takes the user to a game over screen that shows the user their time. My issue is that the time that is being displayed is overlapping and not updating as it should be. I am also unsure how to save the time that the user took to complete the puzzle.
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
void setup(){
size(500, 500);
setupGame();
sqSide = width/NUM_SQUARES;
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
}
}
//visual representation of the board
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
fill(random(0,255), random(0,255), random(0,255));
rect(col*sqSide, row*sqSide, sqSide, sqSide);
fill(0);
textSize(30);
text(board[row][col], (col+0.5)*sqSide, (row+0.5)*sqSide);
}
}
}
class Timer{
float Time;
Timer(float set){
Time = set;
}
float getTime(){
return(Time);
}
void setTime(float set){
Time = set;
}
void countUP(){
Time += 1/frameRate;
}
}
boolean searchFor(int itemToBeSearched){
for(int i=0; i<NUM_SQUARES; i++){
for(int j=0; j<NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
startTimer.countUP();
fill(0);
text(startTimer.getTime(), 20,20);
}
int clickedRow, clickedCol, releasedRow, releasedCol;
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
//visual representation - finish up
//show what is inside board[clickedRow][clikedCol]
//then show what is inside board[releasedRow][releasedCol]
//where the child pressed
fill(random(0,255), random(0,255), random(0,255));
rect(clickedCol*sqSide, clickedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[clickedRow][clickedCol],(clickedCol+0.5)*sqSide, (clickedRow+0.5)*sqSide) ;
//where the child released
fill(random(0,255), random(0,255), random(0,255));
rect(releasedCol*sqSide, releasedRow*sqSide, sqSide, sqSide);
fill(0);
text(board[releasedRow][releasedCol],(releasedCol+0.5)*sqSide, (releasedRow+0.5)*sqSide);
if(gameOver()==true){ //calling function gameOver
background(255);
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
if(mousePressed == true){
setupGame();
}
}
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
There's plenty of good work there, especially when it comes to managing the board / swapping elements / etc. It takes focus to keep it in check.
It also looks like there's a bit of confusion regarding drawing.
You can draw elements once and in draw(); render overlapping elements on top as you are doing now, however you need to pay attention to what needs to be rendered once or multiple times.
The timer text is leaving trails because the background is never cleared, but the board is only drawn once. You will want to redraw the background/board to fix the text, but some bits of code will need to move or need to be handled differently.
For example:
fill(random(0,255), random(0,255), random(0,255));
If you call that in draw() the colours will change continuously you don't want.
You could however generate the colours once in setup() then re-use them in draw() without resetting the values.
There seems to be also some confusion with mouse events and when or in which state should resets happen.
Here's a re-organised version of your code taking into account the notes above:
final int NUM_SQUARES = 4;
int[][] board = new int[NUM_SQUARES][NUM_SQUARES];
// also remember the colours set once in setup() to re-use in draw()
int[][] boardColors = new int[NUM_SQUARES][NUM_SQUARES];
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
// this will store the result of gameOver() once so it can be re-used
boolean isGameOver;
void setup(){
size(500, 500);
setupGame();
}
void setupGame(){
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
clearBoard();
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
shuffleBoard();
}
void clearBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
board[row][col] = 0;
}
}
}
void shuffleBoard(){
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row * sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col + 0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
void draw(){
background(255);
// draw based on state
if(gameOver()){
// render game over state
String s = "Congratulations!";
String d = "Click to start again!";
fill(0);
text(s, 125, 225);
text(d, 125, 250);
// reset game only if clicking in game over state
if(mousePressed == true){
setupGame();
}
}else{
// render game state
startTimer.countUp();
// re-render board
drawBoard();
// render text on top
fill(0);
text(startTimer.getTime(), 20, 30);
}
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return(time);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
It might make it easier to organise a basic finite state machine(FSM).
It sounds more complicated than it is: the basic idea is to isolate functionality per state and tightly handle transitions between states which allow you to reset/update data accordingly. For example a game play state will only have to deal with gameplay related data until the state completes. Similarly the game over state only deals with it's data until it completes (when a user clicks). There are many ways you can write this.
Here's a suggestion organised around how a Processing sketch runs:
setup() is where things get set up once at the start
draw() is where things get updated/rendered
mouse / key / etc. events handle user input
You're already using a class (Timer) this will be very similar:
// the two states
StateDisplay playState;
StateDisplay gameOverState;
// a reference to the current state
StateDisplay currentState;
void setup(){
size(500, 500);
textAlign(CENTER);
// setup each state
playState = new PlayState();
gameOverState = new GameOverState();
// set the reference to the 1st state
currentState = playState;
}
// forward events to the current state: doesn't matter if it's play or game over, they're can all handle it
void draw(){
currentState.draw();
}
void mousePressed(){
currentState.mousePressed();
}
void mouseReleased(){
currentState.mouseReleased();
}
// global function to be called by each state as it exits
// this does the state switch: reset state data as required
void onStateExit(StateDisplay exitingState){
// game play state to game over state
if(exitingState == playState){
// cast each state to access specialised variables
// in this case store the last timer value to display on the game over screen
((GameOverState)gameOverState).timerValue = ((PlayState)playState).startTimer.getTimeFormatted();
// set the state
currentState = gameOverState;
}
// game over state to game play state
if(exitingState == gameOverState){
// reset game
playState.setup();
// set the state
currentState = playState;
}
}
class Timer{
float time;
Timer(float set){
time = set;
}
float getTime(){
return time;
}
String getTimeFormatted(){
return nfc(time, 2);
}
void setTime(float set){
time = set;
}
void countUp(){
time += 1 / frameRate;
}
}
// "parent" state class that all other states will extend
// and inherit functionality from
class StateDisplay{
StateDisplay(){
// as soon as the constructor is called, set up this state
this.setup();
}
void setup(){
// to be overriden by subclass
}
void draw(){
// to be overriden by subclass
}
void mousePressed(){
// to be overriden by subclass
}
void mouseReleased(){
// to be overriden by subclass
}
}
class PlayState extends StateDisplay{
final int NUM_SQUARES = 4;
int[][] board;
int[][] boardColors;
int sqSide;
Timer startTimer;
int clickedRow, clickedCol, releasedRow, releasedCol;
void setup(){
setupGame();
}
void setupGame(){
this.board = new int[NUM_SQUARES][NUM_SQUARES];
this.boardColors = new int[NUM_SQUARES][NUM_SQUARES];
sqSide = width/NUM_SQUARES;
startTimer = new Timer(0);
//populate the board
//generate random number
//check if we have it already inside the array
//if we have, then go on to generate another random number
//if we do not have it, then we can store inside array
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
int randVal;
do{
randVal = int(random(1, NUM_SQUARES*NUM_SQUARES+1) );
}while( searchFor(randVal) );
board[row][col] = randVal;
boardColors[row][col] = color(random(0,255), random(0,255), random(0,255));
}
}
}
boolean searchFor(int itemToBeSearched){
for(int i = 0; i < NUM_SQUARES; i++){
for(int j = 0; j < NUM_SQUARES; j++){
if(itemToBeSearched == board[i][j]){
return true;
}
}
}
return false;
}
//definition of gameOver
boolean gameOver(){
int counter=1;
for(int row=0; row<NUM_SQUARES; row++){
for(int col=0; col<NUM_SQUARES; col++){
if(board[row][col] !=counter){
return false;
}
counter++;
}
}
return true;
}
void drawBoard(){
//visual representation of the board
for(int row = 0; row < NUM_SQUARES; row++){
for(int col = 0; col < NUM_SQUARES; col++){
fill(boardColors[row][col]);
rect(col * sqSide, row*sqSide, sqSide, sqSide);
fill(255);
textSize(30);
text(board[row][col], (col+0.5) * sqSide, (row + 0.5) * sqSide);
}
}
}
void draw(){
// clear screen
background(255);
// redraw board
drawBoard();
// optional: drag and drop visual cue
if(mousePressed){
fill(255, 192);
text(board[clickedRow][clickedCol], mouseX, mouseY);
}
startTimer.countUp();
fill(255);
text(startTimer.getTimeFormatted()+"s", width * 0.5, 30);
}
void mousePressed(){
clickedRow = int(mouseY/sqSide);
clickedCol = int(mouseX/sqSide);
}
void mouseReleased(){
releasedRow = int(mouseY/sqSide);
releasedCol = int(mouseX/sqSide);
//swap
int buffer = board[clickedRow][clickedCol];
board[clickedRow][clickedCol] = board[releasedRow][releasedCol];
board[releasedRow][releasedCol] = buffer;
if(gameOver()){
onStateExit(this);
}
}
}
class GameOverState extends StateDisplay{
// time taken to solve
String timerValue = "";
void draw(){
String s = "Congratulations!\n" +
"Solved in " + timerValue + "s\n" +
"Click to start again!";
background(255);
fill(0);
text(s, width * 0.5, 225);
}
void mouseReleased(){
onStateExit(this);
}
}
The code may look verbose but essentially most of the work that's doing is grouping functionality per state: as if you're running mini-sketches and swapping between them.
The things that may be new are:
extending a class: the class that extends (subclass) will inherit properties/methods from the parent class (superclass)
polymorphism: relying on what subclasses have in common with the superclass to treat them as if they are the same (though internally the implementation for each is different). (e.g. all states have draw(), but each state renders something else)
casting: in this particular case allowing subclass to behave as itself (with all it's extra properties/methods), not just what's shared from the superclass. More specifically in the code above the timer data is passed from game play state to the game over state to display.
Even though it's a bit more work to set up this way it may be worth doing to keep states isolated and easily add more states using the same logic (e.g. a high scores stable, a start / game menu screen / etc.). With each state as a min-sketch you can also keep it organised with tabs, saving time having scroll up and down all the time:
I am making an animation in Processing it is a simulation of a ball going up and coming down, I have an error saying 'NullPointerException' it keeps appearing I will give the code and show the error place:
Obj[] objs = new Obj[100];
void setup(){
size(1000, 1000);
}
void draw(){
background(250);
for(int i = 0; i < objs.length; i++){
objs[i].render();
objs[i].up();
objs[i].run();
}
}
the error is at objs[i].render();
here is the code for Obj:
class Obj{
float x;
float y;
float speed;
float pspeed;
float velocity;
void render(){
fill(0);
ellipse(x, y, 5, 5);
}
void up(){
x = random(-1000, 1000);
y = y-1010;
}
void run(){
speed = random(4, 6);
pspeed = speed;
velocity = 0.05;
while(y<random(700, 1100)){
y=y-speed;
speed=speed-velocity;
}
while(y>0){
y=y+pspeed;
pspeed = pspeed - velocity;
}
}
}
This line creates an array that can hold 100 instances of Obj:
Obj[] objs = new Obj[100];
But it doesn't actually create any instances. In other words, your array contains 100 null values.
Then you're looping through those null values and trying to call functions on them, which is what's causing your error.
To fix the problem, you probably just want to fill your array up with instances:
void setup(){
size(1000, 1000);
for(int i = 0; i < objs.length; i++){
objs[i] = new Obj();
}
}
Shameless self-promotion: I wrote a tutorial on arrays in Processing available here.
I'm having a ton of trouble making a simple video delay in processing. I looked around on the internet and I keep finding the same bit of code and I can't get it to work at all. When I first tried it, it did nothing (at all). Here's my modified version (which at least seems to load frames into the buffer), I really have no idea why it doesn't work and I'm getting really tired of pulling out my hair. Please... please, for the love of god, please somebody point out the stupid mistake I'm making here.
And now, without further delay (hah, get it?), the code:
import processing.video.*;
VideoBuffer vb;
Movie myMovie;
Capture cam;
float seconds = 1;
void setup() {
size(320,240, P3D);
frameRate(30);
String[] cameras = Capture.list();
if (cameras.length == 0) {
println("There are no cameras available for capture.");
exit();
} else {
println("Available cameras:");
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}
cam = new Capture(this, cameras[3]);
cam.start();
}
vb = new VideoBuffer(90, width, height);
}
void draw() {
if (cam.available() == true) {
cam.read();
vb.addFrame(cam);
}
image(cam, 0, 0);
image( vb.getFrame(), 150, 0 );
}
class VideoBuffer
{
PImage[] buffer;
int inputFrame = 0;
int outputFrame = 0;
int frameWidth = 0;
int frameHeight = 0;
VideoBuffer( int frames, int vWidth, int vHeight )
{
buffer = new PImage[frames];
for(int i = 0; i < frames; i++)
{
this.buffer[i] = new PImage(vWidth, vHeight);
}
this.inputFrame = 0;
this.outputFrame = 1;
this.frameWidth = vWidth;
this.frameHeight = vHeight;
}
// return the current "playback" frame.
PImage getFrame()
{
return this.buffer[this.outputFrame];
}
// Add a new frame to the buffer.
void addFrame( PImage frame )
{
// copy the new frame into the buffer.
this.buffer[this.inputFrame] = frame;
// advance the input and output indexes
this.inputFrame++;
this.outputFrame++;
println(this.inputFrame + " " + this.outputFrame);
// wrap the values..
if(this.inputFrame >= this.buffer.length)
{
this.inputFrame = 0;
}
if(this.outputFrame >= this.buffer.length)
{
this.outputFrame = 0;
}
}
}
This works in Processing 2.0.1.
import processing.video.*;
Capture cam;
PImage[] buffer;
int w = 640;
int h = 360;
int nFrames = 60;
int iWrite = 0, iRead = 1;
void setup(){
size(w, h);
cam = new Capture(this, w, h);
cam.start();
buffer = new PImage[nFrames];
}
void draw() {
if(cam.available()) {
cam.read();
buffer[iWrite] = cam.get();
if(buffer[iRead] != null){
image(buffer[iRead], 0, 0);
}
iWrite++;
iRead++;
if(iRead >= nFrames-1){
iRead = 0;
}
if(iWrite >= nFrames-1){
iWrite = 0;
}
}
}
There is a problem inside your addFrame-Method. You just store a reference to the PImage object, whose pixels get overwritten all the time. You have to use buffer[inputFrame] = frame.get() instead of buffer[inputFrame] = frame. The get() method returns a copy of the image.