How to make mouse movement work with no delay? - c++

I'm making a program that let me click on the center of two concentric circles and, by mouse move, change it's position and i can do the same with it's radii.
The thing is that the mouse movement is followed by a delay response from the circles drawing making the radius follow the mouse instead of being exactly in the same position during the movement.
Would you guys know how to make it work like that? pin point following by the drawing.
a bit of the code that treats the mouse clicking and movements:
void DemoApp::OnLButtonDown(FLOAT pixelX, FLOAT pixelY)
{
SetCapture(m_hwnd);
mouseRegion = DPIScale::PixelsToDips(pixelX, pixelY);
FLOAT xDifference = centerCircles.x - mouseRegion.x;
FLOAT yDifference = centerCircles.y - mouseRegion.y;
FLOAT distanceToCenter = sqrtf(xDifference*xDifference + yDifference*yDifference);
if(distanceToCenter < 10.0f)
{
centerMove = true;
minimumRadiusCircleMove = false;
maximumRadiusCircleMove = false;
}
else if((distanceToCenter > (minimumRadius - 1.0f)) && (distanceToCenter < (minimumRadius + 1.0f)))
{
minimumRadiusCircleMove = true;
centerMove = false;
maximumRadiusCircleMove = false;
}
else if((distanceToCenter > (maximumRadius - 1.0f)) && (distanceToCenter < (maximumRadius + 1.0f)))
{
maximumRadiusCircleMove = true;
centerMove = false;
minimumRadiusCircleMove = false;
}
else
{
centerMove = false;
minimumRadiusCircleMove = false;
maximumRadiusCircleMove = false;
}
InvalidateRect(m_hwnd, NULL, FALSE);
}
void DemoApp::OnMouseMove(int pixelX, int pixelY, DWORD flags)
{
if (flags & MK_LBUTTON)
{
if(centerMove)
{
centerCircles = DPIScale::PixelsToDips(pixelX, pixelY);
FLOAT distanceLeftToCenterCircles = abs(centerCircles.x - bitmapTopLeft);
FLOAT distanceTopToCenterCircles = abs(centerCircles.y - bitmapTopRight);
percentageFromLeft = distanceLeftToCenterCircles / displaySizeWidth;
percentageFromTop = distanceTopToCenterCircles / displaySizeHeight;
}
else if(minimumRadiusCircleMove)
{
radiusSelection = DPIScale::PixelsToDips(pixelX, pixelY);
FLOAT xDifference = centerCircles.x - radiusSelection.x;
FLOAT yDifference = centerCircles.y - radiusSelection.y;
minimumRadius = sqrtf(xDifference*xDifference + yDifference*yDifference);
minimumRadiusPercentage = minimumRadius/(displaySizeWidth/2);
}
else if(maximumRadiusCircleMove)
{
radiusSelection = DPIScale::PixelsToDips(pixelX, pixelY);
FLOAT xDifference = centerCircles.x - radiusSelection.x;
FLOAT yDifference = centerCircles.y - radiusSelection.y;
maximumRadius = sqrtf(xDifference*xDifference + yDifference*yDifference);
maximumRadiusPercentage = maximumRadius/(displaySizeWidth/2);
}
InvalidateRect(m_hwnd, NULL, FALSE);
}
}
void DemoApp::OnLButtonUp()
{
ReleaseCapture();
}

According to MSDN ( http://msdn.microsoft.com/en-us/library/dd145002%28v=vs.85%29.aspx ) InvalidateRect doesn’t cause the window to be repainted until the next WM_PAINT and "The system sends a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window." so it’s not immediate.
I found a possible solution on MSDN here Drawing Without the WM_PAINT Message

i've found a solution to that problem!
It's way simple than expected, all you got to do is add a flag while creating the render target, that way the mousemove will respond way faster:
the flag is: D2D1_PRESENT_OPTIONS_IMMEDIATELY.
// Create Direct2d render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY),
&m_pRenderTarget
);

Related

