Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

878764 Posts in 32935 Topics- by 24346 Members - Latest Member: Vuoripeikko

May 22, 2013, 03:38:29 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Need help with objects and classes.
Pages: 1 [2] 3 4
Print
Author Topic: Need help with objects and classes.  (Read 2985 times)
ASnogarD
Level 1
*



View Profile
« Reply #15 on: November 22, 2010, 06:34:37 AM »

I'll try what you suggest and let you know what happened, thanks.

Where do you put your list of objects ? In a seperate class design to control the object list , or a function in main ?
( not the list of tile objects, I mean all the objects you put in the list )
Logged

Somethings are painfully obvious, others must be made obvious... painfully.
Netsu
Level 10
*****



View Profile WWW
« Reply #16 on: November 22, 2010, 06:38:27 AM »

Where do you put your list of objects ? In a seperate class design to control the object list , or a function in main ?
( not the list of tile objects, I mean all the objects you put in the list )
I don't quite get what you mean. What is the difference? Do you mean where do I create the objects I want to put in the list?
Logged

ASnogarD
Level 1
*



View Profile
« Reply #17 on: November 22, 2010, 06:47:32 AM »

In an earlier post you say :

Quote
Now for the objects, I keep a container for all the objects (an STL list to be precise) and iterate through all the objects in the logic function. Each object has an enum type that describes the type of the object. Now depending on the type of the object different actions are taken. For example if it has type ENEMY I move it towards the player, if it has type BULLET I check for collision with enemies etc.

Where do you create this STL list ? How do you create the list of pointers ?

Do you go :

// instance objects
classname1 *objectname1;
classname2 *objectname2;
classname3 *objectname3;
classname3 *objectname4;
classname4 *objectname5;
classname4 *objectname6;
classname4 *objectname7;

then make a list that contains all the *objectnames ?
Logged

Somethings are painfully obvious, others must be made obvious... painfully.
Netsu
Level 10
*****



View Profile WWW
« Reply #18 on: November 22, 2010, 08:04:29 AM »

Here, I'll expand the previous example:
Code:
class World
{
private:
// this is the STL vector of pointers to Tiles
static vector <Tile*> vector_of_tiles;
public:
// this function returns a pointer to a tile numbered n
static Tile* get_tile(int n);
// this function creates n new tiles
static void create_tiles(int n);
}

static Tile* World::get_tile(int n)
{
// just return the pointer in the n-th position in the vector
return vector_of_tiles[n];
}

static void World::create_tiles(int n)
{
// iterate n times
for(int i = 0; i < n; i++)
{
// create a new tile using a constructor of choice
Tile* pointer = new Tile()
// add the pointer to this new tile to the vector
vector_of_tiles.push_back(pointer);
}
}

Basically, when you create an STL vector or list like this:
Code:
vector <Tile*> vector_of_tiles;
it has length equal zero. It has no elements inside it. But when you call the member function push_back:
Code:
vector_of_tiles.push_back(pointer);
it expands by one element and puts the argument ("pointer" in this case) in this new space, in case the vector was previously empty it's in the space number '0'. It is now accessible with this call:
Code:
vector_of_tiles[0];

In particular you can do this in your main or even in a member function of player or tile:
Code:
World::create_tiles(10); // this is how you access static members
for(int i = 0; i < 10; i++)
World::get_tile(i)->member_function_of_tail();

There are significant differences between STL list and vector, each has it's specific purpose, but for a beginner I recommend using only vector at first. It's easier because it's more like an array.
Logged

ASnogarD
Level 1
*



View Profile
« Reply #19 on: November 22, 2010, 08:23:58 AM »

Sorry my bad, I meant the other objects in your game...

I understood your suggestion with the tiles and world class, I was asking about how you created your list of all the objects you used.

I will try out your idea with the static world class using tile objects as members in a vector, see how that goes and then move on to putting all the other objects into a list.

Thanks for your help , appreciate it. Beer!
Logged

Somethings are painfully obvious, others must be made obvious... painfully.
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #20 on: November 22, 2010, 08:25:15 AM »

Here, I'll expand the previous example:
Code:
class World
{
private:
// this is the STL vector of pointers to Tiles
static vector <Tile*> vector_of_tiles;
public:
// this function returns a pointer to a tile numbered n
static Tile* get_tile(int n);
// this function creates n new tiles
static void create_tiles(int n);
}

static Tile* World::get_tile(int n)
{
// just return the pointer in the n-th position in the vector
return vector_of_tiles[n];
}

