Matter JS Prevent dragging body beyond specific area?

TLDR; How do I make a body draggable only in the bottom half of the screen and release it if user tries to go beyond that specified area?

I’m making a simple game using p5.js for rendering and Matter JS as the physics Engine. The game involves tossing a ball towards targets to gain points. But I’m not sure how to prevent the player from simply dragging the ball all over the targets. I’d like to limit the area of the screen in which the user can drag the ball, and if they exceed that area, the ball just drops/is released.

Demo With Error: https://toss-game-8d371.web.app/

CODE:

let Engine = Matter.Engine;
let World = Matter.Composite;
let Mouse = Matter.Mouse;
let MouseConstraint = Matter.MouseConstraint;
let Collision = Matter.Collision;
let Constraint = Matter.Constraint;
let ground, ball, world, engine, mCon, leftWall, rightWall, scoreBoard;
let boxes = [];
let score = 0;
let timer = 42;
let bgImage, ballImage, scoreboardImage;
let monsterImages = [];
let imgIndex = 0;
let constraint, constraintOptions;

const BALL_CATEGORY = 0b0001;
const MOUSE_CATEGORY = 0b0010;

function sketch(p) {
    p.preload = async function() {
        bgImage = p.loadImage(bg);
        ballImage = p.loadImage(candy);
        scoreboardImage = p.loadImage(scoreboard);
        monsterImages.push(await p.loadImage(skull));
        monsterImages.push(await p.loadImage(ghost));
        monsterImages.push(await p.loadImage(zombie));
        monsterImages.push(await p.loadImage(goblin));
        monsterImages.push(await p.loadImage(vampire));
    }

    p.setup = function() {
        const canvas = p.createCanvas(p.windowWidth, p.windowHeight);
        engine = Engine.create();
        world = engine.world;
        const canvasMouse = Mouse.create(canvas.elt);
        canvasMouse.pixelRatio = p.pixelDensity();

        ground = new Boundary(p.width/2, p.height-10, p.width, 20, world);
        leftWall = new Boundary(10, p.height/2, 20, p.height, world);
        rightWall = new Boundary(p.width - 10, p.height/2, 20, p.height, world);
        ball = new Ball(p.width/2, p.height - 100, 40, world, ballImage, BALL_CATEGORY);
        scoreBoard = new Scoreboard( 10, 10, p.width > 800 ? 400 : p.width - 30, 75, world, scoreboardImage);

        const options = {
            mouse: canvasMouse,
            collisionFilter: {
                category: MOUSE_CATEGORY,
                mask: 3,
            }
        }
        mCon = MouseConstraint.create(engine, options);


        World.add(world, [mCon]);
    }

    setInterval(spawnBoxes, 500);

    p.mouseDragged = function() {
        if(p.mouseY > 600) {

        } else {
            ball.hide();
            ball.reset(p);
        }
    }

    function spawnBoxes() {
        if(boxes.length > 7) {
            World.remove(engine.world, boxes[0].body);
            boxes.splice(0, 1);
        }
        let xLoc = p.random(0, p.width);
        let yLoc = p.random(100, p.height/2 + 100);
        let boxWidth, boxHeight;
        let overlapping = false;
        if(imgIndex === 3 || imgIndex === 4) {
            boxWidth = 105;
            boxHeight = 85;
        }
        else {
            boxWidth = 80;
            boxHeight = 85;
        }
        let boxToPush = {
            x: xLoc,
            y: yLoc,
            w: boxWidth,
            h: boxHeight,
            world: world,
            img: monsterImages[imgIndex],
        }

        for(let j = 0; j < boxes.length; j++) {
            let boxToCheckAgainst = boxes[j];
            let distance = p.dist(boxToPush.x, boxToPush.y ,boxToCheckAgainst.x, boxToCheckAgainst.y);
            if(distance < boxToPush.w + boxToCheckAgainst.w - 80
            || distance < boxToPush.h + boxToCheckAgainst.h - 80) {
                overlapping = true;
                break;
            }
        }
        if(!overlapping) {
            boxes.push(new Box(boxToPush));
            imgIndex = (imgIndex + 1) % monsterImages.length;
        }
    }


    p.windowResized = function() {
        p.resizeCanvas(p.windowWidth, p.windowHeight);
    }

    p.draw = function () {
        p.background(bgImage);
        Engine.update(engine);
        rightWall.show(p);
        leftWall.show(p);
        ground.show(p);
        ball.show(p);
        if(p.frameCount % 60 === 0 && timer > 0) {
            timer--;
        }
        scoreBoard.show(p, score, timer);

        for(let i = 0; i < boxes.length; i++) {
            boxes[i].show(p);
        }

        if(ball.body.position.y < 0 || ball.body.position.y > p.height + 50 || ball.body.position.x < 0 || ball.body.position.x > p.width + 50) {
            ball.hide();
            ball.reset(p);
        }

        for(let i = 0; i < boxes.length; i++) {
            if(Collision.collides(ball.body, boxes[i].body)) {
                ball.hide();
                World.remove(engine.world, boxes[i].body);
                boxes.splice(i, 1);
                ball.reset(p);
                score += 1;
            }
        }
    }
}

