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

gem56Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ambienceCommented:
It is difficult to say exactly, because much of the code is not given. However,
The constant speed could be because you seem to be adding a constant velocity no matter how fast or slow the mouse moves.
 addVel(vec * 20);    
The vec here is the direction vector only (unit vector), and multiplied by 20 means constant velocity of 20 in that direction.
If you want to scale the velocity up and down then you should calculate and save the current speed too, and move by that amount. In updatePos(), you would calculate the amount the mouse has moved and then
speed = max(magnitude() , maxspeed);
I do expect a kind of jerky and the slowdown might become more obvious than usual.
 
 
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gem56Author Commented:
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

0
ambienceCommented:
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?


0
gem56Author Commented:
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.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Game Programming

From novice to tech pro — start learning today.