Jump to content

  • Log In with Google      Sign In   
  • Create Account

Servant of the Lord

Member Since 24 Sep 2005
Online Last Active Today, 07:41 PM

#5200196 What would you recommend for a Jrpg game?

Posted by Servant of the Lord on Yesterday, 09:59 PM

I agree with Roots 100%.

I think you should look at the RPG maker products.

Definitely start here. It's a tad costly (though you can find it on sale on Steam from time to time). You can also try GameMaker and Construct2, but RPG Maker is more RPG-focused, letting you get prototyping quickly.
 

As someone who has been working on a JRPG built from scratch for the last several years, I will tell you that it is a lot of work to build your own game.

Totally agree. While I haven't been doing it as long as Root's Hereos of Allocrost project, I've been working on my own RPG for 3 1/2 years now.
 

We use 32x32 pixel tiles, which seems to be more or less the most common size that games like this use. Our sprites are 32x64 pixels (2 tiles high), but if you're going for a more cartoonish or cute style, you may want to make them 48x32 or shorter.


My game uses 48x48, and character sprites are 48x96 (two-tiles high) - closer to 1 and 1/2 high. In-combat enemy sprites will vary greatly.
As a basic measurement in my own game, 1 pixel = 1 inch, so 48x48 = 4ft x 4ft.




#5200190 Game class holding a pointer to Renderer class

Posted by Servant of the Lord on Yesterday, 08:58 PM

I'm not an expert at architecture - I'm still learning good high-level architecture myself. But maybe I can be a wall and bounce some of your thoughts back at you.
 

I decided to create a singleton InputManager,
a singleton Application class,

Why are they singleton?

Do you *need* them to be global? Global increases coupling.

Singletons are globals in disguise.

*Must* there only ever be a single instance of them?
Singleton doesn't mean "there's only one", singleton means, "I'm going to enforce the fact that there's only one" - is that what you intend? Why?

 

InputManager since this class doesn't get changed between platforms(only the event names do)

Why do event names change between platforms? That ought to be generalized (when possible!) so the game logic doesn't always have to constantly check if it's a mouse-click OR a finger-click.
 

and a game class which handles the game logic.

'Game' is rather vague. Is it handling the logic, or more than the logic?

In my own code, my "game" class *owns* everything else. Does your class only do logic?
 

cameras and sprites which are apart of the renderer class

Why is the camera class part of the renderer? Why are sprites part of the renderer?

Certainly the renderer needs to know about them, but both the camera and the sprites should be passed in by function call during drawing. It sounds like Renderer does alot more than just rendering. Alternatively, you can "SetCurrentCamera()", and let the renderer hold a copy or pointer to the camera, but not own it. Who knows how many cameras you might want? Maybe the game is split-screened. Maybe the game's gui is drawn with a different camera. Maybe the minimap is drawn with a different camera. Renderer shouldn't have a fixed amount of cameras, and most likely shouldn't own the cameras.

Infact, you don't even want the screen to be owned by renderer, because occasionally you want to pass in a off-screen texture for rendering using the same code paths - for example:

draw the world to (screen)
draw the world to (minimapTexture, zoomed out)
draw minimapTexture to (screen's upper-left corner)

I don't want the game class to actually hold a pointer to the renderer class to decrease coupling.

Why not? Some classes do have actual dependencies.
 

Instead, i want to have the sprite and camera class add themselves via constructors or factory methods to the renderer class. Then I can have something like Camera1.makeCurrent() which would make Camera1 the current camera the renderer is using to draw the world.

Why does the Camera know about the renderer? Cameras don't do renderering. The renderer should know about the Camera, though, because it requires the camera to draw things in the correct places.
 

I was hoping to leave that all in the Application class and have the Game class use Sprites or Cameras but not have access to the actual SDLRenderer to decrease coupling.

Ah, so it's the Application class that is the owner of everything. Except the singletons (but why not? they don't need to be singletons).
 