Ball Class

import Matter from 'matter-js'

export default class Ball {
    constructor(x, y, r, world, ballImage, collisionCategory) {
        this.body = Matter.Bodies.circle(x, y, r);
        this.body.collisionFilter.category = collisionCategory;
        this.body.collisionFilter.mask = 1;
        Matter.World.add(world, this.body);
        this.world = world;
        this.r = r;
        this.ballImage = ballImage;
        this.visible = true;
    }

    show(p) {
        if(this.visible) {
            const pos = this.body.position;
            if(pos.y > p.height/1.2) {
                this.body.collisionFilter.mask = 3;
            }
            else {
                this.body.collisionFilter.mask = 1;
            }
            const angle = this.body.angle;
            Matter.Body.setSpeed(this.body, Math.min(this.body.speed, 40));
            p.push();
            p.translate(pos.x, pos.y);
            p.rotate(angle);
            p.imageMode(p.CENTER);
            p.image(this.ballImage, 0, 0, this.r*2, this.r*2);
            p.pop();
        }
    }

    hide() {
        this.visible = false;
    }

    reset(p) {
        Matter.Body.setPosition(this.body, { x: p.width / 2, y: p.height - 100 });
        Matter.Body.setAngle(this.body, 0);
        Matter.Body.setVelocity(this.body, { x: 0, y: 0 });
        setTimeout(() => {
            this.visible = true
        }, 300)
    }
}

UNSUCCESSFUL ATTEMPTS:

I have tried this solution. But many of the properties used there don’t seem to be available any more (I couldn’t find any drag object associated with my mouse).

I have tried creating a constraint between the ball and my mouse, but I must be linking the mouse wrong because on adding that constraint to the World, I get an error: “cannot read properties of undefined (reading ‘x’)”.

constraintOptions = {
    bodyA: mCon.mouse,
    bodyB: ball.body,
    stiffness: 0.75
}
constraint = Constraint.create(constraintOptions);
World.add(world, constraint);

I have tried removing the mouse constraint from the world, if the mouse is dragged beyond a certain height. That didn’t produce errors, but also didn’t seem to work at all.

I have added collisionFilter categories and masks. In my Ball class, I make sure that once the ball goes beyond a certain height, it cannot be interacted with by the mouse. But this only means that a released ball won’t collide with the mouse in that area. A dragged ball still remains attached to the mouse.

Finally, I have tried resetting the position of the ball once it is dragged beyond specified area. This makes the ball flicker a lot, but it still remains attached to the mouse.

I’d really appreciate any help, really stuck with this issue.
Thanks!