xxxxxxxxxx
228
//Start running the sketch, wait for it to load for a little while, and then start dancing! This sketch is activated by the classic disco "point move" (reference https://www.pinterest.com/pin/687150855617652957/ if you don't know what I'm talking about)
//this sketch uses ml5.js and p5.sound
let video;
let bodyPose;
let poses = [];
let connections;
let leftPointingUp = false;
let leftPointingDown = false;
let rightPointingUp = false;
let rightPointingDown = false;
let discoMode = false;
let discoball;
let sunglasses;
let discoballY = -100;
let tintalpha = 0;
let lastSwitchTime = 0;
let leftFlipCount = 0;
let rightFlipCount = 0;
let lastLeftPositionUp = false;
let lastRightPositionUp = false;
let colorSwitchTime = 0;
let colorIndex = 0;
let extraPurpleDelay = true;
let sunglassesX = 0, sunglassesY = 0, sunglassesScale = 1;
let targetSunglassesX = 0, targetSunglassesY = 0, targetSunglassesScale = 1;
let colors = [
[179, 56, 255],
[56, 141, 255],
[255, 56, 150]
];
let songs = [];
let currentSong;
let songsLoaded = 0;
function preload() {
bodyPose = ml5.bodyPose();
discoball = loadImage('discoball.png');
sunglasses = loadImage('sunglasses.png');
}
function setup() {
createCanvas(640, 480);
discoball.resize(100, 100);
video = createCapture(VIDEO);
video.size(640, 480);
video.hide();
bodyPose.detectStart(video, gotPoses);
connections = bodyPose.getSkeleton();
// Load songs into the songs array with loaded callbacks. https://thecodingtrain.com/tracks/sound/sound/1-loading-and-playing
songs = [
loadSound('rasputin.mp3', songLoaded),
loadSound('hotstuff.mp3', songLoaded),
loadSound('funkytown.mp3', songLoaded),
loadSound('dancingqueen.mp3', songLoaded),
loadSound('stayingalive.mp3', songLoaded),
loadSound('lefreak.mp3', songLoaded)
];
}
function songLoaded() {
songsLoaded++;
}
function draw() {
if (songsLoaded < songs.length) {
console.log("Songs loading...");
}
image(video, 0, 0, width, height);
detectDiscoMode();
//multiple events are triggered when the sketch enters 'discoMode' (see the detectDiscoMode function below for more information on the criteria for discoMode being active). A purple overlay fades in, and then the overlay begins switching between pink, purple, and blue, a discoball lowers from the ceiling, sunglasses appear on the user's face, and one of six random songs start playing
if (discoMode) {
if (tintalpha < 100) {
tintalpha += 5;
} else {
let currentTime = millis();
if (extraPurpleDelay) {
colorSwitchTime = currentTime;
extraPurpleDelay = false;
} else if (currentTime - colorSwitchTime > 1000) {
colorIndex = (colorIndex + 1) % colors.length;
colorSwitchTime = currentTime;
}
}
fill(colors[colorIndex][0], colors[colorIndex][1], colors[colorIndex][2], tintalpha);
noStroke();
rect(0, 0, width, height);
// Discoball descent
if (discoballY < 50) {
discoballY += 5;
}
// sunglasses
if (poses.length > 0) {
let pose = poses[0];
let leftEye = pose.keypoints[1];
let rightEye = pose.keypoints[2];
let eyeDistance = dist(leftEye.x, leftEye.y, rightEye.x, rightEye.y);
targetSunglassesX = (leftEye.x + rightEye.x) / 2;
targetSunglassesY = (leftEye.y + rightEye.y) / 2 - eyeDistance * 0.3;
targetSunglassesScale = eyeDistance / sunglasses.width * 2.5;
// lerping of sunglasses movement
sunglassesX = lerp(sunglassesX, targetSunglassesX, 0.1);
sunglassesY = lerp(sunglassesY, targetSunglassesY, 0.1);
sunglassesScale = lerp(sunglassesScale, targetSunglassesScale, 0.1);
push();
translate(sunglassesX, sunglassesY);
scale(sunglassesScale);
imageMode(CENTER);
image(sunglasses, 0, 0);
pop();
}
if (songsLoaded === songs.length && (!currentSong || !currentSong.isPlaying())) {
playRandomSong();
}
}
image(discoball, 100, discoballY);
stroke('white');
strokeWeight(3);
line(150, 0, 150, discoballY);
}
// Function to detect if discoMode should be activated. It activates when it detects that the user has raised either wrist above their head, then down to be within 100 pixels of their hip, then up above their head again in a sequence of 3 steps. It continues to be active for as long as that sequence continues. If too much time passes between steps, the user is assumed to have stopped dancing and discoMode is deactivated.
function detectDiscoMode() {
for (let i = 0; i < poses.length; i++) {
let pose = poses[i];
let leftWrist = pose.keypoints[9];
let rightWrist = pose.keypoints[10];
let nose = pose.keypoints[0];
let leftHip = pose.keypoints[11];
let rightHip = pose.keypoints[12];
leftPointingUp = leftWrist.y < nose.y;
leftPointingDown = Math.abs(leftWrist.y - leftHip.y) < 100;
rightPointingUp = rightWrist.y < nose.y;
rightPointingDown = Math.abs(rightWrist.y - rightHip.y) < 100;
let currentTime = millis();
if (leftPointingUp && !lastLeftPositionUp) {
leftFlipCount++;
lastSwitchTime = currentTime;
lastLeftPositionUp = true;
} else if (leftPointingDown && lastLeftPositionUp) {
leftFlipCount++;
lastSwitchTime = currentTime;
lastLeftPositionUp = false;
}
if (rightPointingUp && !lastRightPositionUp) {
rightFlipCount++;
lastSwitchTime = currentTime;
lastRightPositionUp = true;
} else if (rightPointingDown && lastRightPositionUp) {
rightFlipCount++;
lastSwitchTime = currentTime;
lastRightPositionUp = false;
}
//checks to see if the up-down-up sequence has occured
if ((leftFlipCount >= 3 || rightFlipCount >= 3) && !discoMode) {
discoMode = true;
leftFlipCount = 0;
rightFlipCount = 0;
extraPurpleDelay = true;
}
//resets variables if too much time passes between up-down state switches
if (discoMode && (currentTime - lastSwitchTime >= 2500)) {
discoMode = false;
tintalpha = 0;
discoballY = -100;
colorIndex = 0;
extraPurpleDelay = true;
if (currentSong) currentSong.stop();
}
}
}
function playRandomSong() {
if (currentSong && currentSong.isPlaying()) {
currentSong.stop();
}
let randomIndex = floor(random(songs.length));
currentSong = songs[randomIndex];
if (currentSong) {
currentSong.play();
}
}
function gotPoses(results) {
poses = results;
}