Its a little easier with the input manager since it doesn't need multiple types, theres only ever 1 type of Input Manager. Renderers however can be OpenGL3.3, 4.4, Directx9, mobile stuff, etc. so there are multiple types, each for a different platform or target hardware.

Now hold on, you're never (99.99% of the time) going to want to have different types of renderers running at the same time. You aren't going to have OpenGL and DirectX drawing at the same time. As far as abstracting platforms go, that happens either through a factory (if you must), or more likely, at compile-time with #ifdefs.

The renderer should present the same interface regardless of platform, but the guts of the renderer should change depending on the platform (though, SDL handles all this for you, even on mobile platforms, so you don't really need to reinvent the wheel).

Ultimately, your highest priority is finishing the project and making it fun and polished. A perfectly-coded application that never gets finished is worse than a poorly-coded application that does get finished. But clean code *is* important, so it's good to think about it and work towards it, just not at the expense of dragging on the development time for all eternity.




#5200124 Getting Rid of "char*"

Posted by Servant of the Lord on Yesterday, 02:28 PM

Let's pretend it is an issue. How do you think you would solve it?

 

Most std::string implementations keep small strings on on the stack for you automatically, and store larger strings in dynamically allocated memory. For example, with GCC they carefully chose what is best speed/size optimization tradeoff depending on whether your architecture is 32 bit or 64 bit. They decided that small strings up to ~10 characters work well for 32 bit machines, and small strings up to 22 characters work best with 64 bit machines, and give that optimization to you at virtually no cost. wink.png




#5199780 Any Full (Complete) Multiplayer RPG tutorials?

Posted by Servant of the Lord on 23 December 2014 - 06:41 PM

It's hard to find tutorials that go through creating the entire game you want to create. Usually, programming involves learning the individual pieces, and figuring out how to make the big project from the small components. Kinda like legos - you have your idea in mind, and you have all these blocks, but you have to put the blocks together to build your idea. Unless you are making a small project, like the lego model on the box, or like tetris or asteroids, your idea doesn't come with step-by-step instructions.

This is especially so since any two games (not using the same engine) are likely built in different ways.

Copy+pasting myself from a different thread:

 

I typically find grandiose tutorials that cover "everything" to cover none of them well. When I want to learn a specific feature, I find it better to just google, because google will (most of the time) bring up better results, and provide enough different results from different sources to get better understanding of the subject. (Having three or four different people explain something helps me alot).

 

I also google in the generic, not the specific. I don't google "Loading rooms for text adventure games in C++", I instead google "C++ loading text from files". You want to learn the general method, and apply it yourself to your code project, without falling into the trap of copy+pasting exact solutions. StackOverflow, when it appears in the google results, is one of the links you want to look for for good explanations.

 

If I still have questions, I ask on GameDev.net in a new thread dedicated to just that one question. The resulting explanations (and opportunities to ask questions directly) are the single most helpful thing that helps me grow.

 

The hardest part, for me personally, is figuring out the big picture architecture of my code - how it all fits together. That's something I'm still learning and refining, partially by reading others' views, and partially by experience gained through trial-and-error.




#5199758 Rendering blurred progress lines

Posted by Servant of the Lord on 23 December 2014 - 03:22 PM

Looks like you are right, thanks for clarifying. I'm curious if this simple image horizontal movement will look too static.

 

I think it'd be fine. The fact that its moving will likely distract most users. If it's still not good enough, you can also animate the alpha transparency slightly, and if that still isn't enough, then you can scroll the image and have multiple frames to, say, pulsate the fireball.

 

But really, just scrolling the bars is a significant enough visual cue - I think it'd look plenty fine and polished; but can be enhanced later if needed.




#5199657 Rendering blurred progress lines

Posted by Servant of the Lord on 23 December 2014 - 02:18 AM

Speculation:

Each image is only a single texture with alpha transparency.

 

The bottom two can be done with a single image that you rotate around its center. The bottom-left is rotated smoothly, the bottom right is rotated in larger jumps of degrees so the dots don't actually move. (12 dots = 360/12 = rotated 30 degrees each step).

 

The top two could be as simple as a single image looping around. Imagine you are wanting to display the top line at 60%.

Split the image in two, draw the end 60% of the image first, then draw the remaining 40%.

 

Shifted_draws.png

(pardon sloppy image editing)

 

You're always drawing the complete image, but you're drawing it in two pieces.

Alternatively, you can draw the line, and then draw the "fireball" as a separate image, and just shift it across the line letting it go "offscreen" before a "new" fireball starts again on the left side.

 

The top line is drawn in smooth motion, the second line is drawn in jumps so the dots don't actually move - 13 dots, so (imageSize / 13) = amount shifted each step.




#5199607 What to do after the basics

Posted by Servant of the Lord on 22 December 2014 - 05:09 PM

do you maybe know a source from which I could learn those basic mechanics?

 

I typically find grandiose tutorials that cover "everything" to cover none of them well. When I want to learn a specific feature, I find it better to just google, because google will (most of the time) bring up better results, and provide enough different results from different sources to get better understanding of the subject. (Having three or four different people explain something helps me alot).

 

I also google in the generic, not the specific. I don't google "Loading rooms for text adventure games in C++", I instead google "C++ loading text from files". You want to learn the general method, and apply it yourself to your code project, without falling into the trap of copy+pasting exact solutions. StackOverflow, when it appears in the google results, is one of the links you want to look for for good explanations.

 

If I still have questions, I ask on GameDev.net in a new thread dedicated to just that one question. The resulting explanations (and opportunities to ask questions directly) are the single most helpful thing that helps me grow.




#5199594 Why are abandoned, deserted areas so common in video games?

Posted by Servant of the Lord on 22 December 2014 - 04:26 PM

Speculation:

 

Computers are great at rendering flat surfaces. Man-man structures are flat, so they require less polygons. It's less work for videocards to render a really good looking city than for videocards to render a poor looking jungle.

 

Want a "natural" area that can look good? Make an abandoned man-made (or alien-made) structure or town. Sure, you can toss some ivy and vines, trash, bumpy ground, and such, but predominately, it's a bunch of mostly flat surfaces on top of mostly flat terrain. (By 'flat' I don't mean level - it could be a flat surface sloping downhill)

 

