It's great you're already splitting what you're trying to achieve into steps:
Divide the screen into four quadrants (as if it were displaying feed from security cameras, but I'd be using videos, for the most
part)
Have videos load randomly to those quadrants (from a total of 8 videos) and have the videos change after a certain number of seconds (they don't all have to change at once, but whatever's easiest)
Have a webcam send its feed into one of the quadrants as if it were another video
It looks like you've already tackled the first section.
I would split the second section further:
- trigger a change after a certain number of seconds (time it)
- pick a random quadrant / video
Trigger an action after a certain delay can be achieved using millis() and conditional. You can see an example and more details here
Regarding the picking random quadrant / video, you're very close: random()
should do the trick. The trickier part is how you organize your data.
One option would be to keep track of two arrays:
- a list(array) of videos to display
- a list of quadrants pointing to a subset of the above list of videos
The videos will always be accessible, but only a selection will be displayed. Simply store the indices of the videos from the first list (of loaded videos) into a second list (the video selection)
I would also recommend getting into the habit of grouping a set of instructions that perform a task into a function. This way the code will be easier to read/follow, use and especially re-use.
I'm not sure if you're familiar with functions already, as in writing them from scratch, but you've been using them quite a lot so far :)
If you haven't used them, they're not that hard to pick up.
Here's an attempt at over simplifying the idea to get to use one right away.
You've called smooth()
for example and you've written void setup(){}
and placed a group of instructions inside.
Similarly you can define your own function with whatever name you want:
void myFunction(){
println("myFunction is working!");
}
which you can then easily call:
myFunction();
e.g.
void draw(){
}
void keyPressed(){
myFunction();
}
void myFunction() {
println("myFunction is working!");
ellipse(random(width),random(height),10,10);
}
I'll admit, it's not the most exciting example, but it should prove how simple it is to define and use a function. There are other details like the function return types and arguments, but you can get away getting into these yet.
Let's apply this knowledge to make a function randomises videos which can be easily called when the 'r' key is pressed:
import processing.video.*;
Capture cam;
int maxmyMovies = 8;
int myMoviesIndex = 0;
Movie[] myMovies = new Movie[maxmyMovies];
int[] selection = {0,1,2,3};
void setup() {
size(640, 480);
cam = new Capture(this, 640, 480, 12);
cam.start();
smooth();
for (int i = 0; i < myMovies.length; i ++ ) {
myMovies[i] = new Movie(this, i + ".mov");
}
selectRandomVideos();
}
void selectRandomVideos(){
//select random movie for each quadrant
for(int i = 0 ; i < selection.length; i++){
//random() returns a float and the index in an int, therefore we cast to (int)
//this also has the side effect to rounding down (similar to floor()) which is convenient as we need 7 as the highest index
selection[i] = (int)random(0,maxmyMovies);
myMovies[selection[i]].loop();
myMovies[selection[i]].volume(0);
}
}
void draw() {
//top left
image(myMovies[selection[0]], 0, 0);
//top right
image(myMovies[selection[1]], 640, 0);
//bottom left
image(myMovies[selection[2]], 0, 480);
//bottom right
image(myMovies[selection[3]], 640, 480);
}
void keyPressed(){
if(key == 'r') selectRandomVideos();
}
void movieEvent(Movie myMovies) {
myMovies.read();
}
Note: The above code isn't tested and the video size isn't set (so either you have the videos at the correct resolution or set the width/height when calling image()
as you previously did). The code may not run as it is, but hopefully should illustrate an approach to solving the problems above.
So this is a very basic way of randomising videos and it's doing that to all of them at the same time. This function an be tweaked to handle a single video at a time:
void selectRandomVideo(){
//select random movie for one quadrant
//pick a quadrant
int randomQuadrant = (int)random(4);
//pick a video
int randomVideo = (int)random(maxmyMovies);
//store the random video index in the random quadrant
selection[randomQuadrant] = randomVideo;
//loop the random quadant's video and mute
myMovies[selection[randomQuadrant]].loop();
myMovies[selection[randomQuadrant]].volume(0);
}
and integrated:
import processing.video.*;
Capture cam;
int maxmyMovies = 8;
int myMoviesIndex = 0;
Movie[] myMovies = new Movie[maxmyMovies];
int[] selection = {0,1,2,3};
void setup() {
size(640, 480);
cam = new Capture(this, 640, 480, 12);
cam.start();
smooth();
for (int i = 0; i < myMovies.length; i ++ ) {
myMovies[i] = new Movie(this, i + ".mov");
}
selectRandomVideos();
}
void selectRandomVideos(){
//select random movie for each quadrant
for(int i = 0 ; i < selection.length; i++){
//random() returns a float and the index in an int, therefore we cast to (int)
//this also has the side effect to rounding down (similar to floor()) which is convenient as we need 7 as the highest index
selection[i] = (int)random(0,maxmyMovies);
myMovies[selection[i]].loop();
myMovies[selection[i]].volume(0);
}
}
void selectRandomVideo(){
//select random movie for one quadrant
//pick a quadrant
int randomQuadrant = (int)random(4);
//pick a video
int randomVideo = (int)random(maxmyMovies);
//store the random video index in the random quadrant
selection[randomQuadrant] = randomVideo;
//loop the random quadant's video and mute
myMovies[selection[randomQuadrant]].loop();
myMovies[selection[randomQuadrant]].volume(0);
}
void draw() {
//top left
image(myMovies[selection[0]], 0, 0);
//top right
image(myMovies[selection[1]], 640, 0);
//bottom left
image(myMovies[selection[2]], 0, 480);
//bottom right
image(myMovies[selection[3]], 640, 480);
}
void keyPressed(){
if(key == 'r') selectRandomVideo();
}
void movieEvent(Movie myMovies) {
myMovies.read();
}
Using something like this and the millis()
based timer should solve the second section.
For the third section you can use the same trick. It might help if you use a for loop to display the videos in quadrants instead of using repetitive image()
calls. Within the loop you could use a condition to decide whether a quadrant needs to display a video or the camera feed.
We can use a separate variable to keep track of what quadrant should the camera be displayed in, then put together a basic function that sets this value using random:
void selectRandomCameraQuadrant(){
//selects a valid index (0-3) or an invalid one (4) which means disable the camera
cameraIndex = (int)random(5);
}
There's a little hack above where random(5)
is used instead of random(4)
.
This would give a chance every once in a while of getting an index that isn't a valid quadrant and therefore wouldn't display the camera feed all the time.
Here's a version of the code using this function and the 'c' key to pick a random camera feed quadrant:
import processing.video.*;
Capture cam;
int maxmyMovies = 8;
int myMoviesIndex = 0;
Movie[] myMovies = new Movie[maxmyMovies];
int[] selection = {0,1,2,3};
int cameraIndex = -1;
void setup() {
size(640, 480);
cam = new Capture(this, 640, 480, 12);
cam.start();
smooth();
for (int i = 0; i < myMovies.length; i ++ ) {
myMovies[i] = new Movie(this, i + ".mov");
}
selectRandomVideos();
}
void selectRandomVideos(){
//select random movie for each quadrant
for(int i = 0 ; i < selection.length; i++){
//random() returns a float and the index in an int, therefore we cast to (int)
//this also has the side effect to rounding down (similar to floor()) which is convenient as we need 7 as the highest index
selection[0] = (int)random(0,maxmyMovies);
myMovies[selection[0]].loop();
myMovies[selection[0]].volume(0);
}
}
void selectRandomVideo(){
//select random movie for one quadrant
//pick a quadrant
int randomQuadrant = (int)random(4);
//pick a video
int randomVideo = (int)random(maxmyMovies);
//store the random video index in the random quadrant
selection[randomQuadrant] = randomVideo;
//loop the random quadant's video and mute
myMovies[selection[randomQuadrant]].loop();
myMovies[selection[randomQuadrant]].volume(0);
}
void selectRandomCameraQuadrant(){
//selects a valid index (0-3) or an invalid one (4) which means disable the camera
cameraIndex = (int)random(5);
}
void draw() {
//movie quadrant index
int movieIndex = 0;
//loop through y
for(int yIndex = 0; yIndex < 2; yIndex++){
//loop through x
for(int xIndex = 0; xIndex < 2; xIndex++){
//calculate x position based on index
int x = xIndex * 640;
int y = yIndex * 480;
//check if the camera index matches any of the quadrants (if so display camera, otherwise display movie)
if(movieIndex == cameraIndex){
image(cam, x, y);
}else{
image(myMovies[selection[movieIndex]], x, y);
}
//increment movie quadrant index
movieIndex++;
}
}
}
void keyPressed(){
if(key == 'r') selectRandomVideo();
if(key == 'c') selectRandomCameraQuadrant();
}
void movieEvent(Movie myMovies) {
myMovies.read();
}
Final notes This isn't the best/cleanest way to solve the problem, but an idea. There are multiple ways the same can be achieved.