/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Final Project
*/
//This program uses images to simulate an interactive dressup game.
//It allows users to click on items which will then jump to the
//front of the screen via reordering of the array. Users can drag
//clothing close to the body, where it will then snap into place
//in a smooth motion. When a shirt is snapped onto the body, a button
//will appear that allows the user to recolor the shirt (if clothing is
//layered, only the top layer will be recolored). There is additional
//functionality for resetting the canvas and randomizing outfits.
//stores figure and clothing image links
var croquisLink = "https://i.imgur.com/7aZm27c.png";
var hairLinks = ["https://i.imgur.com/SwP45yO.png",
"https://i.imgur.com/TqmIRYi.png",
"https://i.imgur.com/JqFGPxq.png",
"https://i.imgur.com/QzqTfIY.png",
];
var shirtLinks = ["https://i.imgur.com/vNLNc6V.png",
"https://i.imgur.com/e3LzXk6.png",
"https://i.imgur.com/tBuSMNk.png",
"https://i.imgur.com/wkJ7JJC.png"
];
var pantsLinks = ["https://i.imgur.com/hyAxaOY.png",
"https://i.imgur.com/yk3zFDt.png",
"https://i.imgur.com/mF21MeN.png",
"https://i.imgur.com/ki89EhN.png"
];
var shoesLinks = ["https://i.imgur.com/EMbMtDy.png",
"https://i.imgur.com/IZaU3Ls.png",
"https://i.imgur.com/xa3Rrjs.png",
"https://i.imgur.com/S8GJRGa.png"
];
//loads images for figure and clothing
var croquis;
var hair = [];
var shirt = [];
var pants = [];
var shoes = [];
//stores clothing objects
var blouse = [];
var bottom = [];
var feet = [];
//positions for figure and clothing
var bodyCenter = 120;
var headCenterY = 87;
var shirtCenter = 224;
var pantsCenter = 389;
var shoesCenter = 544;
//stores colors for clothing
var wheel = ["white", "red", "turquoise", "green"];
//image link for color wheel
var colorLink = "https://upload.wikimedia.org/wikipedia/commons/d/dc/Eight-colour-wheel-2D.png";
//stores color wheel image
var colorWheel;
//positions for wheel
var wheelX = 40;
var wheelY = 140;
//positions for random button
var randomX = 490;
var randomY = 580;
//positions for direction button
var infoX = 560;
var infoY = 580;
//counters for changing hair style and clothing color
var hairClick = 0;
var colorClick = 0;
//reset and random button color
var buttonColor = 255;
//indicate that pants and shoes are not being dragged
var dragBottom = false;
var dragFeet = false;
//array position of shirt on body
var wearing;
//display directions
var showInfo = false;
//------------------------------------------------------------------
//loads images into variables and arrays
function preload() {
croquis = loadImage(croquisLink);
colorWheel = loadImage(colorLink);
for (var i = 0; i < hairLinks.length; i++) {
hair[i] = loadImage(hairLinks[i]);
shirt[i] = loadImage(shirtLinks[i]);
pants[i] = loadImage(pantsLinks[i]);
shoes[i] = loadImage(shoesLinks[i]);
}
}
function setup() {
createCanvas(600, 600);
//calls function to make clothing objects and arrange on the page
clothesSetup();
}
//fills shirt, shoes and pants arrays with objects containing images and positions
//serves as a reset function when mix() and reset() are called
function clothesSetup() {
hairClick = 0;
for (var i = 0; i < 4; i++) {
blouse[i] = makeItem(shirt[i], width * 0.48 + 81 * i,
height * 0.15 + 20 * i, shirtCenter);
bottom[i] = makeItem(pants[i], width * 0.49 + 77 * i,
height * 0.55 + 10 * i, pantsCenter);
feet[i] = makeItem(shoes[i], width * 0.49 + 77 * i,
height * 0.85 + 5 * i, shoesCenter);
}
}
function draw() {
background(206, 255, 181);
imageMode(CENTER);
//displays figure
image(croquis, bodyCenter, height / 2, 225, 600);
//displays clothing
for (var i = 0; i < shirt.length; i++) {
//draws current hair style
image(hair[hairClick % 4], bodyCenter, headCenterY);
//draws all pants, shirts and shoes
bottom[i].draw();
blouse[i].draw();
feet[i].draw();
//if shirt is on the body, store index and make color wheel appear
if (blouse[i].x == bodyCenter) {
drawWheel();
wearing = i;
}
}
//calls function to fit clothing on the figure
snap(blouse);
snap(bottom);
snap(feet);
//calls reset function
reset();
//calls direction function
directions();
//If the mouse is not being pressed, reset drag state to false
//Note: this will be utilized in the mouseDragged function to prevent
//multiple items from being "picked up" at once
if (!mouseIsPressed) {
dragBottom = false;
dragFeet = false;
}
//draw random button
drawButton("random", randomX, randomY, buttonColor);
drawButton("directions", infoX, infoY, buttonColor);
}
function mousePressed() {
//HAIR STYLE----------------------------------------------------
//distance from mouse to head
var dHair = dist(mouseX, mouseY, bodyCenter, headCenterY);
//if hair is clicked, increase counter to display different style
if (dHair < 60) hairClick++;
//--------------------------------------------------------------
var click = false; //tracks if a clothing item has been selected
var selection; //stores type of selected item
//SHIRT---------------------------------------------
//cycle through shirt positions
for (var i = 0; i < blouse.length; i++) {
var dBlouse = dist(mouseX, mouseY, blouse[i].x, blouse[i].y);
//if shirt is clicked, store the array and index
if (dBlouse < 75) {
index = i;
click = true;
selection = blouse;
}
}
//PANTS-------------------------------------------
//cycle through pants positions
for (var i = 0; i < bottom.length; i++) {
var dBottomX = abs(mouseX - bottom[i].x);
var dBottomY = abs(mouseY - bottom[i].y);
//if pants are clicked, store the array and index
if (dBottomX < 60 & dBottomY < 150) {
index = i;
click = true;
selection = bottom;
}
}
//SHOES-------------------------------------------
//cycle through shoes positions
for (var i = 0; i < feet.length; i++) {
var dFeetX = abs(mouseX - feet[i].x);
var dFeetY = abs(mouseY - feet[i].y);
//if shoes is clicked, store the array and index
if (dFeetX < 60 & dFeetY < 40) {
index = i;
click = true;
selection = feet;
}
}
//if an item is selected, display it on top of other items
if (click) bringToFront(selection, index);
//---------------------------------------------------------------
//RECOLORING-----------------------------------------
//distance from mouse to button
var dTint = dist(mouseX, mouseY, wheelX, wheelY);
//if button is clicked, recolor item
if (dTint < 20) recolor(3);
//RANDOM OUTFIT--------------------------------------
//distance from mouse to button
var dRandomX = abs(randomX - mouseX);
var dRandomY = abs(randomY - mouseY);
//if button is clicked, assemble a random outfit
if (dRandomX < 30 & dRandomY < 12) mix();
//DIRECTIONS-----------------------------------------
//distance from mouse to button
var dInfoX = abs(infoX - mouseX);
var dInfoY = abs(infoY - mouseY);
//if button is clicked, display info
if (dInfoX < 30 & dInfoY < 12) showInfo = !showInfo;
}
//if an item is selected, push it to the end of the array
//and remove it from its original position.
//Reordering the array allows item to displayed "on top"
function bringToFront(item, index) {
item.push(item[index]);
item.splice(index, 1);
}
function mouseDragged() {
//distance between mouse and "most recent" shirt, pants and shoe positions
var dBlouse = dist(mouseX, mouseY, blouse[3].x, blouse[3].y);
var dBottomX = abs(mouseX - bottom[3].x);
var dBottomY = abs(mouseY - bottom[3].y);
var dFeetX = abs(mouseX - feet[3].x);
var dFeetY = abs(mouseY - feet[3].y);
//If mouse is on the shirt and no pants or shoes are
//already selected, call function to allow dragging.
//Establishing items as "true" when they are selected prevents
//other items from being picked up while the mouse is dragged.
if (dBlouse < 80 & !dragBottom && !dragFeet) {
dragItem(blouse, 30);
}
// if only shoes are selected, allow them to be dragged
else if (dFeetX < 60 & dFeetY < 50 && !dragBottom) {
dragFeet = true;
dragItem(feet, 0);
}
// if only pants are selected, allow them to be dragged
else if (dBottomX < 60 & dBottomY < 140 && !dragFeet) {
dragBottom = true;
dragItem(bottom, 90);
}
}
//allows selected item to be dragged
function dragItem(item, offset) {
item[3].x = mouseX;
item[3].y = mouseY + offset;
}
//snaps items near the body to their fixed positions
function snap(item) {
//measures distance from item to target position
var dx = bodyCenter - item[3].x;
var dy = item[3].center - item[3].y;
var D = sqrt(dx*dx + dy*dy);
//when an item is near its target and the mouse is released,
//snap it into position with a smooth motion
if (D < 50 & !mouseIsPressed) {
dirX = dx / max(1, D);
dirY = dy / max(1, D);
item[3].x += dirX;
item[3].y += dirY;
}
}
//BUTTON FUNCTIONS-------------------------------------
//draw button with label, position, and color parameters
function drawButton(type, x, y, col) {
//button
stroke(0);
strokeWeight(2);
fill(col);
rectMode(CENTER);
rect(x, y, 60, 24, 10);
//text
noStroke();
fill("MAGENTA");
textAlign(CENTER);
text(type, x, y + 5);
}
//provides button to reset clothes to original position
function reset() {
//button position
var buttonX = 420;
var buttonY = 580;
//distance from mouse to center of button
var dResetX = abs(buttonX - mouseX);
var dResetY = abs(buttonY - mouseY);
//if button is clicked, recall setup and draw "clicked" button
if (mouseIsPressed & dResetX < 30 && dResetY < 12) {
drawButton("reset", buttonX, buttonY, buttonColor - 80);
clothesSetup();
}
//else, draw button in unclicked state
else drawButton("reset", buttonX, buttonY, buttonColor);
}
//draw color wheel with an outline
function drawWheel() {
image(colorWheel, wheelX, wheelY, 40, 40);
noFill();
stroke(0);
strokeWeight(2);
ellipse(wheelX, wheelY, 37, 37);
}
//recolors shirt when wheel is clicked
function recolor() {
//increase color counter and assign tint
colorClick++;
blouse[wearing].tint = wheel[colorClick % 4];
}
//provides button to assemble a random outfit
function mix() {
//selects a random shirt, pants and shoe pairing
var randBlouse = round(random(3));
var randBottom = round(random(3));
var randShoes = round(random(3));
//draw button in "clicked" mode
//call setup to remove any clothes on the body
clothesSetup();
//selects random hair style
hairClick = round(random(3));
//positions random shirt on the body
blouse[randBlouse].x = bodyCenter;
blouse[randBlouse].y = shirtCenter;
//positions random pants on the body
bottom[randBottom].x = bodyCenter;
bottom[randBottom].y = pantsCenter;
//positions random shoes on the body
feet[randShoes].x = bodyCenter;
feet[randShoes].y = shoesCenter;
}
//displays directions for game
function directions() {
if (showInfo) {
stroke(0);
strokeWeight(10);
fill(255);
rect(width / 2, height / 2, 400, 150, 30);
noStroke();
fill("MAGENTA");
text("Drag and drop the clothes to make one chic as heck fashion diva", width / 2, height / 2 - 30);
text("Click her face to change hair styles", width / 2, height / 2 - 5);
text("Click the color wheel to recolor her shirt", width / 2, height / 2 + 20);
text("(Press any key to escape)", width / 2, height / 2 + 60);
}
//exits directions when a key is pressed
if (keyIsPressed) showInfo = false;
}
//---------------------------------------------------------------------
//OBJECT CREATION AND CLOTHING DISPLAY
//Creates objects with parameters for
//image, initial position, and center relative to the body.
function makeItem(ipic, ix, iy, icenter) {
return {pic: ipic, x: ix, y: iy,
center: icenter,
tint: 255,
draw: drawItem,
};
}
//draw image and recolor with specified tint
function drawItem() {
tint(this.tint);
image(this.pic, this.x, this.y);
noTint();
}
Directions: Drag and drop the clothes to make one chic-as-heck fashion diva! Click on the hair to change the style. If you give her a shirt, you can tint it by clicking on the color wheel. Click the random button to generate a random outfit, and click the reset button to put everything back!
Statement: This project was a lot of fun to make and I loved that I was able to incorporate my own drawing style with my code! It ended up being a lot more complicated than I thought to get the click, drag, and drop functions right, but I’m happy with what I was able to do. I’m proud I was able to figure out a way to change the order in which items were displayed on the screen, and I think this level of responsiveness helps my project feel more like a real dress up game. While I’m happy with how the game turned out, I do wish I could have the mouse respond to clicking anywhere on a clothing item rather than estimating its distance from the center.