noob stuck with code

Started by
7 comments, last by Misantes 9 years, 6 months ago

ok, i'm a total noob at coding (just started two days ago) and finished reading "Learning c++ through game programming".

There where still something I have problems with but I really wanted to take a break a screw around a bit so I started programming something I hope it will be an asteroids copy. I want to do it step by step and is more for the fun before i really start studying again.

But i'm currently stuck and I really want to know how to fix it (I think I know the problem but i just don't really know how to fix it)(I'm using the pong example of sfml as reference)


#include <SFML\Graphics.hpp>
#include <SFML\Window.hpp>
#include <iostream>
#include <ctime>

int main(){
	// Constanten//
	const int GameWidth = 800;
	const int GameHeight = 600;
	const int Speed = 5;
	sf::Clock clock;
	bool isPlaying = false;
	sf::RenderWindow window(sf::VideoMode(GameWidth,GameHeight ,32),"Asteroids");

	//bouwen van schip//
	sf::CircleShape triangle(15,3);
	triangle.setFillColor(sf::Color::Black);
	triangle.setOutlineColor(sf::Color::White);
	triangle.setOutlineThickness(3);
	triangle.setPosition((GameWidth/2),(GameHeight/2));
	
	// Opening scherm //
	while(window.isOpen()){
		sf::Event Event;
		bool isPlaying = false;
		while(window.pollEvent(Event)){
			if((Event.type == sf::Event::Closed)||((Event.type == sf::Event::KeyPressed)&&(Event.key.code== sf::Keyboard::Escape))){
				window.close();
			};
			//starten//					
			if((Event.type == sf::Event::KeyPressed)&&(Event.key.code == sf::Keyboard::E)){
				if(!isPlaying){
					isPlaying = true;
					triangle.setPosition((GameWidth/2),(GameHeight/2));
				}
				if(isPlaying){
						
					if((Event.type == sf::Event::KeyPressed)&&(Event.key.code == sf::Keyboard::Z))
					{
						sf::Time tijd = clock.getElapsedTime();

						float deltaTime = tijd.asSeconds();

						triangle.move(0, -Speed*deltaTime);
						clock.restart();
					}
				}
			}

			//Weergeven schermen //
			window.clear(sf::Color::Black);
			window.draw(triangle);
			window.display();
		};
	};
return 0;
}

The place where i'm stuck is the movement code. I'm thinking it is because there is to little time between activation and restarting for it to really move but still I can't see anything. Please tell me what i did wrong and how I can fix this

Advertisement

If you don't mind clarifying, what is your actual problem? It's a little unclear. Does your character not move at all when pressed?

As a side note, using sf::Event for movement is generally a bad idea (depending on circumstances) as it takes in KeyPress and will suffer from your OS's key delay. I think it's generally best to use sf::Keyboard::isKeyPressed(sf::Keyboard::WhateverKey);

From Here:

"Sometimes, people try to react to KeyPressed events directly to implement smooth movement. Doing so will not produce the expected effect, because when you hold a key you only get a few events (remember, the repeat delay). To achieve smooth movement with events, you must use a boolean that you set on KeyPressed and clear on KeyReleased; you can then move (independently of events) as long as the boolean is set.

The other (easier) solution to produce smooth movement is to use real-time keyboard input withsf::Keyboard (see the dedicated tutorial).

"
Perhaps try using the KeyBoard::isKeyPressed() function to trigger your movement. Though, for starting the game, an Event is perfectly fine as it's called once and only once. When I use sfml, I tend to use Events for things that I want to happen once, like casting a spell, or opening a menu, but isKeyPressed for things where you want to check if the key is still pressed, like movement or rapid firing of a weapon.
So, it would look something roughly like:

if(isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::Z))//checks if key is pressed
{		
    float deltaTime = clock.restart().asSeconds();//this will restart clock, as well as return the time

    triangle.move(0, -Speed*deltaTime);
}
				