static void World::create_tiles(int n)
{
// iterate n times
for(int i = 0; i < n; i++)
{
// create a new tile using a constructor of choice
Tile* pointer = new Tile()
// add the pointer to this new tile to the vector
vector_of_tiles.push_back(pointer);
}
}

This generally not a good idea.  If you have a class with nothing but static members, a namespace is generally more manageable.
Something like so:

world.h

Code:
#ifndef WORLD_H
#define WORLD_H

class Tile;

namespace World
{
    Tile *get_tile(int n);
    void create_tiles(int n);
}

#endif

world.cpp

Code:
#include "world.h"
#include "tile.h"
#include <vector>

using std::vector;

// Local data
namespace
{
    vector<Tile*> vector_of_tiles;
}

Tile *World::get_tile(int n)
{
    return vector_of_tiles[n];
}

void World::create_tiles(int n)
{
    for (unsigned x = 0; x < n; x++)
    {
        vector_of_tiles.push_back(new Tile);
    }
}

This reduces header pollution by putting far less information in the header, and allows you to switch the implementation (changing to a list from a vector, for example) without the need to recompile all the clients.

The "class full of a statics" is a Java-ism, needed in that language because Java requires everything to be in classes.  This problem doesn't exist in C++, and that approach tends to be unsuitable.
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
Netsu
Level 10
*****



View Profile WWW
« Reply #21 on: November 22, 2010, 08:35:06 AM »

That's more complicated. The way I do it is actually not the best way to do it.
The correct way would be to create one parent class, called for example Particle. It has fields such as 'position', 'velocity', 'diensions' etc. All the stuff that every object on the screen should have. It should also have an enum field that specifies the type of the object.
The you create subclasses that are more specific, the player class, tile class, enemy class, bullet class etc.

What you do then is create one big vector/list of pointers to Particles. Then in each frame of the game you do something like this:
Code:
for (int i = 0; i < all_particles.size(); i++)
{
all_particles[i]->update(); // execute the particle method that is shared between all subclasses, the most generic one
if (all_particles[i]->type == PLAYER)
all_particles[i]->update_player(); // execute a member function of player
if (all_particles[i]->type == ENEMY)
all_particles[i]->update_enemy(); // execute a member function of enemy
}

This one big vector would also be in your static World class, and you could have separate member functions for creating new enemies, new bullets and so on.
Logged

Netsu
Level 10
*****



View Profile WWW
« Reply #22 on: November 22, 2010, 08:40:00 AM »

This generally not a good idea.  If you have a class with nothing but static members, a namespace is generally more manageable.
Something like so:

[...]

This reduces header pollution by putting far less information in the header, and allows you to switch the implementation (changing to a list from a vector, for example) without the need to recompile all the clients.

The "class full of a statics" is a Java-ism, needed in that language because Java requires everything to be in classes.  This problem doesn't exist in C++, and that approach tends to be unsuitable.

Hey, good to know. Static classes are quite unwieldy (I never knew where it is best to initialise them), but up until now I thought they are the most 'correct' way to handle this stuff.
Actually classes with static members also could be changed in implementation and you only need to recompile this one class. But a namespace sound just simpler. Thanks Smiley
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #23 on: November 22, 2010, 08:56:36 AM »

Actually classes with static members also could be changed in implementation and you only need to recompile this one class. But a namespace sound just simpler. Thanks Smiley

By implementation, I was referring to the private part of the class definition.  If you change that, all the code that includes that header needs a recompile.
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
Netsu
Level 10
*****



View Profile WWW
« Reply #24 on: November 22, 2010, 09:33:44 AM »

By implementation, I was referring to the private part of the class definition.  If you change that, all the code that includes that header needs a recompile.

Why so? They shouldn't have access to the private part anyway, only to the public functions, and the interface of those isn't changed.
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #25 on: November 22, 2010, 10:13:57 AM »

By implementation, I was referring to the private part of the class definition.  If you change that, all the code that includes that header needs a recompile.

Why so? They shouldn't have access to the private part anyway, only to the public functions, and the interface of those isn't changed.

The compiler has no way of knowing what changed, so it has to recompile.  On top of that, changes to the private section may change the size of the object, which would require recompiling any code that actually instantiates that type.

There are a type of compiler called an incremental compiler that can actually analyze header changes and only recompile the files that are affected by the change, but this is actually very difficult to do and most compilers don't do it.
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
ASnogarD
Level 1
*