Other good choices: Caves, canyons, deserts, mountains, other locations without a huge amount of plants. wink.png




#5199490 iOS Submisssion: URL/Website required

Posted by Servant of the Lord on 22 December 2014 - 01:06 AM

A Small Orange is fairly cheap for hosting (cheapest plan is $35 / year, and you can host more than one website on it), and the customer support is fantastic. 

You can host your website for even cheaper using Amazon's servers, but it's more complicated to set up.

 

I use Namecheap for domains. 

*shrug* I have no complaint against them, so I'm sticking with them, but there might be better domain-name providers that others are aware of.

A Small Orange also sells domains, but it seemed reasonable to me to keep my domains and hosting separate, incase I ever need to switch hosting or domain providers.




#5199452 Passing information between states?

Posted by Servant of the Lord on 21 December 2014 - 05:17 PM

This is an area I'm still working through myself, so take this post as an inexperienced opinion.

Signals and slots seem to me the best way to pass information between parent-child hierarchies.
My GameStates can have children, and can rearrange those children. In an active state, only the topmost of its children is active with the parent.

I would have a GameState "PlayingGame" that created and owns both LevelMenu and WithinLevel.
 

Say I have a 'menuState' showing available levels and the user clicks 'level1' starting a new state 'gameState'.
How would the gameState I just created know what level to load,


Within 'PlayingGame':
LevelID/Handle/Path = this->LevelMenu.getSelectedLevel();
this->WithinLevel->loadLevel(levelID);

this->WithinLevel.RaiseToTop(); //Make 'WithinLevel' the active topmost child of PlayingGame.
(psuedocode)
 

and also how would it send data back once I returned to the menu to say "hey, he completed level 1, and can now play level 2"?


