xxxxxxxxxx
let bubbles = [];
let bodyPose;
let poses = [];
let video;
let points = [];
// Matter.js
let Engine = Matter.Engine;
let World = Matter.World;
let Bodies = Matter.Bodies;
let engine;
let world;
// OpenCV
var src, dst, cap;
function preload() {
bodyPose = ml5.bodyPose();
}
function setup() {
video = createCapture(VIDEO);
video.size(1280, 720);
video.hide();
bodyPose.detectStart(video, gotPoses);
// OpenCV setup
src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
dst = new cv.Mat(video.height, video.width, cv.CV_8UC1);
cap = new cv.VideoCapture(video.elt);
createCanvas(video.width, video.height);
// Matter.js setup
engine = Engine.create();
world = engine.world;
// Criando o chão
let ground = Bodies.rectangle(width / 2, height, width, 20, { isStatic: true });
World.add(world, ground);
// Criando as paredes
let leftWall = Bodies.rectangle(0, height / 2, 20, height, { isStatic: true });
let rightWall = Bodies.rectangle(width, height / 2, 20, height, { isStatic: true });
World.add(world, [leftWall, rightWall]);
}
function draw() {
background(0);
processVideo(points);
// Invert video horizontally on the canvas
translate(width, 0);
scale(-1, 1);
// Draw detected contours
stroke(255);
noFill();
points.forEach(coords => {
beginShape();
coords.forEach(coord => {
vertex(coord.x, coord.y);
});
endShape();
});
// Add new bubbles at random intervals
if (frameCount % 20 === 0) {
let size = random(50, 100);
let bubble = new Bubble(random(0, width), -size, size);
bubbles.push(bubble);
World.add(world, bubble.body); // Add to Matter.js world
}
// Update and display bubbles
Engine.update(engine); // Update Matter.js physics engine
for (let i = bubbles.length - 1; i >= 0; i--) {
let bubble = bubbles[i];
for (let k = 0; k < poses.length; k++) {
let pose = poses[k];
for (let j = 0; j < pose.keypoints.length; j++) {
let keypoint = pose.keypoints[j];
let x = keypoint.x;
let y = keypoint.y;
if (bubble.checkCollision(x, y)) {
if (bubble.exploded && bubble.particles.length === 0) {
World.remove(world, bubble.body); // Remove from Matter.js world
bubbles.splice(i, 1); // Remove from the array
}
break;
}
}
}
bubble.update();
bubble.display();
}
}
function gotPoses(results) {
poses = results;
}
class Bubble {
constructor(x, y, size) {
this.size = size;
this.x = x;
this.y = y;
this.speed = random(1, 3);
this.particles = [];
this.exploded = false;
// Create a Matter.js circle body
this.body = Bodies.circle(this.x, this.y, this.size / 2, {
restitution: 0.8, // Bounciness
friction: 0.01,
density: 0.01
});
}
update() {
// Update the bubble's position using Matter.js body position
this.x = this.body.position.x;
this.y = this.body.position.y;
// If exploded, handle the particles
if (this.exploded) {
for (let i = this.particles.length - 1; i >= 0; i--) {
this.particles[i].update();
if (this.particles[i].isFinished()) {
this.particles.splice(i, 1);
}
}
}
}
display() {
if (!this.exploded) {
push();
translate(this.x, this.y);
// Draw bubble outline with gradient effect
for (let i = 0; i < 10; i++) {
stroke(255, map(i, 0, 10, 100, 0));
strokeWeight(1);
noFill();
ellipse(0, 0, this.size + i);
}
// Soft internal fill
fill(255, 255, 255, 30);
noStroke();
ellipse(0, 0, this.size);
// Reflection effect
fill(255, 255, 255, 50);
noStroke();
ellipse(-this.size * 0.2, -this.size * 0.2, this.size * 0.3, this.size * 0.3);
// Small highlight at the bottom
fill(255, 255, 255, 30);
ellipse(this.size * 0.2, this.size * 0.2, this.size * 0.1, this.size * 0.1);
pop();
} else {
for (let particle of this.particles) {
particle.display();
}
}
}
checkCollision(x, y) {
let d = dist(this.x, this.y, x, y);
if (d < this.size / 2 && !this.exploded) {
this.explode();
}
return this.exploded && this.particles.length === 0;
}
explode() {
this.exploded = true;
for (let i = 0; i < 100; i++) {
let angle = random(TWO_PI);
let speed = random(2, 5);
let vx = cos(angle) * speed;
let vy = sin(angle) * speed;
this.particles.push(new Particle(this.x, this.y, vx, vy));
}
}
}
class Particle {
constructor(x, y, vx, vy) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.alpha = 255;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.alpha -= 20; // Explode faster
}
display() {
noStroke();
fill(255, this.alpha);
ellipse(this.x, this.y, 4);
}
isFinished() {
return this.alpha <= 0;
}
}
function processVideo() {
try {
cap.read(src);
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(dst, dst, 120, 200, cv.THRESH_BINARY);
var contours = new cv.MatVector();
var hierarchy = new cv.Mat();
cv.findContours(dst, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);
points = [];
for (var i = 0; i < contours.size(); ++i) {
var cnt = contours.get(i);
var coords = [];
for (var j = 0; j < cnt.data32S.length; j += 2) {
coords.push({x: cnt.data32S[j], y: cnt.data32S[j+1]});
}
points.push(coords);
cnt.delete();
}
contours.delete();
hierarchy.delete();
} catch (err) {
console.log(err);
}
}
function modelReady() {
console.log("Handpose model ready!");
}