View Profile
« Reply #26 on: November 23, 2010, 12:42:46 AM »

Out of curiousity , I thought the whole reason Netsu suggested using a static class was to avoid needing to create a object of the world class to access the world functions ?

As far as I know merely using namespace wouldnt allow for access without an object, or  without declaring the functions static again... basically you only gain the ability to be able to use the using keyword with world and its functions.
Logged

Somethings are painfully obvious, others must be made obvious... painfully.
Netsu
Level 10
*****



View Profile WWW
« Reply #27 on: November 23, 2010, 01:46:29 AM »

Nope, actually you access everything inside a namespace exactly how you would access static members of a class. After declaring World the way Avarage Software shown you could do either this:

Code:
using namespace World;
create_tiles(10);

or this:

Code:
World::crate_tiles(10);

'Using namespace' means you don't have to specifically declare which namespace the function belongs to from now on. If you don't use this line, then you have to tell exactly where the function is, like in the second example.

You don't have to create any object, there can't be objects of namespaces, as namespaces are something different than classes. Think of them as a package for functions and variables.

The compiler has no way of knowing what changed, so it has to recompile.  On top of that, changes to the private section may change the size of the object, which would require recompiling any code that actually instantiates that type.

Oh, now I see.
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW Email
« Reply #28 on: November 23, 2010, 06:08:49 AM »

You don't have to create any object, there can't be objects of namespaces, as namespaces are something different than classes. Think of them as a package for functions and variables.

Exactly, it's an example of modular programming, which is sadly underutilized by a lot of C++ programmers.

One of the best things that ever happened to me was spending some time working in C and Ada, where I learned to do proper modular programming.  Simplified my C++ code enormously.
Logged

Franchise - The restaurant wars begin!

What would John Carmack do?
ASnogarD
Level 1
*



View Profile
« Reply #29 on: November 29, 2010, 01:03:49 AM »

I decided to rewrite the whole game again using what was advised in here, and making some good progress and enhancements compared to the original. I have a new console mechinism that allows functions to report what they are doing and accessing the namespace using IO class is a breeze, and most importantly I can visualise my path progression quiet easily and cant see any concerns about access.

I have hit a issue I am curious about though :

I changed my IO class ( basically inits SDL, sets up the surfaces and pointers to the surfaces, loads resources, and has a blit function to update the screen ) so it uses a namespace instead of a object with a pointer.
It works fine... most of the time.

The issue is it seems I cant use data members of the IO class outside the class, like I cant call my pointer to the mainscreen surface in the World class to draw the tiles to the screen, nor can I use the control system in main to increment the msgStart variable which controls which msgs are displayed in my 'console'.

I got around both issues with a special function in IO that changes / uses the members but I am curious about it.

For example my pointers are declared in IO.h between namespace IO { } as

static SDL_Surface      *mMainScreen   = NULL;
static SDL_Surface              *mGameWorld     = NULL;

removing static results in :

main.obj : error LNK2005: "struct SDL_Surface * IO::mMainScreen" (?mMainScreen@IO@@3PAUSDL_Surface@@A) already defined in IO.obj

but using the pointers in a function in the world class :

IO::apply_surface(  mTiles[ t ]->mTileXpos, mTiles[ t ]->mTileYpos, IO::mGameWorld, IO::mMainScreen ,&clips[ mTiles[ t ]->mTileType ] );

mGameWorld is the source of the tile that will get clipped and blitted to the mMainScreen surface, or least it should of done but while the code compiles and runs it doesnt show anything.

I know the problem is the pointers mGameWorld and mMainScreen as I did a test by removing the need to supply apply_surface with the pointers and added the surfaces directly into the apply_surface function and it works.
Basically when IO uses the pointers it works, but when another class tries to use the same pointers it compiles but just doesnt work... no errors or crashing , just doesnt work. It allows access via the IO::mMainScreen , but doesnt seem to do anything to or with the accessed member.

In short it seems that using a static data member in a class outside the namespace definition of that member will compile but not really use the member at all.

I have bypassed the issue with a intermediate function that basically takes a int value and uses that int value in if statements to select which surfaces to supply the apply_surface function... but it isnt ideal and I would love to work out why I cant access the pointers from outside the IO class ( ? namespace ? ).

Thanks for reading this long post.
Logged

Somethings are painfully obvious, others must be made obvious... painfully.
Pages: 1 [2] 3 4
Print
Jump to:  

Theme orange-lt created by panic