Im kinda new to glut and opengl and I'm trying to make camera movement on mouse movement but when trying to get the mouse position on the screen I assumed the method you want to pass the x and y to should just be referenced in the glutPassiveMotionFunc() parameter. But I'm getting errors when trying to give the function the CameraMove method. I know I'm passing the method wrong but Im not sure how.
void helloGl::CameraMove(int x, int y)
{
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 60)
mouseY = 60;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;`enter code here`
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
}
void helloGl::mouse(int button, int state, int x, int y)
{
switch (button)
{
// When left button is pressed and released.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL);
}
else if (state == GLUT_UP)
{
glutIdleFunc(NULL);
}
break;
// When right button is pressed and released.
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL);
//fltSpeed += 0.1;
}
else if (state == GLUT_UP)
{
glutIdleFunc(NULL);
}
break;
case WM_MOUSEMOVE:
glutPassiveMotionFunc(CameraMove);
break;
default:
break;
}
}
Assuming helloGl is a class. Then the answer is, you can't. A function is not the same as a method. The thing is that glutPassiveMotionFunc() expects:
void(*func)(int x, int y)
But what you're trying to give it is:
void(helloGl::*CameraMove)(int x, int y)
In other words a thiscall. This doesn't work because a thiscall basically has an additional hidden argument in contrast to a cdecl. In all it's simplicity you can imagine your CameraMove() as:
void CameraMove(helloGl *this, int x, int y)
As you can see, that isn't the same. So the solution is then to move CameraMove() out of your helloGl class or making the method static.
Related
I am new to c++ and Opencv.
I am trying to detect the mouse coordinates when I click the left button of the mouse, and if such coordinates are within a certain area of the image, it draws a rectangle using the current mouse coordinates as the top-left vertex.
Here is the implementation:
void CallBackFunc(int event, int x, int y, int flags, void * userdata)
{
if(event == EVENT_LBUTTONDOWN || event == EVENT_LBUTTONUP)
{
mouseX=x;
mouseY = y;
`
if(( mouseX >= 0 && mouseX <= 130) && ( mouseY >= 22 && mouseY <=301))
{
rectangle(img,Point(mouseX, mouseY),Point(mouseX+30, mouseY+ 40),Scalar(0,0,0),1,8);
}
}
It will store the coordinates, but it seems that it never executes the inner if statement.
I am currently working with SDL2 and am fairly new to it. I am trying to use case statments to get the mouse motion coordinates only while the left mouse button is pressed down.
In the end, I need to be able to click on a object and find how much the mouse is dragged from that selected object.
So far I have been able to get the mouse press and the mouse motion working separately, but not at the same time.
Here is my code for the mouse press event:
void SDL::OnEvent(SDL_Event *_event)
{
Mallet mallet;
switch (_event->type)
{
case SDL_QUIT:
m_running = false;
break;
default:
break;
case SDL_KEYUP:
switch (_event->key.keysym.sym)
{
case SDLK_SPACE:
if(m_playerTurn == 1)
m_playerTurn = 2;
else
m_playerTurn = 1;
std::cout<<"player turn = "<<m_playerTurn<<std::endl;
break;
}
case SDL_MOUSEBUTTONDOWN:
switch(_event->button.button)
{
case SDL_BUTTON_LEFT:
int x = _event->button.x;
int y = _event->button.y;
if(m_playerTurn == 1)
{
bool collision = checkCollision(x, y, m_player1->getTeamMallets(), mallet);
if(collision)
std::cout<<"collision with P1"<<std::endl;
}
if(m_playerTurn == 2)
{
bool collision = checkCollision(x, y, m_player2->getTeamMallets(), mallet);
if(collision)
std::cout<<"collision with P2"<<std::endl;
}
break;
}
}
}
Can anyone help.
Many thanks in advance.
Will
on SDL_MOUSEBUTTONDOWN set variable click = true ans save x,y coordinates,
on SDL_MOUSEMOTION check if click == true and update x,y coordinates,
on SDL_MOUSEBUTTONUP set click = false and calculate distance.
http://lazyfoo.net/tutorials/SDL/17_mouse_events/index.php
I got a problem with my code, I'm trying to make a First Person 3D Camera.
I use SDL_GetKeyboardState(NULL) to get the pressed keys.
When I press one of the defined keys nothing happens, why?
Camera (Controll):
void Control(float movevel, float mousevel, bool mi, SDL_Window* window)
{
if (mi) //if the mouse is in the screen
{
int MidX = 640 / 2; //middle of the screen
int MidY = 480 / 2;
SDL_ShowCursor(SDL_DISABLE); //we don't show the cursor
int tmpx, tmpy;
SDL_GetMouseState(&tmpx, &tmpy); //get the current position of the cursor
camYaw += mousevel*(MidX - tmpx); //get the rotation, for example, if the mouse current position is 315, than 5*0.2, this is for Y
camPitch += mousevel*(MidY - tmpy); //this is for X
lockCamera();
//SDL_WarpMouse(MidX, MidY); //move back the cursor to the center of the screen
SDL_WarpMouseInWindow(window, MidX, MidY);
const Uint8* kstate = SDL_GetKeyboardState(NULL);
if (kstate[SDLK_w])
{
if (camPitch != 90 && camPitch != -90)
{ //if we are facing directly up or down, we don't go forward, it will be commented out, when there will be gravity
moveCamera(movevel, 0.0); //move forward
}
moveCameraUp(movevel, 0.0); //move up/down
}
if (kstate[SDLK_s])
{
//same, just we use 180 degrees, so we move at the different direction (move back)
if (camPitch != 90 && camPitch != -90)
{
moveCamera(movevel, 180.0);
}
moveCameraUp(movevel, 180.0);
}
if (kstate[SDLK_a])
{ //move left
moveCamera(movevel, 90.0);
}
if (kstate[SDLK_d])
{ //move right
moveCamera(movevel, 270);
}
}
glRotatef(-camPitch, 1.0, 0.0, 0.0);
glRotatef(-camYaw, 0.0, 1.0, 0.0);
}
Main (Loop)
while (running)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
SDL_Event ev;
while (SDL_PollEvent(&ev))
{
switch (ev.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
int x, y;
SDL_GetMouseState(&x, &y);
Main::handleKeys(ev.key.keysym.scancode, x, y);
break;
}
}
Main::update(window);
Main::render(window);
SDL_GL_SwapWindow(window);
}
Main (Update):
void Main::update(SDL_Window* window)
{
Control(0.2, 0.2, mousein, window);
UpdateCamera(0.2); //move the camera to the new location
}
you should call the glRotatef functions before you translate the camera, otherwise it will be rotated about the origin and not its position
Use SDL_PumpEvents() to update the state array. (From the SDL_GetKeyboardState() wiki).
I believe that if you do:
SDL_PumpEvents();
SDL_GetKeyboardState(NULL);
you should get the results you are looking for. (You need to SDL_PumpEvents every loop as well as SDL_GetKeyboardState obviously)
(EDIT)
Another option:
case SDL_KEYDOWN:
switch(event.key.keysym.sym){
case SDLK_w
(... code)
break;
case SDLK_s:
(... code)
break;
case SDLK_a:
(... code)
break;
case SDLK_d:
(... code)
break;
You can also send the event.key.keysym.sym to a function and use it their ofcourse.
I am trying to make a game and am stuck on gravity..... In the following code a rectangle stands for a player and when I press up key it moves in y-axis but when I activate gravity on it (i.e resetting its previous position) it does not animate (i.e. It does not jumps) instead it just stays in its position. I am using SFML library of C++ and that's a game development tool. Please Help!
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Gravity");
sf::RectangleShape rectangle;
rectangle.setSize(sf::Vector2f(100, 100));
rectangle.setFillColor(sf::Color::Black);
rectangle.setPosition(sf::Vector2f(10, 350));
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
if(Event.type == sf::Event::Closed)
{
window.close();
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
rectangle.move(0, -1);
}
if(rectangle.getPosition().y >= 350-1)
{
rectangle.setPosition(0, 350);
}
window.display();
window.clear(sf::Color::Cyan);
window.draw(rectangle);
}
}
Theoretically your code would work, but there's one significant problem:
Your initial position is 350.
Now your "jumping code" (which will allow the player to fly indefinitely!) triggers and your position is changed to 349.
However, your code keeping the player from dropping off the screen (y >= 350-1) essentially resolves to the check y >= 349, which will be true, so your position is permanently reset to 350.
To solve this, just remove the -1 or replace the >= operator with >.
While your approach should be working (once the fix above is applied), you should rethink your strategy and store a velocity in addition to a position. I've recently written the following example code. It's far from being perfect, but it should teach you a few basics for a jump and run game (not necessarily the only way to do such things):
Allow the player to jump.
Apply gravity.
Allow the player to determine jump height based on how long he holds down a key.
#include <SFML/Graphics.hpp>
int main(int argc, char **argv) {
sf::RenderWindow window;
sf::Event event;
sf::RectangleShape box(sf::Vector2f(32, 32));
box.setFillColor(sf::Color::White);
box.setOrigin(16, 32);
box.setPosition(320, 240);
window.create(sf::VideoMode(640, 480), "Jumping Box [cursor keys + space]");
window.setFramerateLimit(60);
window.setVerticalSyncEnabled(false);
// player position
sf::Vector2f pos(320, 240);
// player velocity (per frame)
sf::Vector2f vel(0, 0);
// gravity (per frame)
sf::Vector2f gravity(0, .5f);
// max fall velocity
const float maxfall = 5;
// run acceleration
const float runacc = .25f;
// max run velocity
const float maxrun = 2.5f;
// jump acceleration
const float jumpacc = -1;
// number of frames to accelerate in
const unsigned char jumpframes = 10;
// counts the number of frames where you can still accelerate
unsigned char jumpcounter = 0;
// inputs
bool left = false;
bool right = false;
bool jump = false;
while (window.isOpen()) {
while (window.pollEvent(event)) {
switch(event.type) {
case sf::Event::KeyPressed:
case sf::Event::KeyReleased:
switch (event.key.code) {
case sf::Keyboard::Escape:
window.close();
break;
case sf::Keyboard::Left:
left = event.type == sf::Event::KeyPressed;
break;
case sf::Keyboard::Right:
right = event.type == sf::Event::KeyPressed;
break;
case sf::Keyboard::Space:
jump = event.type == sf::Event::KeyPressed;
break;
}
break;
case sf::Event::Closed:
window.close();
break;
}
}
// logic update start
// first, apply velocities
pos += vel;
// determine whether the player is on the ground
const bool onground = pos.y >= 480;
// now update the velocity by...
// ...updating gravity
vel += gravity;
// ...capping gravity
if (vel.y > maxfall)
vel.y = maxfall;
if (left) { // running to the left
vel.x -= runacc;
}
else if (right) { // running to the right
vel.x += runacc;
}
else { // not running anymore; slowing down each frame
vel.x *= 0.9;
}
// jumping
if (jump) {
if (onground) { // on the ground
vel.y += jumpacc * 2;
jumpcounter = jumpframes;
}
else if (jumpcounter > 0) { // first few frames in the air
vel.y += jumpacc;
jumpcounter--;
}
}
else { // jump key released, stop acceleration
jumpcounter = 0;
}
// check for collision with the ground
if (pos.y > 480) {
vel.y = 0;
pos.y = 480;
}
// check for collision with the left border
if (pos.x < 16) {
vel.x = 0;
pos.x = 16;
}
else if (pos.x > 624) {
vel.x = 0;
pos.x = 624;
}
// logic update end
// update the position
box.setPosition(pos);
window.clear();
window.draw(box);
window.display();
}
return 0;
}
First of all, I already did ask this in SFML forums but they couldn't help, they actually copied my code and it worked perfectly, even with someone with the same OS as me (Windows 8)
I'm currently reading the SFML Game Development book, in the first chapter, when movement is introduced, I encountered some problems, I spawn a white circle in the centre of the window, now If i press any directional arrow, the circle keeps going in the other direction till I press it, and then it gets back to normal, and horizontal and vertical ones are seperate.
Example: I start "Game", press up, the circle keeps going down, i hold up, the circle stands still, I release, it keeps going down, I press down, it stops, now it responds normally to both keys, it will happen again with the right and left, it gets fixed after the initial error, but I wish to know how I can remove it
#include <SFML/Graphics.hpp>
using namespace sf;
class Game
{
public:Game();
void run();
private:
void processEvents();
void update(Time);
void render();
void handlePlayerInput(Keyboard::Key,bool);
bool mIsMovingUp, mIsMovingRight, mIsMovingLeft, mIsMovingDown;
float playerSpeed;
Time TimePerFrame;
private:
RenderWindow mWindow;
CircleShape mPlayer;
};
Game::Game():mWindow(VideoMode(640, 480), "SFML Application"),mPlayer(), playerSpeed(20.f), TimePerFrame(seconds(1.f / 60.f))
{
mPlayer.setRadius(20.f);
mPlayer.setPosition(220.f, 220.f);
mPlayer.setFillColor(Color::White);
}
void Game::handlePlayerInput(Keyboard::Key key, bool isPressed)
{
if (key == Keyboard::W || key == Keyboard::Up)
mIsMovingUp = isPressed;
else if (key == Keyboard::S || key == Keyboard::Down)
mIsMovingDown = isPressed;
else if (key == Keyboard::A || key == Keyboard::Left)
mIsMovingLeft = isPressed;
else if (key == Keyboard::D || key == Keyboard::Right)
mIsMovingRight = isPressed;
}
void Game::run()
{
Clock clock;
Time timeSinceLastUpdate = Time::Zero;
while (mWindow.isOpen())
{
processEvents();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
processEvents();
update(TimePerFrame);
}
render();
}
}
void Game::processEvents()
{
Event event;
while (mWindow.pollEvent(event))
{
switch (event.type)
{
case Event::KeyPressed:
handlePlayerInput(event.key.code, true);
break;
case sf::Event::KeyReleased:
handlePlayerInput(event.key.code, false);
break;
case sf::Event::Closed:
mWindow.close();
break;
}
}
}
void Game::update(Time deltaTime)
{
Vector2f movement(0.f, 0.f);
if (mIsMovingUp)
movement.y -= playerSpeed;
if (mIsMovingDown)
movement.y += playerSpeed;
if (mIsMovingLeft)
movement.x -= playerSpeed;
if (mIsMovingRight)
movement.x += playerSpeed;
mPlayer.move(movement * deltaTime.asSeconds());
}
void Game::render()
{
mWindow.clear();
mWindow.draw(mPlayer);
mWindow.display();
}
int main()
{
Game game;
game.run();
}
Answer:
By default, these variables must be true:
bool mIsMovingUp, mIsMovingRight, mIsMovingLeft, mIsMovingDown;
In Game::Game(), declare them all as false. That should solve your problem.
Explanation:
In other words, when mIsMovingUp and down are mIsMovingDown true, it stays still. When you press up and let go, it makes mIsMovingUp false but leaves mIsMovingDown true, so the ball moves mIsMovingDown. After you press and let go of mIsMovingDown, it makes mIsMovingDown false, and then they are both false and movement ceases. Same for isMovingLeft and isMovingRight.