INTERACTIVe Patterns
In the basic introduction you can learn the programming syntax. However, to make interesting things with code one need to think in terms of combining the different programming components into basic structures. These structures are called patterns. They are similar to having a basic sewing pattern for a shirt, but the end result can be very different depending on how you use it. Programming patterns differ depending on what kind of programming one is doing. When working with interaction design there is a set of commonly known strategies for making interactive elements. The secret trick to mastering interactive programming is to recognize these patterns that makes up structures for common solutions to interactive problems. In the following we have collected the most common patterns that everry interaction design programmer needs to know to create interactions.
Long example: Programming PONG (as a pattern)
In this video I go through the core concepts of programming with P5.JS by programming a simple pong game.
The video is a bit fast paced, so do make sure to pause and scroll back and forth.
Basic Pong:
https://editor.p5js.org/hobyedk/sketches/4T-l65OWi
Correct bounce on all axis:
https://editor.p5js.org/hobyedk/sketches/GrcQM_w8L
Many games are based on this pattern in some form.
Interactive pattern cheat sheet
We have tried to make the examples as generic as possible. Although there are only examples from one platform, it should be relatively simple to convert it to the other. Be aware that the main method in Processing is called draw(), where in Arduino it is called loop(). Simply change the words depending on the platform used.
function draw() {
var btnPressed = mouseIsPressed;
if (btnPressed == true) {
print("Button is down");
} else {
print("Button is up");
}
}
Doing something while a button is pressed
To change something while a button is pressed. The code looks like this.
var posX = 200;
var posY = 200;
var radius = 100;
function setup()
{
createCanvas(400,400);
}
function draw() {
background(0);
if(dist(mouseX, mouseY,posX,posY) <radius/2 )
{
fill(255,0,0);
}
else
{
fill(255);
}
ellipse(posX,posY,radius,radius);
}
Calculating the distance to use for detecting the hover/collision of the mouse
By using the dist() function you can see whether a mouse is over a circle. This is the simplest way to make an interactive button or to detect a collision between the mouse (the player) and an object.
var btnPressedOld = false;
function draw() {
var btnPressed = mouseIsPressed;
if (btnPressed == false && btnPressedOld == true) {
print("Button has been clicked");
}
btnPressedOld = btnPressed;
}
Detecting a push button event
The above example only works for doing something WHILE the button is pressed, and it is not the same as an event. An event is when something changes from one state to another; e.g. you want something to happen when the button is released => going from a pressed state to a not pressed state. This requires us to "remember" the old state an compare it to detect the change.
var btnPressedOld = false;
var toggle = false;
function draw() {
var btnPressed = mouseIsPressed;
if (btnPressed == true && btnPressedOld == false) {
// button has been pressed.
toggle = !toggle;
}
btnPressedOld = btnPressed;
if (toggle == true) {
background(0, 255, 0);
// the butten has been toggled on.
} else {
background(0);
}
}
Make a toggle button
Toggling with a pushbutton is a common solution to turning things on an off. This is one way to do it.
var btnPressedOld = false;
var timer = 0;
function draw() {
// do something every two seconds
if (millis() - timer > 2000) {
timer = millis();
print("tick");
//do something here
}
}
Make an interval timer
To make something happen every x miliseconds. This pattern is a generic solution.
var timeWhenPressed = 0;
var oldMouseState = 0;
var timerActive = false;
function draw() {
if (mouseIsPressed == true) {
timeWhenPressed = millis();
timerActive = true;
}
if (millis() - timeWhenPressed > 2000 && timerActive == true) {
// do something two seconds later
timerActive = false;
print("Two seconds later");
}
}
Timing an event
To time an event; e.g. you want something to happen two seconds after the button is pressed. To do so you need to register the time the button was pressed and look for when the two seconds has passed from then.
var btnPressedOld = false;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(100);
if (mouseX > 100 && mouseX < 200 && mouseY > 100 && mouseY < 200 && mouseIsPressed) {
if (btnPressedOld == false) {
/// Code in here will only run once, when the mouse has clicked within a 100x100 square positioned at 100,100.
print("pressed");
}
btnPressedOld = true;
fill(0, 255, 0);
} else {
btnPressedOld = false;
fill(0,255, 255);
}
rect(100,100,100,100);
}
Detect a mouse click within a square
In Processing you sometimes need to design your own button interaction. To do this, we need to define the active area of the mouse pointer. Here is a simple pattern to solve this problem:
var value = 0;
var speed = 2;
var direction = 1;
function draw() {
value = value + direction * speed;
if (value > 255 || value < 0) {
direction = direction * -1;
}
background(value);
}
Fade in and fade out
To make something fade in and fade out you need to create a counter and add/subtract from it over time.
var positionX = 0;
var speed = 2;
var direction = 1;
function draw() {
positionX = positionX + direction * speed;
if (positionX > width || positionX < 0) {
direction = direction * -1;
}
background(0);
ellipse(positionX, height/2, 20,20);
}
Make an object move
To make something move you need to created a counter and add/subtract from it over time.
var currentState = 0;
var btnPressedOld = 0;
function draw() {
if (mouseIsPressed == false && btnPressedOld == true) {
currentState = currentState + 1;
if (currentState > 2) {
currentState = 0;
}
}
btnPressedOld = mouseIsPressed;
if (currentState == 0) {
background(0);
} else if (currentState == 1) {
background(0, 255, 0);
} else if (currentState == 2) {
background(0, 255, 255);
}
}
Creating a state machine
As the complexity of your code grows you will need to have multiple states where different parts of code should happpen in certain situations. Using a this pattern allows you to compartamentalise which part of the program should in any given moment. Each state represent at certain situation in your porgram. It could be the intro screen in a game, the actual game, the highscore etc.
var buttonPushedTime = 0;
var lastButtonState = false;
function draw() {
background(120);
if (mouseIsPressed && !lastButtonState) {
buttonPushedTime = millis();
}
if (mouseIsPressed && millis() - buttonPushedTime > 3000) {
print("button has been pressed for 3 seconds");
}
lastButtonState = mouseIsPressed;
}
Detecting a long press
Check if a button has been pressed for a particular minimum time (in this example 3 seconds). This can provide safety (e.g. for a reset button, check that someone actually means it, not just touched the button by accident) and provides implicit debouncing of a glitchy signal.
var turnRed = true;
function setup() {
createCanvas(400, 400);
}
var lastShot = 0;
var delay = 1000;
function draw() {
background(220);
if (millis() - lastShot > delay ) {
lastShot = millis();
//shouldBGRed =!shouldBGRed;
if(turnRed == false)
{
turnRed = true;
delay = 1000;
}
else
{
turnRed = false;
delay = 10000;
}
}
if (turnRed == true) {
background(255, 0, 0);
} else {
background(255);
}
}
Toggling with two different delays
Sometimes you want something to be turned on for one second and turned off for 10 seconds. This code does that.
Note: This code can be compressed - this example will toggle the background every one second (but hard to read):
background(255*Math.floor((millis()/1000)%2), 0,0);
var inputBuffer = "";
var inputResult = "";
var newInput = false;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if(newInput==true)
{
print( inputResult);
background(255);
newInput=false;
}
}
function keyPressed()
{
//print(key);
if(key != "Enter" && key!= "Control" && key != "Shift")
{
inputBuffer = inputBuffer + key;
}
else if(key == "Enter")
{
inputResult = inputBuffer;
inputBuffer = "";
newInput = true;
}
}
Reading a line from the keyboard
This collects all the keypress characters until return has been pressed.
var balls = [];
function setup() {
createCanvas(400, 400);
// generat many objects at random positions
for(let i = 0; i < 20;i++)
{
// create a random vector postions
var randomPos = createVector(random(width), random(height));
// add it to the list
balls.push(randomPos);
}
}
function draw() {
background(220);
// loop through the ball vector array and
// draw an ellipse at their positions
for(var i = 0; i < balls.length; i++){
ellipse(balls[i].x, balls[i].y, 20,20);
}
}
Generating multiple objects
This little example generates multiple objects. It uses an array of vectors. Vectors contain both and x and y coordinate.