How to make trigger area in Cocos2d

I am doing a Flappy Bird game following some tutorials. To count up the score, I have set PhysicsBody among the score area, but it is just like a Rigibody in Unity, other objects cannot get through it.
You can take reference at https://www.youtube.com/watch?v=3zGTCGgwt_U&list=PLRtjMdoYXLf7GSD9crXIjMQiRuIZ7mUVp&index=12, it is the result that I want. I followed it but I don't know why here comes a difference.
In my situation, the score line blocks my flying bird. As the score lines and pipes are moving backward, my flappy bird is pushed by the score line until it reaches the screen edge and turns out a gameover.
I want something like a Trigger Collider in Unity. Is there any similar thing in cocos2d?
Also attach my code here, it spawns the pipes as well as the score line:
void Pipe::Spawn(Layer* pipeLayer) {
auto upperPipe = Sprite::create("pipe_upper.png");
upperPipe->setAnchorPoint(Vec2(0.5,0));
upperPipe->setScale(spriteScale);
auto upperPipeBody = PhysicsBody::createBox(upperPipe->getContentSize());
upperPipeBody->setDynamic(false);
upperPipeBody->setCollisionBitmask(OBSTACLE_COLLISION_BITMASK);
upperPipeBody->setContactTestBitmask(true);
upperPipe->setPhysicsBody(upperPipeBody);
auto bottomPipe = Sprite::create("pipe_bottom.png");
bottomPipe->setAnchorPoint(Vec2(0.5,1));
bottomPipe->setScale(spriteScale);
auto bottomPipeBody = PhysicsBody::createBox(bottomPipe->getContentSize());
bottomPipeBody->setDynamic(false);
bottomPipeBody->setCollisionBitmask(OBSTACLE_COLLISION_BITMASK);
bottomPipeBody->setContactTestBitmask(true);
bottomPipe->setPhysicsBody(bottomPipeBody);
float randomPosIndex = CCRANDOM_0_1();
if (randomPosIndex < PIPE_BOTTOM_THRESHOLD) {
randomPosIndex = PIPE_BOTTOM_THRESHOLD;
}
else if (randomPosIndex > PIPE_UPPER_THRESHOLD) {
randomPosIndex = PIPE_UPPER_THRESHOLD;
}
float gapHeight = Sprite::create("flappybird1_01.png")->getContentSize().height * spriteScale * PIPE_GAP_INDEX;
Size visibleSize = Director::getInstance()->getVisibleSize();
//setup bottom pipe
bottomPipe->setPosition(Point(visibleSize.width, visibleSize.height * randomPosIndex));
//setup upper pipe
upperPipe->setPosition(Point(visibleSize.width, bottomPipe->getPositionY() + gapHeight));
//setup score area
auto scoreNode = Node::create();
auto scoreNodeBody = PhysicsBody::createBox(Size(1, gapHeight));
scoreNodeBody->setDynamic(false);
scoreNodeBody->setCollisionBitmask(SCORE_COLLISION_BITMASK);
scoreNodeBody->setContactTestBitmask(true);
scoreNode->setPhysicsBody(scoreNodeBody);
scoreNode->setPosition(Point(bottomPipe->getPositionX(), bottomPipe->getPositionY() + gapHeight / 2));
auto bottomPipeAction = RepeatForever::create(MoveBy::create(1, Vec2(-PIPE_MOVE_SPEED, 0)));
auto upperPipeAction = RepeatForever::create(MoveBy::create(1, Vec2(-PIPE_MOVE_SPEED, 0)));
auto scoreNodeAction = RepeatForever::create(MoveBy::create(1, Vec2(-PIPE_MOVE_SPEED, 0)));
bottomPipe->runAction(bottomPipeAction);
upperPipe->runAction(upperPipeAction);
scoreNode->runAction(scoreNodeAction);
pipeLayer->addChild(bottomPipe);
pipeLayer->addChild(upperPipe);
pipeLayer->addChild(scoreNode);
CCLOG("Spawn Pipe");
}
Credits to ryemoss's reference. Simply return false in the collision callback function solves everything!
bool GameScene::onContactBegin(PhysicsContact &contact)
{
PhysicsBody* a = contact.getShapeA()->getBody();
PhysicsBody* b = contact.getShapeB()->getBody();
if ( (a->getCollisionBitmask() == FLAPPYBIRD_COLLISION_BITMASK && b->getCollisionBitmask() == OBSTACLE_COLLISION_BITMASK) ||
(b->getCollisionBitmask() == FLAPPYBIRD_COLLISION_BITMASK && a->getCollisionBitmask() == OBSTACLE_COLLISION_BITMASK)
)
{
auto gameoverScene = GameOverScene::createScene();
Director::getInstance()->replaceScene(TransitionFade::create(SCENE_TRANSITION_DURATION, gameoverScene));
}
else if ((a->getCollisionBitmask() == FLAPPYBIRD_COLLISION_BITMASK && b->getCollisionBitmask() == SCORE_COLLISION_BITMASK) ||
(b->getCollisionBitmask() == FLAPPYBIRD_COLLISION_BITMASK && a->getCollisionBitmask() == SCORE_COLLISION_BITMASK))
{
score++;
CCLOG("Score Count: %i", score);
return false;
}
return true;
}

