Link to home
Start Free TrialLog in
Avatar of gem56
gem56

asked on

Capture mouse motion

hey guys,

im building a small air hockey game using c++ and SDL and im having some problems building a controller. the mission is to be able to control one of the allocated bats by the mouse, however im just having a hell of a time getting it to work properly.

the thought was to capture the mouse position at every update, store the current position and the previous position. get the difference between both sets of values, normalize them, then add that set of values to the sprites current velocity. not working as planned unfortunately.

the way it currently works is say i move the mouse from left to right, the sprite will accelerate and continue at the same speed when i stop the mouse. to slow the sprite down again i actually have to move the mouse in the opposite direction. i know theres a logic error here somewhere, i just need a fresh set of eyes.

again, the idea was to make the sprite pretty much follow the mouse, however i need this to be done in a velocity manner as im going to be adding table friction and maximum speeds and etc.

code attached below, any help is much appreciated :)

cheers

p.s. no matter what i tried i just couldnt get the SDL event.motion.xrel & .yrel to work for me, it seems that when the mouse stops moving all together, they dont update.
// Update command within the sprite manager
void update(SDL_Event event, float delta)
{
  for (unsigned int i = 0; i < sprites.size(); i++)
    {
     // Calculate sprite velocity
     Controller *controller = &sprites[i]->getController();

     if (controller->getType() != "none")
     {
        // event.motion contains the x/y pos of the mouse
        controller->updatePos(Vector(event.motion.x, event.motion.y));
        Vector vec = controller->getVelUnit();
        sprites[i]->addVel(vec * 20);    
     }
  }
};

// -------------------------------
 
  void addVel(Vector newVel)
  {
    xVel += newVel.getX();
    yVel += newVel.getY();
  };

// -------------------------------

// UpdatePos within the controller
  void updatePos(Vector newPos)
  {

    lastX = curX;
    curX = newPos.getX();

    lastY = curY;
    curY = newPos.getY();

    Vector vec(curX - lastX, curY - lastY);
    vec.normalize();
    xRel = vec.getX();
    yRel = vec.getY();

  };

// -------------------------------

// Vector2D junk
  // Normalize / Unit Vector
  Vector normalize(void)
  {
    double mag = magnitude();

    if (x != 0)
      x /= mag;

    if (y != 0)
      y /= mag;

    return Vector(x, y);
  };

// -------------------------------

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of ambience
ambience
Flag of Pakistan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of gem56
gem56

ASKER

hi ambience, thanks for your reply.

yep i get what your saying...i may try code something up to compare. i actually gave up on using velocity in terms of adding and subtracting to it, i am instead now using acceleration and setting the velocity instead. i've got the solution working mostly, however now i just need to tweak my acceleration rate and what not.

to my surprise the sprite moves along very cleanly and doesnt jerk at all...however like i said, i need to calibrate the acceleration rate which is going to be interesting.

code based on acceleration capture is below. A sprite object (the image) contains a Controller object (records mouse positions) which determines the rate the sprite moves around.

i'll write up another method to use velocity instead of acceleration, however if that doesnt work more perfectly, anyone have any ideas on how exactly i can find the perfect value for 'MOUSE_ACCEL_RATE' ?

cheers
// -----------------------------------------------------------
// SpriteManager class

  void update(SDL_Event event, float delta)
  {
    // For each Sprite instance in the container
    for (unsigned int i = 0; i < sprites.size(); i++)
    {
      // .......

      // Calculate sprite velocity
      Controller *controller = &sprites[i]->getController();

      if (controller->getType() != "none") // If the controller is the 'mouse'
      {

        // Accelerate to the mouse...relatively. make 1.9 MOUSE_ACCEL_RATE const!
        controller->updatePos(Vector(event.motion.x, event.motion.y), delta);
        sprites[i]->setVel((controller->getAccel() * 1000) * 1.9);   // 1000 for milliseconds to seconds, 1.9 is acceleration rate
            
        
      }

      // Update sprite
      sprites[i]->update(delta, offset);
    }
  };


// -----------------------------------------------------------
// Controller class

  // Update controller with new positions of the mouse
  void updatePos(Vector newPos, float delta)
  {
    // If the newPos doesnt equal 0 (ie, mouse isnt off the screen)
    if ((newPos.getX() != 0) && (newPos.getY() != 0))
    {
      lastX = curX;
      curX = newPos.getX();

      lastY = curY;
      curY = newPos.getY();
    }

    deltaTime = delta;

  };

  // The difference between positions
  Vector getDeltaPos(void)
  {
    return Vector(curX - lastX, curY - lastY);
  };

  // The acceleration of the controller
  Vector getAccel(void)
  {
    // v = deltaX / deltaT
    Vector vec = getDeltaPos() / deltaTime;

    // a = deltaV / deltaT
    vec = vec / deltaTime;

    return vec;
  };

Open in new window

I would think 'MOUSE_ACCEL_RATE'  would be a good candidate for a "Mouse Sensitivity" setting in the Game Settings screen (if you do plan to have that configurable). Other than that, the best way is emprical, ie whatever works the best.

In a sense, I see that your new code is no different from what I suggested. The update gets called on mouse move only (right?), and in there you calculate the velocity (new pos - last pos). So now the term 20 is not there, but the magnitude is implicit in calculations.

I believe, you have a separate update method (physics update) that is called at a fixed rate?


Avatar of gem56

ASKER

hey ambience,

yeah 100% that the mouse accel rate would be in the options somewhere as the mouse sensitivity, however i was just curious if there was a value i could get to determine my exact 'sensitivity'.

i've actually converted the process to use velocity now instead of acceleration...and it works perfectly, no jittering or anything. mathematically both methods *should* produce the exact same result (given the mouse_accel_rate is 100% accurate).

much appreciated for your help mate, saved me many hours of insanity :)

p.s. no the update() is given to the game object which then calls the update of each manager (sprite, surface, sound, etc). the sprite manager update is passed to each sprite, and within that update the mouse position gets updated and calculated. probably not the best way to do it, but unfortunately the SDL mouse hook that im using is very very limited in functionality and it had to be done that way =\

the game object throws the update() to each manager, then preforms all the collision tests before exiting the funciton.