If that isn't actually what your problem is, just post and we'll go from there.
Also, welcome smile.png

Beginner here <- please take any opinions with grain of salt

Don't do logic updating inside your event reactions.

Here's an example of a possible layout that works decently well:


int main()
{
	const float UpdateTickInterval = (1.0f / 30.0f); //30 times a second.

	//Create the window.
	sf::RenderWindow renderWindow.create(sf::VideoMode(800, 600), "My game");

	//Set the icon.
	sf::Image iconImage;
	AssertExpr(iconImage.loadFromFile("./Icon.png"));
	renderWindow.setIcon(iconImage.getSize().x, iconImage.getSize().y, iconImage.getPixelsPtr());

	//Begin tracking the framerate.
	sf::Clock updateClock;

	//Create the root gamestate.
	RootGameState rootGameState;

	//Main loop.
	while(rootGameState.StillRunning())
	{
		//Process the events.
		sf::Event event;
		while(renderWindow.pollEvent(event))
		{
			//Send the game states the events.
			rootGameState.DoReacting(event);
		}

		//Update everything, if we've accumulated enough time.
		//Also do logic; for performance reasons, we don't need to do thinking and updating every frame.
		if(updateClock.getElapsedTime().asSeconds() > UpdateTickInterval)
		{
			rootGameState.DoUpdating(updateClock.restart().asSeconds());
		}

		//Clear the window.
		renderWindow.clear(sf::Color::Black);

		//Draw everything.
		rootGameState.DoDrawing(renderWindow);

		//Display everything.
		renderWindow.display();
	}

	return 0;
}

Note: There are better ways to handle updating, so things look smoother, but for a basic 2D game, this works well enough.

When you get a keypress, store the result like 'movingLeft = true' (or let SFML store it for you in sf::Keyboard::isKeyPressed()), as Misantes mentioned), and then in your update function, update the movement for as long as 'movingLeft' is still true, based on the speed of the player and the amount of time pressed. Or you can give the player a velocity, change the current velocity in the event-handling function, but continually apply the velocity to the actual player position, based on the amount of time passed, in the update() function.

You have an if condition that checks if an event is the E key being pressed, and inside that block you check if the event is for the Z key being pressed. That will never work, if the event is "E pressed" the inner if will be false, and if the event is "Z pressed" the outer if will be false.

Also, you have a "isPlaying" variable that is constantly being set to "false" (it's inside the "while(window.isOpen())" loop), and when you press a key you set it to "true" and also move the triangle to the center of the screen.

And one last thing, you are only drawing when there are events, you need to do it all the time. I guess you are confused about the first and the second "while" loops you defined, the "while(window.isOpen())" will be called all the time until you quit the game, even if there are no events, and the "while(window.pollEvent(Event))" will be called for every new event that happened since the last check. If you stop pressing keys the block of code won't be executed.

I guess you need to do something like this:


sf::Event Event;
bool isPlaying = false;

while(window.isOpen()){
		
	while(window.pollEvent(Event)){
		if((Event.type == sf::Event::Closed)||((Event.type == sf::Event::KeyPressed)&&(Event.key.code== sf::Keyboard::Escape))){
			window.close();
		};
		//starten//					
		if((Event.type == sf::Event::KeyPressed)&&(Event.key.code == sf::Keyboard::E)){
			if(!isPlaying){
				isPlaying = true;
				triangle.setPosition((GameWidth/2),(GameHeight/2));
			}
		}
                if(isPlaying){
			if((Event.type == sf::Event::KeyPressed)&&(Event.key.code == sf::Keyboard::Z))
			{
				sf::Time tijd = clock.getElapsedTime();

				float deltaTime = tijd.asSeconds();

				triangle.move(0, -Speed*deltaTime);
				clock.restart();
			}
		}
	};

        //Weergeven schermen //
	window.clear(sf::Color::Black);
	window.draw(triangle);
	window.display();
};

Thanks alot for you're comments, the problem is now fixed :D

Think there where 2 main problems:

1) is the fact the isPlaying kept on getting resetted to false (thx crossbones)

