I made this account as I have no where else to ask this. So I'm a beginner in coding in general (I have tried python,html and javascript before) and have just started trying out Processing. My goal was to make a rag doll character with draggable arms and legs and realistic falling physics. Now the arms and legs fly out of frame when I start the program and I have no idea how to fix it.
This is the full code I have right now.
float rectWidth = 200, rectHeight = 250; // Body
float faceRectWidth = 150, faceRectHeight = 115; // Face
boolean dragging = false;
PVector target;
PVector characterPos;
float gravity = 0.5; // Reduced gravity to prevent limbs from falling too fast
float groundLevel;
boolean isSquinting = false;
float armLength = 60, legLength = 80;
PVector leftArm, rightArm, leftLeg, rightLeg;
PVector leftArmVel, rightArmVel, leftLegVel, rightLegVel;
// Static anchor points for the limbs
PVector leftArmAnchor, rightArmAnchor, leftLegAnchor, rightLegAnchor;
void setup() {
size(800, 600);
background(255);
characterPos = new PVector(width / 2 - rectWidth / 2, height - rectHeight - 30);
target = new PVector();
// Set static anchor points relative to the torso position
leftArmAnchor = new PVector(-20, rectHeight * 0.4);
rightArmAnchor = new PVector(rectWidth + 20, rectHeight * 0.4);
leftLegAnchor = new PVector(rectWidth * 0.3, rectHeight);
rightLegAnchor = new PVector(rectWidth * 0.7, rectHeight);
// Initialize limb positions at their anchored points
leftArm = PVector.add(characterPos, leftArmAnchor);
rightArm = PVector.add(characterPos, rightArmAnchor);
leftLeg = PVector.add(characterPos, leftLegAnchor);
rightLeg = PVector.add(characterPos, rightLegAnchor);
leftArmVel = new PVector(0, 0);
rightArmVel = new PVector(0, 0);
leftLegVel = new PVector(0, 0);
rightLegVel = new PVector(0, 0);
groundLevel = height - rectHeight;
}
void draw() {
background(255);
if (dragging) {
// Dragging character
PVector difference = PVector.sub(target, characterPos);
characterPos.add(difference.mult(0.2));
target.set(mouseX, mouseY);
isSquinting = true;
} else {
isSquinting = false;
// Apply gravity
if (characterPos.y < groundLevel) {
characterPos.y += gravity;
} else {
characterPos.y = groundLevel;
}
}
// Update limb positions, keeping them anchored
updateLimb(leftArm, leftArmVel, leftArmAnchor);
updateLimb(rightArm, rightArmVel, rightArmAnchor);
updateLimb(leftLeg, leftLegVel, leftLegAnchor);
updateLimb(rightLeg, rightLegVel, rightLegAnchor);
// Draw character
pushMatrix();
translate(characterPos.x, characterPos.y);
drawBmo();
popMatrix();
}
void drawBmo() {
// Draw body
stroke(#3C4342);
strokeWeight(5);
fill(#92D8D2);
rect(0, 0, rectWidth, rectHeight, 20); // Rounded corners
// Draw face
stroke(#3C4342);
strokeWeight(5);
fill(#C9F0EC);
float faceRectX = (rectWidth - faceRectWidth) / 2;
float faceRectY = 20;
rect(faceRectX, faceRectY, faceRectWidth, faceRectHeight, 20); // Rounded corners
// Draw eyes (squinting effect)
fill(#102C29);
noStroke();
float eyeWidth = 10, eyeHeight = isSquinting ? 5 : 10;
float leftEyeX = faceRectX + faceRectWidth * 0.25;
float rightEyeX = faceRectX + faceRectWidth * 0.75;
float eyeY = faceRectY + faceRectHeight * 0.4;
ellipse(leftEyeX, eyeY, eyeWidth, eyeHeight);
ellipse(rightEyeX, eyeY, eyeWidth, eyeHeight);
// Draw mouth
stroke(#102C29);
strokeWeight(3);
noFill();
float mouthX = faceRectX + faceRectWidth / 2;
float mouthY = faceRectY + faceRectHeight * 0.6;
arc(mouthX, mouthY, 35, 10, 0, PI);
// Draw buttons
stroke(#102C29);
strokeWeight(3);
fill(#072723);
rect(30, 150, 80, 10);
fill(#171476);
ellipse(150, 155, 10, 10);
fill(#4AE5F5);
triangle(135, 190, 125, 200, 145, 200);
// Draw limbs
drawLimb(leftArm, 10, armLength);
drawLimb(rightArm, 10, armLength);
drawLimb(leftLeg, 10, legLength);
drawLimb(rightLeg, 10, legLength);
// Other details
stroke(#102C29);
strokeWeight(3);
fill(#2AF53F);
ellipse(170, 195, 15, 15);
fill(#F52A82);
ellipse(150, 225, 25, 25);
}
void drawLimb(PVector pos, float width, float height) {
// Draw limb as a rectangle
stroke(#3C4342);
strokeWeight(3);
fill(#92D8D2);
rect(pos.x - characterPos.x, pos.y - characterPos.y, width, height, 10);
}
void updateLimb(PVector pos, PVector vel, PVector anchor) {
float elasticity = 0.2; // Increased elasticity to keep limbs closer to anchor
float maxStretch = 50; // Maximum distance limbs can stretch from the anchor
PVector anchoredPos = PVector.add(characterPos, anchor);
// Apply gravity to limbs
vel.y += gravity * 0.5; // Reduced gravity effect for limbs
pos.add(vel);
// Apply elasticity to keep the limb close to its anchor
PVector stretch = PVector.sub(anchoredPos, pos);
float stretchDist = stretch.mag();
if (stretchDist > maxStretch) {
stretch.normalize();
pos.set(PVector.add(anchoredPos, stretch.mult(-maxStretch)));
}
pos.add(stretch.mult(elasticity));
// Apply friction to slow down velocity
vel.mult(0.95);
}
// Mouse interaction functions
void mousePressed() {
if (mouseX > characterPos.x && mouseX < characterPos.x + rectWidth &&
mouseY > characterPos.y && mouseY < characterPos.y + rectHeight) {
dragging = true;
target.set(mouseX, mouseY);
}
}
void mouseDragged() {
if (dragging) {
target.set(mouseX, mouseY);
}
}
void mouseReleased() {
dragging = false;
}
The following demo creates two classes: body and leg. Both objects may be repositioned by dragging. The leg may be detached and repositioned independently, but always follows the body as it is repositioned. You may be able to use this technique in your application.
boolean bodySelected = false;
boolean legSelected = false;
PVector bodyOffset;
PVector legOffset;
class Body {
float x, y, w, h;
Body(float xpos, float ypos, float wide, float ht) {
x = xpos;
y = ypos;
w = wide;
h = ht;
}
void display() {
rect(x, y, w, h);
}
}
Body body;
class Leg {
float x, y, w, h;
Leg(float xpos, float ypos, float wide, float ht) {
x = xpos;
y = ypos;
w = wide;
h = ht;
}
void display() {
rect(x, y, w, h);
}
}
Leg leg;
void setup() {
size(800, 800);
background(209);
body = new Body(300, 200, 200, 200);
bodyOffset = new PVector(0.0, 0.0, 0.0);
leg = new Leg(body.x + 30, body.y + body.h, 20, 100);
legOffset = new PVector(0.0, 0.0, 0.0);
}
void draw() {
background(209);
body.display();
leg.display();
}
void mousePressed() {
if ((mouseX >= body.x) && (mouseX <= body.x + body.w) && (mouseY >= body.y) && (mouseY <= body.y + body.h)) {
bodySelected = true;
println("mouse pressed x,y = " + mouseX + " : " + mouseY);
println(body.x + " : " + body.y);
bodyOffset.set(mouseX - body.x, mouseY - body.y, 0.0);
// Change offset of leg also
legOffset.set(mouseX - leg.x, mouseY - leg.y, 0.0);
println("mouse pressed body offsets = " + bodyOffset.x + " : " + bodyOffset.y);
println("mouse pressed leg offsets = " + legOffset.x + " : " + legOffset.y);
} else {
bodySelected = false;
}
if ((mouseX >= leg.x) && (mouseX <= leg.x + leg.w) && (mouseY >= leg.y) && (mouseY <= leg.y + leg.h)) {
legSelected = true;
println("mouse pressed x,y = " + mouseX + " : " + mouseY);
println(leg.x + " : " + leg.y);
legOffset.set(mouseX - leg.x, mouseY - leg.y, 0.0);
println("mouse pressed offsets = " + legOffset.x + " : " + legOffset.y);
} else {
legSelected = false;
}
}
void mouseDragged() {
if (bodySelected) {
body.x = mouseX - bodyOffset.x;
body.y = mouseY - bodyOffset.y;
println("dragged body rect x,y = "+ body.x + " : " + body.y);
// Keep leg with the body
leg.x = mouseX - legOffset.x;
leg.y = mouseY - legOffset.y;
}
if (legSelected) {
leg.x = mouseX - legOffset.x;
leg.y = mouseY - legOffset.y;
println("dragged leg rect x,y = " + leg.x + " : " + leg.y);
}
}