Within PlayingGame's constructor (right after creating WithinLevel and LevelMenu):
this->WithinLevel.FinishedLevelSignal.connectTo(this->goToNextLevelFunctionCallback);
this->WithinLevel.GameOverSignal.connectTo(this->gameOverFunctionCallback);
(psuedocode)

You can also pass into the constructors of gamestates pointers to the game resources and game data needed, so it can access those details.


I'd be interested to hear how other developers handle it, so I can improve my architecture.


#5199451 SDL problem with passing pointers

Posted by Servant of the Lord on 21 December 2014 - 04:55 PM

Very good, that's mostly correct!

 

There are a few problems and minor additions you should fix to improve it.

 

Class, function, and variable names should not begin with underscores

 

The C++ standard says:

 

Certain sets of names and function signatures are always reserved to the implementation:

Each name that contains a double underscore__ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

 

 

It's easier to remember if you just say, "don't begin any name with an underscore". Compilers, when compiling your code, generate additional variable names using underscores, and that can occasionally, every blue moon, overwrite or conflict with variable names you wrote with underscores.

 

You named your textures memory variables beginning with underscores, which can cause problems. Different people have different coding styles. Some prefix their private member variables with m_  (you can use underscores, just not at the start of a name).

 

Personally, I have public member functions and member variables begin with a capital ( MyFunction(), MyVariable ) and private functions and variables begin with a lowercase. ( myPrivateFunction(), myPrivateVariable ). Other programmers use different styles.

 

C++'s Rule of Three:

 

Imagine you had a texture loaded, and then copied that Texture class.

Texture texture;
texture.Load("blah");
 
Texture texture2 = texture;

Only one SDL_Texture was loaded. But which Texture class will call SDL_FreeSurface() on it? smile.png

The answer is that they will (accidentally) both try to destroy the same texture, freeing invalid memory and resulting in undefined (and bad) behavior that, best case, crashes your program. Worst case, results in random hard-to-find bugs that cause really odd behavior at unpredictable and inconsistent times. Dangling pointers and related issues are the bane of programmers. dry.png

 

For any class that manages memory, you need not only a destructor, but also a copy-constructor and assignment operator. Alternatively, you can explicitly block copying of a class.

class Texture
{
    public:
    Texture(const Texture &) = delete;
    Texture &operator=(const Texture &) = delete;
If you are using a version of C++ that predates C++11 (or have forgotten to enable C++11), instead of = delete, you can move the functions to 'private' access instead. You don't need to even write the functions, just declare them.
class Texture
{
    private:
    Texture(const Texture &); //Copy constructor
    Texture &operator=(const Texture &); //Assignment operator.
 
    public:
    Texture();
    //...etc...
};
 

Now it's the C++ Rule of Five:

 

With C++11, they introduced move-semantics. A copy duplicates the content of a class. A move transfers the content from one class to another, without copying.

 

For any class the manually manages the lifetime of a variable, you'll want to add a move constructor and a move assignment operator.

An easy way to do this is just to swap the variables (for example, swap the null pointer with the good pointer); though you don't always need to swap all of them, and swapping isn't even required as long as you leave the old object in a safe state.

class Texture
{
    public:
    Texture(Texture &&other)
    {
        std::swap(x, other.x);
        std::swap(y, other.y);
        //...etc...
        std::swap(texture, other.texture);
    }
    
