Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am programming the game Battleship in OpenGL(GLUT) and C++.
I know how do to the graphics stuff (like displaying the field and predefined ships),
but where should I put my game code like:
if key left pressed select one field left and display it
if a ship is placed then display the ship
Things like place a ship (switching between the fields) I can't do in the display() function, but if a ship is placed it must be drawn by the display() function, right?
I don't know where to put the game logic.
What you are looking for is the basic, classic game loop. Effectively, your game runs in one giant loop. In this loop, you handle user input, react to the user input, run AI, and update the video/audio in response. This is, of course, a very simplified take on it, but it will suffice for Battleship.
Conceptually, more or less:
while(Game.IsRunning)
{
Input = GetInput();
Game.Update(Input);
Display(Game);
}
If you're actually doing real-time as opposed to event-driven, then you need to make your updates take into account the time-passed since the last update, as well as player input. I'll keep this short and limited to what you're asking though.
GLUT provides functions to intercept mouse keyboards events, like
void keyboardDown(unsigned char key, int x, int y);
void mouseClick(int button, int state, int x, int y);
void mouseMotion(int x, int y);
You may reimplement those function to get a custom behavior of your program.
For example, if you want to draw a ship after the user pushes "s" then, in your keyboardDown function, you may set a global flag to 1. Then, in the display function, you may check that flag. If it's 1 then you'll draw your ship.
Of course it's up to you how to place/move your ship :)
For further informations, take a look at the documentation
you probably want to use keyboard function and save the key pressed on stack and compare on the display which keys where pressed by the player so you can get multiple key detection something like this:
// for pressed keys
void keybd(unsigned char key,int x, int y){
//int pe;
switch(key){
case 'w':up=true;break;
case 's':down=true;break;
case 'd':right=true;break;
case 'a':left=true;break;
case ' ':trig=true;break;
}
}
// for released keys
void ms_r(unsigned char key,int x, int y){
//int pe;
switch(key){
case 'w':up=false;break;
case 's':down=false;break;
case 'd':right=false;break;
case 'a':left=false;break;
}
}
and then just compare which keys have true and act based on that
and when you are calling the glut main loop and functions
use:
glutIgnoreKeyRepeat(1);
glutKeyboardUpFunc(ms_r);
glutKeyboardFunc(keybd);
Related
As you know, glfw works with callbacks for inputs and callback functions have certain signatures that users need to match. Here is an example from the documentation:
void key_callback(GLFWwindow* window, int key, int scancode, int action, int
mods)
{
if (key == GLFW_KEY_E && action == GLFW_PRESS)
activate_airship();
}
Now, activate airship seems to be a global function here. What I really want to do is, to modify some object, possibly, at each input stage. So I want something like:
void key_callback(Airship a, GLFWwindow* window, int key, int scancode, int
action, int mods)
{
if (key == GLFW_KEY_W && action == GLFW_PRESS)
a.render_Wireframe();
}
As you can see, I want to pass the object I am trying to modify, Airship here. But this time, callback signature is distrupted. I can't use it anymore. What is the best way to achieve this? I am trying to come up with ideas but in the future, I might want to change this to work with not just airships but a new object I add as well. What should be the design here?
The thing is, with the ability to set one callback for whole program, I don't know how to achieve the following. Let's say I have two objects Airship and Battlesip. I want both of them to have their own input handling mechanism. Pressing W should do something if Airship is the picked object in the scene and something else if Battleship is the picked object.
So I want to have something like following in the end;
class Airship : public SceneObject
{
...
void input_handle(){
if(is_picked && pressed == GLFW_KEY_W)
launch_missile();
}
}
class Battleship : public SceneObject
{
...
void input_handle(){
if(is_picked && pressed == GLFW_KEY_W)
do_something_else();
}
}
And in my main loop, I have a vector of SceneObject and I call input_handle on each frame, for each object. I don't know how can I handle something like this with a single callback scheme of glfw. I can't pass those things as callback functions to a window even if I matched the signature because they are class members. Well nothing would change if I could pass class members, since I can only set one callback.
Here is how I ended up solving this issue in a simplified manner. I am not sure if this is the correct design but it might be of help to a future viewer. I have a scene graph like object, say SceneGraph that holds all the SceneObjects mentioned in the question. I ended up making this SceneGraph object a singleton. I have one scene graph per run so it seemed logical to me to make it a singleton.
class SceneGraph
{
// ...
// many more code
friend void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mods)
{
// get the singleton instance, singleton is static and this is
// a friend function, so I can register this as a callback
SceneGraph* d = SceneGraph::handle();
d->input_handle();
}
void input_handle()
{
for(auto& s : objs)
s.input_handle()
}
private:
std::vector<SceneObject> objs;
}
Of course, you can pass button state etc. to your input routines. I just wanted show the bare minimum design that I went with. Object picking example that I talked about in the original question can also be handled now.
I've got a serious problem with my SFML game.
I've been trying whole day to find a solution, tried diffrent things but nothing worked for me so far.
These are my .h files:
Bullet.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include <vector>
class Bullet
{
friend class Player;
friend class Game;
float width;
float height;
float x;
float y;
std::vector<Bullet*> projectiles;
sf::RectangleShape bullet;
void draw_projectiles(sf::RenderWindow &window);
void make_projectiles();
public:
void check();
Bullet();
~Bullet();
};
Game.h
#pragma once
#include <SFML\Graphics.hpp>
#include "Player.h"
#include "Bullet.h"
#include <vector>
//#include "Enemy.h"
class Game
{
friend class Player;
sf::RenderWindow* window;
sf::Event* evnt;
Player* player;
Bullet* bullet;
public:
void Loop();
void game_func();
Game();
~Game();
};
Player.h
#pragma once
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Game.h"
#include "Bullet.h"
class Player
{
sf::RectangleShape player;
Bullet* bullet;
int ammo;
float width;
float height;
int x;
int y;
float vel;
public:
void draw(sf::RenderWindow &window);
void move(sf::Event &evnt, sf::RenderWindow &window);
Player();
~Player();
};
Here come cpp files
Bullet.cpp
#include "Bullet.h"
void Bullet::check()
{
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
void Bullet::draw_projectiles(sf::RenderWindow &window)
{
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
}
void Bullet::make_projectiles()
{
projectiles.push_back(new Bullet());
}
Bullet::Bullet()
{
std::cout << "zostal utworzony nowy obiekt" << std::endl;
width = 50;
height = 50;
bullet = sf::RectangleShape(sf::Vector2f(width, height));
bullet.setFillColor(sf::Color::Yellow);
bullet.setPosition(0, 0);
x = bullet.getPosition().x;
y = bullet.getPosition().y;
}
Bullet::~Bullet(){}
Game.cpp
#include "Game.h"
Game::Game()
{
window= new sf::RenderWindow(sf::VideoMode(1280, 720), "SFML Game",
sf::Style::Close);
player = new Player();
}
Game::~Game(){}
void Game::Loop()
{
while (window->isOpen())
{
sf::Event evnt;
while (window->pollEvent(evnt))
{
//events
if (evnt.type==sf::Event::Closed)
window->close();
player->move(evnt, *window);
window->clear();
player->draw(*window);
window->display();
bullet->draw_projectiles(*window);
}
}
}
void Game::game_func()
{
Game::Loop();
}
Player.cpp
#include "Player.h"
void Player::draw(sf::RenderWindow &window)
{
window.draw(player);
}
void Player::move(sf::Event &evnt, sf::RenderWindow &window)
{
x = player.getPosition().x;
y = player.getPosition().y;
float width = window.getSize().x;
float height = window.getSize().y;
Bullet obj;
if (evnt.type == sf::Event::KeyPressed)
{
//movement
if (evnt.key.code == sf::Keyboard::Key::W)
{
if (y <= 0)
{
return;
}
player.move(0, -1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::S)
{
if (y >= height - Player::height)
{
return;
}
player.move(0, 1 * vel);
}
if (evnt.key.code == sf::Keyboard::Key::A)
{
if (x <= 0)
{
return;
}
player.move(-1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::D)
{
if(x>width-Player::width)
{
return;
}
player.move(1 * vel, 0);
}
if (evnt.key.code == sf::Keyboard::Space)
{
obj.make_projectiles();
}
}
}
Player::Player()
{
width = 100;
height = 100;
vel = 10;
player = sf::RectangleShape(sf::Vector2f(width, height));
player.setFillColor(sf::Color::Red);
player.setPosition(sf::Vector2f(15, 20));
}
Player::~Player(){}
And main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "Game.h"
int main()
{
Game gme;
gme.game_func();
return 0;
}
I tried many diffrent things and can't figure it out why it's not working. Im running in on Visual Studio 15.
So here is error that I'm getting:
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<Bullet *,std::allocator<Bullet *> >
>::_Mylast(...) returned 0x18.
I'm aware that code is not perfect and little messy but I'm just a begginer and trying to learn new stuff.
I will appreciate any help!
I answered your question in my last paragraphs, you can skip to that paragraph but I sugest you take a look at all of this. First of all you should understand how should a basic game look like in code.
The Game Logic
You can separate the game logic in 2 main functions. The initialization and the loop.
Initialization
In the initialization function, you basically load everything needed for your game to run (that is only available for small games, since loading tens of gigs of sprites in memory may not be the best solution for bigger ones. With time you'll figure out the right time to load and release resources).
The loop
This is called the main loop or the game loop. This loop should execute 3 main functions. Handle user input, update world, and render the world. This loop should execute while the game is running (i.e. while the window is open)
So your main in pseudo-c++ should look something like this:
Init();
while (window.isOpen())
{
HandleEvents(window); //user input
Update(elapsedTime);
Render(window);
}
I'll explain what the functions do, what the arguments mean and how this functions are mapped to your code. Keep in mind that every function has one specific task and only that. I won't check if the user is pressing a button while I'm drawing the sprites on the screen.
User input
Everything from button pressing and mouse clicking to pressing the exit button and resizing the window is called user input. User's actions generate the so called events, which we handle at the beginning of each loop. Now this events are window specific(you can't control the player if the window is minimized or unfocused). That means that the window generates the events (if I'm wrong with this one technically, please correct me). This is the reason that when you are handling events you need to pass the window.
Events
Before handling the events, you need to understand how sf::Event is made (see more on the sfml page). Long story short the sf::Event is an union (only one field is valid at a time). That is, if you try to access event.key when the window.pollEvent() returned an sf::Event::JoystickEvent you will get an undefined behavior (I lived a long happy life without knowing what unions are, never used them and probably never will, but they are quite an interesting concept that is worth at least reading about). Ok so an event object is created by calling window.pollEvent() and passing to it an sf::Event instance. This function will give you events from the queue until there are no more events to be given, that's when it returns false. With that in mind, your Event handling code would look something like:
sf::Event ev;
while (window.pollEvent(ev))
{
switch (ev.type)
{
//code for each type needed by your application
}
}
Keep in mind that key events do not handle real time input (sf::Keyboard::isKeyPressed does that). This means that if you want your character to move when you hold a button, handling it by events will result in a delay that can be the best explained by the way typing works(when you hold down 'a' for example the first character is written immediately, the rest of the input is delayed by a second before registering). This is a way of explaining it, but maybe not the most technical one(I'm asking for a little help here :) ). Anyway, this problem can be solved either by using the static methods of sf::Keyboard or by keeping a bool in your Player class that answers to the events KeyPressed and KeyReleased(the update will be handled based on that bool).
World Update
Here is your logic code(although player movement may also be handled in the events section, since it's based on them). Here you update your entities(move the enemy one more block based on his AI), move the sun around the map etc. Keep in mind that this has nothing to do with the drawing part, in this section you only change the state of your objects. In your game it means, after you launched a projective through an event triggered by the user, each frame you move the projectile. This code usually requires some sort of frame counting method.
Frames
A frame is an iteration of the loop, you can say that the game updates and draws itself each frame. Frames are a very important concept because they arise some issues. If the game updates itself each frame, that means that each frame the projectile is moving, so that means that his movement is dependent to the FPS your pc can run. This is a problem, because while your game may run as you want on your pc, at a stable 60 FPS rate, on mine it might run at 53, or some other random value. That means that the projectiles on my pc will move slower, and we don't want that.
Frame independent movement
This can be achieved by counting the frames. One way you can do that is by counting the seconds it passed since the last frame, with that in mind you can get the amount of space your entity needs to move in that specific frame. For example, you want to move your projectile with 100px/sec. If you have 2FPS that means that in 2 frames it needs to move 100px, so each frame moves 100 / 2 px. So the formula is finalDistance / framerate. There are more ways of doing this, but in my opinion this is the simplest to understand at the beginning. So how is this implemented in SFML? You basically keep a clock that you restart at the end of each update. getElapsedTime and restart does that, but restart returns the elapsedTime so it is better to call it once, since calling them one by one may result in different times and desyncs.
sf::Clock clock;
while (window.isOpen())
{
HandleEvents(window);
Update(clock.restart());
Render(window);
}
And you simply move your entities with move(vector * clock.getElapsedTime().asSeconds()) since sf::Vector has operator* overloaded for floats(the return type of asSeconds()).
Rendering
The rendering part may be very complicated, but sfml makes it "simple and fast". Basically it works like that: You clear the screen, you draw your entities, you display the screen. The more technical answer is the following: the window consists of 2 buffers, one visible and one hidden. The visible one is the one you see on the screen. When you call clear() you basically clear the hidden one, draw() draws also on the hidden window, and finally display() swaps the buffers.
That means that you won't see any results unless you call window.display(), and you'll get a window xp experience if you don't call clear() before drawing. So the Render function might look like this:
window.clear();
window.draw(player); //or player.draw(window) based on your implementation
//other draws
window.display();
Your question
What happens in your code is that you try to access things that don't exist. You add one projectile at a time, but each frame you draw 10 of them.
The solution
Keep a counter of your objects. Since you are using a vector that is already provided, you have std::vector::size that returns exactly what you expect, so your code will turn into something like:
for (int i = 0; i < yourProjectiles.size(); i++)
{
window.draw(yourProjectiles[i]->bullet);
}
Alternatively you can use iterators(look them up):
for (auto it = yourProjectiles.begin(); it != yourProjectiles.end(); ++it)
{
window.draw(it->bullet);
}
Memory management
You don't deallocate memory. You have to look into dynamic memory allocation. The base principle is that for every new there should be a delete. The deallocation part should be handled most of the time in the destructor of the class. I think someone may suggested to use smart pointers(std::shared_ptr) so manage your memory, but I can't recommend you that since you are at the beginning. Smart pointers are a concept you should keep in mind, but as you started out it is better to face the struggles of manual memory management(until you get used to it).
Code organizing
A class should be made for only one purpose. When you create a class called Bullet, it is expected that this Bullet will represent one projectile in your game, but when your Bullet makes "projectiles" and stores projectiles, it becomes a paranormal entity. Your bullet atm holds pointers to instances of other bullets that hold pointers to instances of other bullets. This is a total mess. Unless you want to create a graph or a tree of some sort you don't have any reason to store pointers of instances of the same class.
Too many friends
If every class is friend with every class, what is your reason of creating private fields? Friend is a very powerful concept and should be used with care, only in cases you DON'T have other options. The only reason I would avoid this keyword is the messiness it creates. It creates the same effect as public attributes. When everything is accessible from everywhere, everything can be destroyed from everywhere. When you create a small set of methods that manipulate your attributes, you know where the problem is.
Conclusion
I might suggest looking a little more into c++ and after that debug your game, or recreate it from scratch. While I know how it feels to try something new, you should always be careful to not shoot yourself in the leg, and don't be afraid to go back to the basics when you stumble into such errors. You have problems managing memory? Read more about dynamic memory allocation, do some example apps using it. Besides that I noticed you are still at the beginning with using classes. I'd say practice makes perfect. Look at other people code, even these 3rd party libraries like sfml may give you some hints on good class practices. The good thing is that it is not needed to look at the source code of those libraries, you just use their interface. If you like it, it means it is good written and you may borrow a part of that style and implement in your classes. I'll conclude this by saying that I am very happy and eager to help you via email if you have any other question regarding anything.
I believe you are attempting to access ten projectiles:
for (int i = 0; i < 10; i++)
{
window.draw(projectiles[i]->bullet);
}
But you only add one at a time:
projectiles.push_back(new Bullet());
Is there any difference between calling glutPostRedisplay() at the end of my display function and using an idle function callback that does nothing but call my display function? I have seen both ways used in examples and cannot tell the difference by observation.
A main loop generally looks like this:
Process and handle events
calling stuff like glutKeyboardFunc/glutMouseFunc.
Advance/update 3D state (physics/animation etc)
typically in glutIdleFunc
Re-draw the scene if needed
use glutDisplayFunc
glutPostRedisplay simply sets a flag, that tells glut to call the display callback on the next loop iteration. It doesn't actually call display [1] [2].
If you have a game, which always updates every frame this might not be that useful. Maybe if you're alt-tabbed or dragging the window you don't need to be calling display. Or you might be frame limiting by dropping frames (although I'd suggest this).
void idle()
{
...
animatedThing.value += deltaTime
glutPostRedisplay(); //scene is always changing. always call display
}
Having a "dirty" flag becomes more useful when you don't need to re-render continuously. Maybe in something like a 3D modelling package where there isn't any animation and you only move the camera occasionally. Or a GUI where you only need to update when you hover and click on stuff.
void mousedown(int button, int state, int x, int y)
{
if (clickedGUI(x, y))
glutPostRedisplay();
}
void idle()
{
...
if (myKeys[MOVE_VIEW_FORWARD])
{
view.z -= deltaTime;
glutPostRedisplay();
}
}
Anyway, to answer your question, no, there's probably not much difference. However...
I'd put the glutPostRedisplay in idle as above. Calling from within display works but gives up some control you might want later. It's essentially this:
bool shouldDraw = true;
while (1)
{
// check events, input etc
// idle/update state
if (shouldDraw)
{
shouldDraw = false;
// draw
shouldDraw = true;
}
}
I also wouldn't call display from idle from a design perspective as it removes some control from glut. For example if there's a case where glut needs to override the post-redisplay (not that I know of one) it won't be able to.
I have a Class Player like this:
class Player
{
public:
Player();
~Player(void);
Sprite *sprite;
Sprite *rocket;
void draw(int x, int y, SpaceInvaders *system);
}
and in Player.cpp
void Player::draw(int x, int y, SpaceInvaders *system) {
sprite = system->createSprite("data/player.bmp");
sprite->draw(x, y);
}
Player::~Player(void)
{
sprite->destroy();
rocket->destroy();
}
This draw method is called in a while loop in main:
player.draw(int(xPos), 480-32, system);
The game runs fine until I X the window. That's when I get "Access violation reading location 0x00000004" on the first line in the Player::draw method.
I've read that it might be due to passing a null pointer or null reference but I don't know how to fix this.
Would appreciate any help, thanks!
It's most probably because when closing the window, something gets destroyed while draw is called - most probably the system pointer.
In your case, draw should never be called when the user wants to close its window (unless the x calls another function to start a closing process of some sort). The best would be to first validate that system is not NULL or even better, use a shared pointer to ensure it is still valid when being used. Afterwwards, you shoiuld ensure that draw is not called when the window is closing - that should be done when calling the draw function (or above depending on how you've designed your application.
On a side note, unless you have a caching mechanism (and even that is not the best way to do it), you're recreating your sprite everytime it's being drawn. I suggest you keep a member variable and initialize the sprite in the construtor.
In most or all object oriented games, each class relies on not just its own but parent classes. How is this class connection implemented in C++? Do you just add a pointer for the parent class you need or is there a better way?
For example a football game, when the person class clicks it ask the scene class if he is kicking any balls, and if he is then move it. I hope this is understandable and not too abstract.
I don't think passing along the parent in a constructor is a good idea. Instead, you should be using a class that maintains a list of all game elements and facilities interactions between them; for instance, the Game class illustrated below would check for collisions between any two players and if it's detected tell each of them that they were hit and by who.
I'm not sure if this will benefit you at all, but I typed it up for my initial response so I might as well submit. Note that all of this is still relevant if you're talking about a text-only game, just ignore the allusions to graphics in that case. Game design is based around a continuous game loop, and can be thought of very simply as:
while(true)
for each tick:
react to user input
update player, enemies, objects, etc.
end while
Where "tick" is every iteration of the game clock, however you choose to implement it--based on the fps, each second, whatever. In your example, the user clicks the football, the game sees the click and tells the football to move. To do this very simply, maintain a list all of all of the game elements within a class that maintains the state. To illustrate, here are is a very basic way you could implement this:
class Game {
vector<GameElement> elements;
Football football;
Player currentPlayer;
Game() {
this.football = new Football();
}
void update() {
for e in elements:
e.update();
// Once every element has been updated for the current tick, redraw them on the screen
screen.redraw();
}
void addElement(GameElement e) {
elements.add(e);
}
}
class GameElement {
int posx, posy; // screen coordinates
void paint() {}; // method to draw this element to the screen
virtual void update();
}
class Football: public GameElement {
bool kicked;
int anglex, angley;
double velocity;
void update() {
if(kicked){
// update position, angle, velocity; slow it down, check for bounce, whatever
posx = new x position;
posy = new y position;
if(velocity == 0)
kicked = false;
}
paint(); // call the paint method after the new position has been found
}
}
Assume you have another class that inherits from GameElement, Player, with a method kick(football) that sets the passed football into motion--i.e., sets kicked=True. So to initialize the game, you'd set it up with something like:
Game game = Game();
game.add(new Football());
game.add(new Player());
while(true) {
if(user_input==X)
game.currentPlayer.kick(football);
game.update();
sleep(1);
}
This could be changed to maintain, for example, layers instead of the entire game, then a higher level class could call update of each layer in order, allowing things to be painted over each other and children to only interact with siblings. There are a lot of possibilities.
Ran into similar questions working on a poker game: Here's the way I did it:
In your example, add a scene * the_scene to the constructor of person. Then, when person is initialized pass it a pointer to scene. Since you said parent and child, if the parent Is scene then it would just use "this" and it would send the address of the parent.
Then again, it seems like that's how you were going to do it anyway. One more thing, if you need person to interact with more than one class that is not directly inside it you can make some kind of container class that would store the pointers to all of them and just pass person that one to avoid having a constructor with too many parameters.