How to move an entity with a mouse click?

Ok i now manage to figure out the problem but now another issue appear, my robot seem to move on its own to another point which i have no idea where its from. Here my code
His code make this robot move to the location i click on the terrain.
bool DemoApp::nextLocation(void){
mDestination = mtoward;
mRobotDir = mDestination - mRobotNode[0]->getPosition();
mDistance = mRobotDir.normalise();
return true;
}
bool DemoApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if (mRobotDir == Ogre::Vector3::ZERO) {
if (nextLocation()) {
// Set walking animation
mAnimationState = mRobot[0]->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}//if
}else{
Ogre::Real move = mWalkSpeed * evt.timeSinceLastFrame;
mDistance -= move;
if (mDistance <= 0.0f){
mRobotNode[0]->setPosition(mDestination);
mRobotDir = Ogre::Vector3::ZERO;
// Set animation based on if the robot has another point to walk to.
if (!nextLocation()){
// Set Idle animation
mAnimationState = mRobot[0]->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}else{
// Rotation Code will go here later
Ogre::Vector3 src = mRobotNode[0]->getOrientation() * Ogre::Vector3::UNIT_X;
if ((1.0f + src.dotProduct(mRobotDir)) < 0.0001f) {
mRobotNode[0]->yaw(Ogre::Degree(180));
}else{
Ogre::Quaternion quat = src.getRotationTo(mRobotDir);
mRobotNode[0]->rotate(quat);
} // else
}//else
}else{
mRobotNode[0]->translate(mRobotDir * move);
} // else
} // if
mAnimationState->addTime(evt.timeSinceLastFrame);
}
Here is the raycast code for my mouse click
Ogre::Terrain* pTerrain = mTerrainGroup->getTerrain(0, 0);
Ogre::Viewport* vp = this->mWindow->getViewport(0);
Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(static_cast<float>(mMouse->getMouseState().X.abs)/mMouse->getMouseState().width, static_cast<float>(mMouse->getMouseState().Y.abs)/mMouse->getMouseState().height);
std::pair <bool, Ogre::Vector3> result;
result = pTerrain->rayIntersects(mouseRay, true, 0);
if (result.first = true)
{
mtoward = result.second - mRobotNode[0]->_getDerivedPosition();
mRobotNode[0]->translate(mtoward, Ogre::Node::TS_LOCAL);
}

Prevent moving a sprite onto another sprite