    Texture &operator=(Texture &&other)
    {
        std::swap(x, other.x);
        std::swap(y, other.y);
        //...etc...
        std::swap(texture, other.texture);
    }
};

There are faster ways of writing it, but that's for another time. smile.png

 

More information on the Rule of 3 / Rule of 5.

 

In the Load() function, std::string should be passed in by const-reference

 

Here:

bool Texture::Load(std::string Filename, SDL_Renderer* pRenderer)

Should be:

bool Texture::Load(const std::string &Filename, SDL_Renderer* pRenderer)

Because 'filename' is not modified inside the function, the Load() function doesn't need a copy of the string, just a reference to the original string. By making it a const reference, you also guarantee to the caller that you aren't going to modify 'Filename' within the function itself.

 

<personal_opinion>

 

And while we're in this function, 'pRenderer' doesn't need the 'p' in its name. You don't need to write 'pointer' in the name of the variable, you already know it's a pointer from reading the code, and your IDE can instantly tell you its a pointer when you hover your mouse over it.

 

You don't call your strings "std::string stringFilenameThatContainsText", you don't need to name your pointers "pRenderer", "ptrRenderer", or "rendererThatIsAPointer". Just plain "renderer" is fine. wink.png

Some programmers do that. But then again, some programmers do many ridiculous things like prefixing their class names with 'c' ("because it's a class!" rolleyes.gif). Some of it was useful twenty years ago when we had poor tools, but is no longer useful now, and some of it is from genuinely good ideas that got twisted into bad ideas because of misunderstanding.

 

In general, I try to name my variables to explain what they are for usage-wise, not what they are type-wise. "Filename" is what it is used for, and so is a descriptive name. If I need to know the type of Filename, I can ask my IDE by hovering the mouse over it, or by jumping to its definition. But if "Filename" was named "AString" instead, I can't ask my IDE what the intended usage was that the original programmer had in mind.

 

</personal_opinion>

 

The Texture class (probably) shouldn't change its value each time you draw it

 

Imagine you had ten monsters you were wanting to draw, and all of them use the same appearance. They can all share the same Texture. The monster classes themselves will store the positions where the monsters want to be drawn. So why does the Texture class store the (x,y) location of the last place the Texture was drawn? What practical use does that have, if more than one object is sharing references/pointers to the same texture? (same thing for Width and Height)

 

It makes sense for textures to remember their (x,y,width,height) of a subportion of a spritesheet, but that doesn't appear to be occurring here.

 

To think about it another way, every time you draw a Texture class, the class changes part of its state. What for? Drawing a texture should be a const operation (i.e. it shouldn't modify the Texture class).

 

Error messages should give more context

 

In your Load() function, there are many ways for the function to fail. You properly detect this and give an error message. Excellent!

 

Still, bugs and crashes can be annoying. You want to make it as easy as possible to track down problems when they arise.

 

Take for example, this error-check:

SDL_Surface* pTempSurface = IMG_Load(Filename.c_str());
if(pTempSurface == NULL)
{
    std::cout << "pTempSurface IMG_Load failed" << std::endl;
    return false;
}

That's helpful - it says what went wrong (IMG_Load() failed).

But it's even more helpful if you add where it went wrong, why it went wrong, and under what circumstances.

 

Where it went wrong:

It failed in the Texture::Load() function. You know that reading the code, but you don't know that when reading an error logfile or the console output.

 

Why it went wrong:

IMG_GetError() returns an error message giving additional details when IMG_Load() fails. You can output that as part of your error output (put it in quotes and say what function produced the message: [[[ My error output message, and details, and IMG_Load() says: "The texture couldn't be loaded from the file." ]]]

 

Under what circumstances it went wrong: 

Imagine your program crashes, and your reading your error logs. Your program loaded 100 textures just fine, but one of them failed.

If all you see is, "Texture::Load(): The image failed to load.", you don't know which of the 100 textures caused the problem!

 

The Texture::Load() function already has the filepath that it is trying to load - you should definitely output that filepath as part of the error output when something goes wrong.

 

 

It's nice when you preemptively help yourself debug potential future problems, by providing the information necessary to make the bugs less painful when they occur.

Think of how much easier it would be to track down problems if you got this message:
 

Function: Texture::Load()
Problem: Failed to load the texture
Reason: IMG_Load() says, "Couldn't find the file at the location given"
Filepath: ./Resources/Textures/SuperAwesomeGriffonSprite.png
 
 
You can add even more details to the error messages, and wrap the information up in functions to make virtually effortless to add the information to all your output without alot of repetitive typing and remembering.

 

Here's some of the other nice things you can add to your error output:

  • The exact location in code (file, function name, and line number) that outputted the error (Google for C++ __FILE__, __LINE__, and __FUNCTION__ / __PRETTY_FUNCTION__ )
  • The stacktrace - which function called what function called which function that called the function that encountered a bug.
  • What overall and in general your program was working on in the big picture before it ran into problems.
  • Syntax highlighting/formatting to make the output easier to read - some people output their error logs to HTML with CSS. happy.png

 

Some are a bit more work to implement than others, so this might not be a priority for your current project.

 

_________________________________________________

 

Hopefully that helps you somewhat, and explains the reasoning behind why I do things that way. Overall, your code looks very good, so you're already on the right track. smile.png

 

Good luck on your programming adventures!




#5199348 SDL problem with passing pointers

Posted by Servant of the Lord on 20 December 2014 - 08:26 PM

I have managed to make a texture wrapper class and I'm trying to implement a linked list for the generation of the textures/objects for when they are needed.

std::list is a standard library available to you (#include <list>) that is a linked list.
However, std::vector (or, depending on what you are doing, std::unordered_map) is a superior choice here.
 

Do I 'Have' to initialize the textures at the point of initialization or can I call them when they are needed from the folders

No, you don't need to point your pointers at dynamic memory the moment you create them, but you should at least initialize your pointers to null. You should never leave variables uninitialized.
 

Blah *myPointer; //Bad. Points to a random gibberish location in memory. 'Bad Things Happen' if you accidentally try to use it.
Blah *myPointer = nullptr; //Better. If you try to read or write to a null pointer, your program crashes. And that's a *good* thing.

However, in general, it's preferred not to use raw pointers to micro-manage memory lifetimes.

Even though SDL does this, that's because SDL is designed for the 'C' language.

In C++, it's better if your variables manage their own allocations and deallocations, to prevent human error mistakes when writing code.

 

Wrapping the texture in a class is one possible correct thing to do, but you might want to post your implementation (inbeween [ code ] and [ /code ] tags) so we can make sure it is written properly. Dynamic memory can be difficult to get right if you are just starting to learn the language.




#5198985 C++ how to declare something that isn't declared?!?

Posted by Servant of the Lord on 18 December 2014 - 01:32 PM

Totally did not know that you could use 'using' keyword like that. Cool stuff!

 

Relatively new feature (C++11 / 2011), so older books and tutorials don't mention it.

 

Buckeye's method is just as acceptable.




#5198983 Certificate needed on Steam?

Posted by Servant of the Lord on 18 December 2014 - 01:27 PM

Doesn't Steam, as part of their DRM, optionally frob your executable? That would probably undo the code signing anyway.

On the Steamworks 'publishing services' page, they talk about generating unique executables per each user's Steam Account.

 

The best way to find out is to just ask Valve.




#5198885 Some help using vertex buffer with std::vector.

Posted by Servant of the Lord on 17 December 2014 - 10:32 PM

Your type naming is a little weird. Take for example:

VertexPC verts;

Shouldn't that be 'VertexPosColor'?

If 'VertexPosColor' is a vector, having it named in the singular sounds weird to me personally. I would named it VertexColorArray.

 

I'm going to assume 'verts' is supposed to be a vector, instead of a single vertex, so the rest of my post holds to that assumption.

 

sizeof() doesn't get the number of elements in an array or vector. std::vector.size() does that.

sizeof() gets the size, in bytes, of an object.

 

So this:

memcpy(data, &verts, sizeof(VertexPC));

Should be this:

memcpy(data, &verts[0], (sizeof(VertexPC) * verts.size()));

Starting at the address of the first vertex, not at the start of the vector class itself.

 

Unless I'm misreading your code. Which is likely, since I don't use DirectX. ohmy.png

 

Also this:

for (DemUINT x = 0; x < m_numVertices; ++x)
{
    verts = m_posColor[x];
}

Repeatedly assigns the same color to a single variable over and over again.






PARTNERS