I'm trying to make user input of WASD move a sprite around in Cocos2D-X. I'm pretty sure I'm doing everything correct but it gives me this error:
expression must be a modifiable lvalue.
Here is my code (Note: I'm new to Cocos2D-X, so it might be a bit messy)
float playerX = visibleSize.width / 2 + origin.x;
float playerY = visibleSize.height / 2 + origin.y;
auto player = Sprite::create("sprites/player.png");
if (player == nullptr)
{
problemLoading("'sprites/player.png'");
}
else
{
// position the sprite on the center of the screen
player->setPosition(Vec2(playerX, playerY));
// add the sprite as a child to this layer
this->addChild(player, 0);
}
// Keyboard events
auto keyboardListener = EventListenerKeyboard::create();
keyboardListener->onKeyPressed = [playerX, playerY](EventKeyboard::KeyCode keyCode, Event* event)
{
switch (keyCode)
{
case EventKeyboard::KeyCode::KEY_W:
playerY += 5.0f;
break;
case EventKeyboard::KeyCode::KEY_A:
playerX -= 5.0f;
break;
case EventKeyboard::KeyCode::KEY_S:
playerY -= 5.0f;
break;
case EventKeyboard::KeyCode::KEY_D:
playerX += 5.0f;
break;
case EventKeyboard::KeyCode::KEY_ESCAPE:
Director::getInstance()->end();
break;
}
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, this);
There is four of the error and they all point to a different playerX/Y +=/-= 5.0f
Try to use mutable specifier(which allows lambdas body to modify the objects captured by copy, and to call their non-const member functions):
float playerX = visibleSize.width / 2 + origin.x;
float playerY = visibleSize.height / 2 + origin.y;
auto player = Sprite::create("sprites/player.png");
if (player == nullptr)
{
problemLoading("'sprites/player.png'");
}
else
{
// position the sprite on the center of the screen
player->setPosition(Vec2(playerX, playerY));
// add the sprite as a child to this layer
this->addChild(player, 0);
}
// Keyboard events
auto keyboardListener = EventListenerKeyboard::create();
// add mutable specifier
keyboardListener->onKeyPressed = [playerX, playerY, player](EventKeyboard::KeyCode keyCode, Event* event) mutable
{
switch (keyCode)
{
case EventKeyboard::KeyCode::KEY_W:
playerY += 5.0f;
break;
case EventKeyboard::KeyCode::KEY_A:
playerX -= 5.0f;
break;
case EventKeyboard::KeyCode::KEY_S:
playerY -= 5.0f;
break;
case EventKeyboard::KeyCode::KEY_D:
playerX += 5.0f;
break;
case EventKeyboard::KeyCode::KEY_ESCAPE:
Director::getInstance()->end();
break;
}
player->setPosition(playerX, playerY);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardListener, this);
Related
int state = 1;
bool turbines_visible = true;
// move the hot air balloon up
// make the square go up
void update(int value) {
// 1 : move up
if (state == 1) {
squareY += 1.0f;
if (squareY > 650.0) {
state = 2;
squareX = -400.0f;
squareY = 200.0f;
}
}
// 2 : move right
else if (state == 2) {
squareX += 1.0f;
if (squareX > 500.0) {
state = 3;
squareX = 0.0f;
squareY = 600.0f;
}
}
// 3 : move down
else if (state == 3) {
squareY -= 1.0f;
if (squareY < 0.0) {
state = 0;
}
}
glutTimerFunc(25, update, 0);
turbines_visible = !turbines_visible;
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
switch (state) {
case 0:
drawBackground1();
break;
case 1:
drawBackground1();
break;
case 2:
drawBackground2();
break;
case 3:
drawBackground1();
break;
}
glPushMatrix();
glTranslatef(squareX, squareY, squareZ);
// display spray
drawSpray();
// display hot air balloon
drawAirBalloon();
glPopMatrix();
if (turbines_visible) {
// display first (left) wind turbine
drawLeftTurbine();
// display first (right) wind turbine
drawRightTurbine();
}
// display rain
drawRain();
calcFPS();
counter++;
glFlush();
glutSwapBuffers();
glutPostRedisplay();
}
The hot air balloon travels up perfectly fine, but the wind turbines keep faded in and out really fast, which is what I don't want. I want it to be visible in the first scene, invisible in the second scene, and visible again in the third scene. I know that the problem is with the glutTimerFunc code because it is using 25 milliseconds, but I need it for my hot air balloon. I would appreciate if someone could help me solve this problem.
Click here to see the full code
Scene 1
Click here to see GIF
Scene 2
Click here to see GIF
Scene 3
Click here to see GIF
I want it to be visible in the first scene, invisible in the second scene, and visible again in the third scene.
The condition for turbines_visible has to be
turbines_visible = !turbines_visible;
turbines_visible = state != 2;
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.
I'm going to get straight to the point:
I have a sprite sheet that has 8 movement sprites (http://i.imgur.com/hLpo2Qn.png cant post images :\ ), so it creates the illusion that im walking)
My problem is that when i press and hold a key i want the sprite to kinda have an animated walk. For example when i press the up arrow the first two sprites play in a loop until i let go of the key. All I've been able to do so far is to get only one sprite showing for each direction, so it kinda gives an unrealistic effect.
Code:
#include <SDL/SDL.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface* screen, *image;
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
bool running = true;
const int FPS = 30;
Uint32 start;
bool direction[4] = {0, 0, 0, 0};
SDL_Rect pos;
pos.x = 0;
pos.y = 0;
SDL_Rect sprite;
sprite.x = 160;
sprite.y = 0;
sprite.w = 32;
sprite.h = 32;;
Uint32 color = SDL_MapRGB(screen -> format, 0xff, 0xff, 0xff);
image = SDL_DisplayFormat(SDL_LoadBMP("sprite.bmp"));
SDL_SetColorKey(image, SDL_SRCCOLORKEY, SDL_MapRGB(screen -> format, 255, 0, 255));
while (running == true)
{
start = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_UP:
direction[0] = 1;
sprite.x = 0;
break;
case SDLK_LEFT:
direction[1] = 1;
sprite.x = 224;
break;
case SDLK_DOWN:
direction[2] = 1;
sprite.x = 160;
break;
case SDLK_RIGHT:
direction[3] = 1;
sprite.x = 96;
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_UP:
direction[0] = 0;
sprite.x = 32;
break;
case SDLK_LEFT:
direction[1] = 0;
break;
case SDLK_DOWN:
direction[2] = 0;
break;
case SDLK_RIGHT:
direction[3] = 0;
break;
}
break;
}
}
if(direction[0])
pos.y-- ;
if(direction[1])
pos.x--;
if(direction[2])
pos.y++;
if(direction[3])
pos.x++;
SDL_FillRect(screen, &screen -> clip_rect, color);
SDL_BlitSurface(image, &sprite, screen, &pos);
SDL_Flip(screen);
if(1000 / FPS > SDL_GetTicks() - start)
SDL_Delay(1000 / FPS - (SDL_GetTicks() - start));
}
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
Disclaimer: This is not the only or best way to achieve what you wanting. It is simply one possible solution
You need to implement a basic timer/counter to switch between the two appropriate images.
For this example I would store your sprite offsets in a 2D array int sprite_x[4][2]; - this would represent the four directions and the two image offsets for each. Then on a key press instead of using a bool array just have a single integer index int sprite_index; for indexing the sprite offsets. All you would then need to do is have another integer value called something like int current_key; which you would switch between 0 and 1.
// Used for indexing the 2D array
enum
{
WALK_LEFT,
WALK_RIGHT,
WALK_UP,
WALK_DOWN
WALK_MAX
};
// How many sprites per animation
const int NUM_KEYFRAMES = 2;
// 2D array to hold the x value offsets for sprites
int sprite_x[WALK_MAX][NUM_KEYFRAMES];
int sprite_index = WALK_LEFT; // Current animation
int current_key = 0; // Current keyframe for the animation
// Set up all the x value offsets in the array
sprite_x[WALK_LEFT][0] = 0;
sprite_x[WALK_LEFT][1] = 32;
sprite_x[WALK_RIGHT][0] = 64;
sprite_x[WALK_RIGHT][1] = 96;
.
.
.
You then simply update the sprite x value accordingly sprite.x = sprite_x[sprite_index][current_key];
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;
}