2) I messed up with my loops: the part of code that was responsible of the movement was inside if statement for activating the game (thx Diego)

also thank you Misantes for telling me how to have a smoother action.

So i've been playing around moving my triangle when I noticed something and I wonder if it can be fixed:

when i'm turning and holding down both Z and Q or D, I turn but when i let go of Q or D and keep Z down, it stops moving. Now i'm wondering why and how I can fix this.

This is the code i'm using.


// Opening scherm //
	while(window.isOpen()){
		sf::Event Event;
		
		while(window.pollEvent(Event)){
			if((Event.type == sf::Event::Closed)||((Event.type == sf::Event::KeyPressed)&&(Event.key.code== sf::Keyboard::Escape))){
				window.close();
			};
			//starten//					
			if((Event.type == sf::Event::KeyPressed)&&(Event.key.code == sf::Keyboard::E)){
				if(!isPlaying){
					isPlaying = true;
					triangle.setPosition((GameWidth/2),(GameHeight/2));
				}
			}
			
			

			if((isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::Z)))
					{

						
					float SpeedY = (Speed * cos(triangle.getRotation()*degree)) ;
					float SpeedX = (Speed * sin(triangle.getRotation()*degree));
					 

					triangle.move(SpeedX,-SpeedY);
														 
			};

				if(isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
				{	
					triangle.setRotation(triangle.getRotation()-1);
					
				};
				
				if(isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::D)){
					triangle.setRotation(triangle.getRotation()+1);
						if(isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
				{	
					triangle.setRotation(triangle.getRotation()-1);
					
				};
					
				};
						  
			if((isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::S)))
					{

						
					float SpeedY = (Speed * cos(triangle.getRotation()*degree)) ;
					float SpeedX = (Speed * sin(triangle.getRotation()*degree));
					 

					triangle.move(SpeedX,SpeedY);

														 
			};		
			if(isPlaying && sf::Keyboard::isKeyPressed(sf::Keyboard::Space)){
				window.draw(bullet);
			}

			}

			//Weergeven schermen //
			window.clear(sf::Color::Black);
			window.draw(triangle);
			window.display();
	};
	
return 0;
}

The "while(window.pollEvent(Event))" loop will only be accessed when an event occurs, and holding a key down is not an event.

Inside that loop, check for events, like closing the window. The "isKeyPressed" calls should be done outside that loop.

EDIT: Sorry, I see you get an event, but with the delay Misantes mentioned. But, anyway, the isKeyPressed should be outside the loop, see if that makes a difference.

I have another question (hopefully this doesn't annoy you guys)

Basicly i want to create an object that starts moving at the beginning of the game and keeps on moving until something happens and i succeeded. The problem is that the movement happens in "jumps": it moves, then stops for a sec and then moves again. Now i'm wondering how i can move it without stopping and without using keys or something like that.

ps here is the code i'm using, it's pretty simple:


Ball.move(std::cos(BallAngle)*BallSpeed*deltaTime,std::sin(BallAngle)*BallSpeed*deltaTime);

Where are you putting that line? You may want to post a larger snippet of the code for this question. It could depend on how you're calculating deltaTime, BallSpeed, where you're placing this line or any number of things.

You may want to take a look at implementing a time-step. I'm not sure if that's the issue, but often times without one, you'll get funny updates. As a minor note, if your ball angle is pretty consistent, and only changes on certain states, you may not want to recalculate the sin/cos of the angle every iteration (unless it's say, a homing missile headed for a moving target). Calculate the angle once, when needed, and set it as your move parameter until its state needs to change, recalculate, etc (also, probably not the issue).

Beginner here <- please take any opinions with grain of salt

This topic is closed to new replies.

Advertisement