xxxxxxxxxx
383
//A kitten eats fish in the sea, press shift to accelerate, facemesh is used to display fish schools, and bodymesh is used to display floating objects in the water. The sound from the microphone can make the kitten open its mouth.
let mic;
let video;
let poseNet;
let poses = [];
let predictions = [];
let canvas_w = 800;
let canvas_h = 600;
let margin = 50;
let margin_left = 50;
let margin_top = 50;
//pictures
let catimg;
let openmouth;
let closemouth;
let catsize;
let balls = [];
let speedx;
function preload() {
catimg = loadImage('assets/popcat.gif');
openmouth = loadImage('assets/open.png');
closemouth = loadImage('assets/shutup.png');
}
function setup() {
createCanvas(640, 480);
video = createCapture(VIDEO);
video.size(width, height);
// Create a new poseNet method with a single detection
poseNet = ml5.poseNet(video, poseNetModelReady);
// This sets up an event that fills the global variable "poses"
// with an array every time new poses are detected
poseNet.on("pose", function (results) {
poses = results;
});
// Hide the video element, and just show the canvas
facemesh_layer = createGraphics(width, height);
body_keypoints_layer = createGraphics(width, height);
skeleton_layer = createGraphics(width, height);
video.hide();
//
//microphone
let cnv = createCanvas(canvas_w, canvas_h);
mic=new p5.AudioIn();
mic.start();
cnv.mousePressed(userStartAudio);
//气泡
for (let i = 0; i < 50; i++) {
balls.push(new Ball(random(width), random(height)));
}
//鱼
fish1 = new Fish();
fish2 = new Fish();
fish3 = new Fish();
}
function poseNetModelReady() {
console.log("poseNet Model ready!");
facemesh = ml5.facemesh(video, faceMeshModelReady);
facemesh.on("predict", (results) => {
predictions = results;
});
}
function faceMeshModelReady() {
console.log("faceMesh Model ready!");
}
// We can call both functions to draw all keypoints and the skeletons
//----------------------------------------------------------------------
function draw() {
if (frameCount % 1 == 0) {
clearScreen();
}
// We can call both functions to draw all keypoints and the skeletons
drawBackground_1();
drawFacemeshKeypoints();
//drawSkeleton();
drawBodyKeypoints();
//image(video, 0, 0, width, height);
image(facemesh_layer, 0, 0, width, height);
image(skeleton_layer, 0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].move();
balls[i].draw();
}
image(body_keypoints_layer, 0, 0, width, height);
//image(video, margin_left, margin_top, video_w, video_h);
//气泡
//小猫在脸上随着声音变化
drawMicLevel();
}
// A function to draw ellipses over the detected keypoints
function drawBodyKeypoints() {
// Loop through all the poses detected
for (let i = 0; i < poses.length; i++) {
// For each pose detected, loop through all the keypoints
let pose = poses[i].pose;
for (let j = 0; j < pose.keypoints.length; j++) {
// A keypoint is an object describing a body part (like rightArm or leftShoulder)
let keypoint = pose.keypoints[j];
let x = keypoint.position.x;
let y = keypoint.position.y;
// Only draw an ellipse is the pose probability is bigger than 0.2
if (keypoint.score > 0.2) {
body_keypoints_layer.push();
if (j == 1 || j == 2) {
body_keypoints_layer.textSize(40);
body_keypoints_layer.text("🦈", x, y);
}
else if (j == 9 || j == 10) {
body_keypoints_layer.textSize(84);
body_keypoints_layer.text("🛟", x, y);
}
else if (j == 5 || j == 6) {
body_keypoints_layer.textSize(84);
body_keypoints_layer.text("🧊", x, y);
}
else if (j == 7 || j == 8) {
body_keypoints_layer.textSize(84);
body_keypoints_layer.text("🧊", x, y);
}
body_keypoints_layer.pop();
}
}
}
}
function drawFacemeshKeypoints() {
for (let i = 0; i < predictions.length; i += 1) {
const keypoints = predictions[i].scaledMesh;
// Draw facial keypoints.
for (let j = 0; j < keypoints.length; j += 1) {
const [x, y] = keypoints[j];
facemesh_layer.push();
facemesh_layer.textSize(20);
// Place three different fish emojis randomly on the face
if (j % 100 === 0) {
facemesh_layer.text(fish1.getRandomEmoji(), x, y);
} else if (j % 75 === 0) {
facemesh_layer.text(fish2.getRandomEmoji(), x, y);
} else if (j % 50 === 0) {
facemesh_layer.text(fish3.getRandomEmoji(), x, y);
}
facemesh_layer.pop();
}
}
}
//暂时不需要骨架
// A function to draw the skeletons
function drawSkeleton() {
// Loop through all the skeletons detected
for (let i = 0; i < poses.length; i++) {
let skeleton = poses[i].skeleton;
// For every skeleton, loop through all body connections
for (let j = 0; j < skeleton.length; j++) {
let partA = skeleton[j][0];
let partB = skeleton[j][1];
skeleton_layer.push();
skeleton_layer.strokeWeight(10);
skeleton_layer.stroke("DodgerBlue");
skeleton_layer.line(
partA.position.x,
partA.position.y,
partB.position.x,
partB.position.y
);
skeleton_layer.pop();
}
}
}
// Miclevel猫猫变大
function drawMicLevel() {
push();
micLevel = mic.getLevel();
noStroke();
pop();
push();
translate(margin_left, margin_top);
catsize = map(micLevel,0,0.8,200,500);
if (catsize<220){
image(closemouth,mouseX-90,mouseY-90,catsize/2,catsize/2);
}
else{
image(openmouth,mouseX-90,mouseY-90,catsize/2,catsize/2);
}
pop();
}
class Ball {
constructor(x, y) {
this.x = x;
this.y = y;
this.d = random(5, 20);
this.color = random(["#FCFCFC","#7FDBCC"]);
}
move() {
if (keyIsPressed === true) {
this.x -=3;
this.y-=1
if (this.y < 0||this.x < 0) {
this.reappear();
}
}
else {
this.y -= 3;
if (this.y < 0) {
this.reappear();
}
}
}
reappear() {
this.x = random(width);
this.y = random(height);
this.d = random(5, 20);
}
draw() {
fill(this.color);
stroke("rgb(4,0,255)");
circle(this.x, this.y, this.d);
}
}
function drawCloud(x,y,s){
push();
noStroke();
translate(x,y);
scale(s);
fill("rgb(255,255,255)")
circle(20+x,20+y,20);
circle(30+x,25+y,10);
circle(15+x,20+y,15);
pop();
}
function drawHouse(x, y, s,housecolor) {
push();
translate(x, y);
scale(s);
noStroke();
// wall
fill("#F6F398");
rect(100, 200, 220, 200);
// roof
fill("#CBF3F4");
triangle(80, 200, 340, 200, 210, 100);
fill("#39DEFF");
triangle(80, 200, 100, 200, 210, 100);
// door
fill("#5738C3");
rect(195, 300, 40, 100);
// house
fill(housecolor);
rect(100, 200, 220, 150);
// windows
fill("#E6EFFF");
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
rect(120 + i * 50, 220 + j * 30, 30, 20);
}
}
pop();
}
//以下函数无需修改
//background1 black&white star background
function drawBackground_1() {
if (keyIsPressed === true) {
speedx=frameCount*2
} else {
speedx=frameCount/2
}
background("#2196F3");
push();
noStroke();
fill("#014276");
drawCloud(0+(0.1*speedx)%width,1,1.5);
drawCloud(0+(0.1*speedx)%width,1,2.5);
drawCloud(30+(0.1*speedx)%width,8,3.5);
drawCloud(60+(0.1*speedx)%width,3,5);
drawCloud(400+(0.1*speedx)%width,4,10);
for (let i = 0; i < 6; i++) {
drawHouse((150*i+1.5*speedx)%width,520 ,0.2,"white"); //anora
drawHouse((50+150*i+1.5*speedx)%width, 520, 0.2,"#3562F2"); //anora
drawHouse((100+150*i+1.5*speedx)%width,550, 0.15,"#00D28B"); //anora
}
}
//星星函数
function star(x, y, radius1, radius2, npoints) {
let angle = TWO_PI / npoints;
let halfAngle = angle / 2.0;
beginShape();
for (let a = 0; a < TWO_PI; a += angle) {
let sx = x + cos(a) * radius2;
let sy = y + sin(a) * radius2;
vertex(sx, sy);
sx = x + cos(a + halfAngle) * radius1;
sy = y + sin(a + halfAngle) * radius1;
vertex(sx, sy);
}
endShape(CLOSE);
}
class Fish {
constructor() {
this.fishes = ["🐟", "🐠", "🐡"];
this.selectedFish = ""; // To store the randomly selected fish emoji
this.isFishSelected = false; // Flag to track if the fish emoji has been selected
}
getRandomEmoji() {
if (!this.isFishSelected) {
let randomIndex = Math.floor(Math.random() * this.fishes.length);
this.selectedFish = this.fishes[randomIndex];
this.isFishSelected = true;
}
return this.selectedFish;
}
}
function clearScreen() {
facemesh_layer.clear();
skeleton_layer.clear();
body_keypoints_layer.clear();
}