I have some sprites (2d-boxes) of the same type stored in a formation vector. Now i want to move them around with the mouse, that works well. But the code should prevent the player to move one sprite onto another already existing sprite of the vector.
My solution is quite ugly and does not work. Whenever a sprite is moved around, i test with the spriteoverlap function if the sprite is moved onto another. The Problem:
Whenever the sprite is directly close to the it stops moving, which is what wanted.
But i can't move it anymore afterwards because the overlapfunction sets the bool always to false.
while (App.pollEvent(Event))
{
//Moving the playerbuttons on the formation screen
for (size_t k = 0; k < formation.size(); k++)
{
bool drag_onto_otherplayer = false;
if (isMouseOver(formation[k], App) == true)
{
//The next loop tests if the sprite being moved with the mouse overlaps with another sprite from the formation vector
for (size_t j = 0; j < formation.size(); j++)
{
if (spriteOverlap(formation[j], formation[k], App) == true && k!=j)
{
std::cout << drag_onto_otherplayer << std::endl;
drag_onto_otherplayer = true;
std::cout << drag_onto_otherplayer <<std::endl;
}
if (drag_onto_otherplayer == false)
//(If the sprite does not overlap getting the new sprite position from the mouseposition)
{
Mouseposition =sf::Vector2f(sf::Mouse::getPosition(App));
Mouseposition.x = Mouseposition.x - formation[k].getLocalBounds().width / 2;
Mouseposition.y = Mouseposition.y - formation[k].getLocalBounds().height / 2;
formation[k].setPosition(sf::Vector2f(Mouseposition));
Formation_playernames.clear();
Formation_playerinformation.clear();
Formation_Playernames(Font, Formation_playernames, formation, playerlist);
Formation_Playerinformation(Font, Formation_playerinformation, formation, playerlist);
}
So the problem are my loops and the bool test i guess, but i don't know how to solve it.
Any ideas ?
Here is my spriteoverlap function:
bool spriteOverlap(sf::Sprite &sprite1, sf::Sprite &sprite2, sf::RenderWindow &App)
{
float x_min1 = sprite1.getPosition().x;
float x_max1 = sprite1.getPosition().x + sprite1.getLocalBounds().width;
float y_min1 = sprite1.getPosition().y;
float y_max1 = sprite1.getPosition().y + sprite1.getLocalBounds().height;
float x_min2 = sprite2.getPosition().x;
float x_max2 = sprite2.getPosition().x + sprite2.getLocalBounds().width;
float y_min2 = sprite2.getPosition().y;
float y_max2 = sprite2.getPosition().y + sprite2.getLocalBounds().height;
if (x_min1 > x_max2 | x_max1 < x_min2 | y_min1 > y_max2 | y_max1 < y_max2)
return false;
else
return true;
};
And my isMouseover function:
bool isMouseOver(sf::Sprite &sprite, sf::RenderWindow &App)
{
float pos_x = sprite.getPosition().x;
float pos_y = sprite.getPosition().y;
if (sf::Mouse::getPosition(App).x > pos_x && sf::Mouse::getPosition(App).x < pos_x+sprite.getLocalBounds().width &&
sf::Mouse::getPosition(App).y >pos_y && sf::Mouse::getPosition(App).y < pos_y + sprite.getLocalBounds().height)
{
return true;
}
else
return false;
};
Check for collision is already included somewhat in sfml:
bool spriteOverlap(sf::Sprite& sprite1, sf::Sprite& sprite2) // possibly const, dunno
{
return sprite1.getGlobalBounds().intersects(sprite2.getGlobalBounds());
}
Generally try this: Only move, if the position of the next frame is valid. This prevents objects being stuck, because you already moved them into an invalid position, thus preventing any further movement
edit:
//untested
bool spritesWillOverlap(sf::Sprite& sprite1, sf::Sprite& sprite2, sf::Vector2f vel)
{
top1 = sprite1.getGobalBounds().top + vel.y;
left1 = sprite1.getGlobalBounds().left + vel.x;
right1 = left1 + sprite1.getGlobalBounds().width;
bottom1 = top1 + sprite1.getGlobalBounds().height;
top2 = sprite2.getGobalBounds().top + vel.y;
left2 = sprite2.getGlobalBounds().left + vel.x;
right2 = left2 + sprite1.getGlobalBounds().width;
bottom2 = top2 + sprite1.getGlobalBounds().height;
sf::FloatRect rect1(top1, left1, right1 - left1, bottom1 - top1);
sf::FloatRect rect2(top2, left2, right2 - left2, bottom2 - top2);
return rect1.intersects(rect2);
}
vel: velocity -> an object is moved by this 2D vector every frame
If the concept of "frames" is unfamiliar, read up on framerates/fixed framerate and/or timestep. here's an example article to get started: Fix Your Timestep!

OpenSceneGraph 3D Programming Toggle Mouse Sensitivity

I have a requirement to put code in to toggle the sensitivity of the mouse - increase or decrease the speed of my Camera’s walk speed in the scene. Currently, I have an eventhandler wired up to intercept keyboard commands, and process them accordingly. What is missing is the right code to slow/increase speed by selected amount.
I have the enum below to depict the acceptable increase/decrease values.
enum CameraSpeed {_WALK = 10, _BRISK_WALK = 17, _JOG = 23, _RUN = 31, _RUN_FAST = 34, _FLY=60};
CameraSpeed _current_camera_speed;
I tried overwriting the CameraManipulator’s base class’s bool performMovement() method like so, but on careful examination, this does not seem to be the code I need to override or use for this purpose. I would appreciate some help in not only getting to the right method but also modifying it so I can control sensitivity even more.
bool WalkingCameraManipulator::performMovement()
{
// return if less then two events have been added
if( _ga_t0.get() == NULL || _ga_t1.get() == NULL )
return false;
// get delta time
double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime();
if( eventTimeDelta < 0. )
{
OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl;
eventTimeDelta = 0.;
}
// get deltaX and deltaY
float dx = (_ga_t0->getXnormalized() - _ga_t1->getXnormalized()/_current_camera_speed);
float dy = (_ga_t0->getYnormalized() - _ga_t1->getYnormalized())/_current_camera_speed;
// return if there is no movement.
if( dx == 0. && dy == 0. )
return false;
// call appropriate methods
unsigned int buttonMask = _ga_t1->getButtonMask();
if( buttonMask == GUIEventAdapter::LEFT_MOUSE_BUTTON )
{
return performMovementLeftMouseButton( eventTimeDelta, dx, dy );
}
else if( buttonMask == GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
buttonMask == (GUIEventAdapter::LEFT_MOUSE_BUTTON | GUIEventAdapter::RIGHT_MOUSE_BUTTON) )
{
return performMovementMiddleMouseButton( eventTimeDelta, dx, dy );
}
else if( buttonMask == GUIEventAdapter::RIGHT_MOUSE_BUTTON )
{
return performMovementRightMouseButton( eventTimeDelta, dx, dy );
}
return false;
}

SFML Sprite moving violently down on 2nd tick

I am working on an SFML game and for some reason after spawning the player, the player gets teleported down. On the first tick he is correctly positioned, but after wards, he is moved down. Any idea on how to diagnose this problem? I set up breakpoints in the move mechanism, the only place where the player's co-ordinates change, and it seems to happen right after the function ends. This is the main function:
int main(){
App.ShowMouseCursor(false);
mainch.mainchinventory.read();
while (App.IsOpened())
{
sf::Event Event;
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App.Close();
}
float time = App.GetFrameTime();
mainch.move(time);
App.Clear();
drawall();
App.Display();
}
return EXIT_SUCCESS;
}
Mainch.move(t):
void cmainchar::move(float t){
if (App.GetInput().IsKeyDown(sf::Key::S)) mainchinventory.save();
if (App.GetInput().IsKeyDown(sf::Key::R)) mainchinventory.read();
if (App.GetInput().IsKeyDown(sf::Key::A)) A = true;
else A = false;
if (App.GetInput().IsKeyDown(sf::Key::D)) D = true;
else D = false;
if(grounded)
if (App.GetInput().IsKeyDown(sf::Key::W)) first = true;
if ((App.GetInput().IsKeyDown(sf::Key::I)) && (keyreleased)){
if (mainchinventory.drawmain){
mainchinventory.drawmain = false;
mainchinventory.press(mainchinventory.selectionx, 3);
}
else{
mainchinventory.drawmain = true;
}
keyreleased = false;
}
else if (!App.GetInput().IsKeyDown(sf::Key::I))
keyreleased = true;
if(!mainchinventory.drawmain){
if(App.GetInput().IsKeyDown(sf::Key::Num1)) mainchinventory.press(0, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num2)) mainchinventory.press(1, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num3)) mainchinventory.press(2, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num4)) mainchinventory.press(3, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num5)) mainchinventory.press(4, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num6)) mainchinventory.press(5, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num7)) mainchinventory.press(6, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num8)) mainchinventory.press(7, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num9)) mainchinventory.press(8, 3);
else if(App.GetInput().IsKeyDown(sf::Key::Num0)) mainchinventory.press(9, 3);
if(App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left)){
mainchinventory.dockitems[mainchinventory.selectionx].use();
spells.push_back(cspell());
}
}
else if ((App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left)) && (mainchinventory.drawmain) && (buttonreleased)){
mainchinventory.checkmouse();
buttonreleased = false;
}
else if (!App.GetInput().IsMouseButtonDown(sf::Mouse::Button::Left))
buttonreleased = true;
int xmap = (View.GetCenter().x - 320) / 40;
int ymap = (View.GetCenter().y - 240) / 40;
if ((xmap != xmapold) || (ymap != ymapold))
maps.read();
xmapold = xmap;
ymapold = ymap;
collisions();
for(std::list<cspell>::iterator i = mainch.spells.begin(); i != mainch.spells.end(); i++)
if (i->move(t))
spells.erase(i);
if (A && left){
animate(2, t);
you.Move(-160 * t, 0);
}
if (D && right){
animate(1, t);
you.Move(160 * t, 0);
}
if (!D && !A)
animate(0, t);
if (up){
if(grounded && first){
jump = 1.25;
first = false;
}
if (jump > 0){
you.Move (0,-250 * t * jump);
jump = jump - 1 * t;
}
if (jump <= 0){
jump = 0.f;
}
}
else{
first = false;
jump = 0.f;
}
if (down){
fall = fall + 10 * t;
you.Move(0, 25 * fall * t);
grounded = false;
}
else{
fall = 0.f;
grounded = true;
}
if(teleport){
mainchinventory.spawn = true;
fall = 0.f;
jump = 0.f;
maps.changemap(maps.nxtmap);
teleport = false;
}
moveview();
}
You don't show the code where you're manipulating the sf::Sprite object, so I (or anyone else, really) can't say for certain, but...that said, I have a strong guess as to what's happening.
I've been familiarizing myself with SFML recently, too, and I encountered this issue myself. What I think is happening is you're calling sf::Sprite::Move(x,y) to move the sprite to position (x,y). This is incorrect; what you should be calling is sf::Sprite::SetPosition(x,y). (Both these functions take will take a 2d vector as an argument instead, btw).
I'm operating under the assumption you're using SFML 1.6, yes? Looks that way...version 2.0 changes the API somewhat, so in case you're using that Sprite::Move() becomes Sprite::move() and Sprite::SetPosition() becomes Sprite::setPosition().
Anyways, to wrap this up: the difference between Move(x,y) and SetPosition(x,y) is that Move adjusts the sprite's position relative to its current position, whereas SetPosition moves the sprite to a new position regardless of where it was before.
Again, this is a blind guess since the relevant code was not included...so was my shot in the dark correct?
Unfortunately, you haven't provided enough code for a straightforward diagnosis. With what you provided however, my best guess is that your fall variable hasn't been initialized. If it hasn't been initialized, its values can be completely random, likely being much larger than expected. This would explain your 'teleporting' behavior.