Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your help!

We need 7 developers from Canada and 18 more from Australia to help us complete a research survey.

Support our site by taking a quick sponsored survey and win a chance at a $50 Amazon gift card. Click here to get started!


Josh Petrie

Member Since 11 Jun 2003
Offline Last Active Private

#5249975 Is my object-structure bad? [Related to Text RPG]

Posted by Josh Petrie on Yesterday, 01:03 PM

In the broad sense, your architecture sounds over-engineered (over-engineering is not neccessary for a "larger, multi-player game"). You haven't really provided enough specifics for me to comment in turn, so I'll offer some similarly broad suggestions:

 

  • in general, it is better for references to be one-way. That is, a character should know what room it is in, or a room should know about characters in it, but not both unless absolutely necessary. Having both complicates things, both in terms of potential API surface area (both interfaces can answer very similar questions of the current game state) and lifetime management (moving a character involves updating state in two places, so does releasing a character). Duplicate state also leads to fun bugs later in development. If you can do without, do so.
  • fight the urge to literally objectify every object in your OO design. Fight the urge to give everything verbs that create as-close-to-1:1 analogues with the real world as possible. Yes, in the real world a character (person) can move itself, but it sounds like in your architecture, the character just passes a message along to something else to actually move it so the existence of the move verb on the character class is questionable.
  • when you have trouble thinking about where to put some functionality, consider thinking about how you're going to use it. What state that does that functionality need to do its job, and where do you current have that state? What is involved from getting that state from where it is to where you're thinking about calling this new function, and can you put that function elsewhere -- closer to the state it will tend to use?
  • there is no standard formula for constraining state and knowledge of the world across interface boundaries. There are guidelines, though. Prefer writing interfaces that are easy to use properly and efficiently and hard to use improperly, for example. Prefer interfaces that allow the implementation to be as uncomplicated and direct as possible.
  • Forget relational databases exist for now. SQL and such is fine for persistent data that you'll need to query in a complex fashion slowly. It is absolutely not a good idea to use one in real-time; stick to data structures in local process memory optimized for the actions you're going to take on them.



#5249365 First game engine

Posted by Josh Petrie on 28 August 2015 - 09:38 AM

Where do i start?

 

 

First, you give up the idea that you need to -- or should -- make a "game engine." It's a waste of your time. You don't need an engine to make a game, and given your documented level of experience you aren't capable of making one that measures up to your own standards yet anyway, because you know almost nothing about what goes into game development or game engines.

 

You need to learn that. Which means you just need to worry about making your game.

 

What design do i need to do in paper? Diagrams and such.

 

 

You don't need to do anything on paper, although you can if it helps you refine your ideas.

 

 

What does a game engine need to work? What are the main classes i will need?

 

 

That depends on what kind of game engine it is, and what its goals are. It's also not something you need to think about right now.

 

After I have built the basics to run the game how do I improve from there?

 

 

As you're building something, you'll come across problems you have to solve in ways that you're not super thrilled out, that you think could be solved better but which you're currently prevented from solving better by some other issue or architectural decision you've already made. Some of these you'll solve immediately. Others you'll put off. When you're "done," you can maybe consider going back to revisit the issues you've put off.

 

 

The "basics" of C++ is probably not enough to jump immediately into creating your own 2D game with OpenGL. Generally I'd recommend starting with text-mode, console-based games first, to flesh out your ability with the language and to practice some common game development idioms and techniques. Can you write a text-mode guess-the-number game? What about blackjack? Or hangman? What about a text adventure game like Zork?

 

If you feel comfortable tackling tasks like that you should try moving on to windowing and graphics using GLFW or the like, perhaps recreating Pong or Tetris. 

 

As you do this you'll have multiple projects under your belt, wherein you learned (hopefully) at least one new skill. As you complete each project you can look back at your code at the things you feel you'd reuse for your next project and you carry that code forward. Eventually, do this enough times, and that's your own basis for your own game engine.

 

You also should disabuse yourself of the goal to "do everything yourself" sooner rather than later. Within practical limits you are always going to be using libraries and software that other people have written for you, and you can still understand how those libraries work without having to build them yourself anyway. In fact, you're rather likely to create a disaster if you just trying to build everything yourself from scratch, because you're assuming you're going to be able invent all the same technologies that we as a collective industry have spent years building and refining. And the chance of that is rather small.

 

Instead, try to look at the decision like this: if you're talking about a component of your project that is unique and critical to the business success of your project, that's usually a good case for building a thing yourself. Things like gameplay mechanisms you'd like to show off, or maybe an incredibly novel method of non-photorealistic rendering, or whatnot. Things that do not constitute unique selling factors of your project you should consider "buying" (using existing implementations of, even if free). This frees up your time to focus on the unique aspects of your project that will make it shine, and decreases the risk that, for example, your crash reporting or analytics code will fail spectacularly because you made a rookie mistake instead of using a battle-tested off-the-shelf solution.

 

The exception would be, perhaps, things you want to be able to do unique and interesting work in but can't yet. For example, if your goal is to be an amazing graphics programmer who builds all kinds of awesome new rendering techniques or whatever, then pretty soon after you learn how the basic graphics pipeline works (by using an existing rendering API), you'll want to start tinkering on your own to develop your skills and knowledge. But if you're not interesting in pushing graphical boundaries, there's not as compelling a reason to be writing your own low-level D3D12 code to move a few hundred sprites around (for example).




#5247219 Code Review

Posted by Josh Petrie on 17 August 2015 - 02:17 PM

Starting in BinPacker.h.

  • Identifiers beginning with an underscore followed by a capital letter are reserved in all scopes (i.e., don't use _FOO_..." header guards).
  • BinRect inheriting Rect seems is an abuse of inheritance as code-reuse; why not just contain a rectangle instead (same with BinNode, later).
  • What is 'rotated," why is it a uint8_t that you XOR 1 into and check for > 0? Is this just a "clever" boolean? If so, use a boolean, if not then this is precisely the kind of weirdness a comment should explain somewhere.
  • You don't need to check for null before deleting a pointer; deleting a null pointer is safe and defined.
  • Unclear why CompareBinRects needs to be a template since you demand they're both of the same type anyway.
  • Similarly, I'm not sure why BinPacker needs a template argument. I'm starting to get real worried about the subclasses of BinRect I'm going to find, as that virtual CanPack() on it suggests bad things.
  • Why does BinPacker store pointers to rectangles, which you delete in the constructor? In Add you simply copy them; this looks like sloppy ownership management that can lead to double-delete bugs and other pointer tomfoolery. Unclear that pointers are necessary here at all, especially since you already have compile-time polymorphism via the template parameter *and* not much of BinRect is actually virtual.
  • "Force" is a verb. "ForceSquare" sounds like it might actually change the packing to demand everything is square, but it doesn't, it just sets a state that is presumably read later. This is not the most clear name.
  • If indices can't be negative (looking at Remove), why are they even signed values?
  • If an index is out of range, that's an error. Treat it like one. By quietly forcing the index to be in range instead, you are potentially hiding bugs in calling code that is not dealing with the index range properly, which means in the face of such a bug you or your team will spend longer trying to track it down. Assert or throw an exception or return a failure code.
  • Don't print to stdout in utility code. Throw an exception or return an error code.
  • If a null rectangle pointer is invalid, prevent a null rectangle pointer from being added to the list in Add (or better yet, don't take pointers here at all). Checking during Commit is wasteful and lets bad data or bugs manifest further from their origin.
  • CompareBinRects is used internally; if it has no external utility, don't expose it as part of your public interface.
  • That root BinNode is allocated, used to call a method, and deleted. It doesn't need to be on the heap at all.
  • GetNumPackedRects is too long to write on a single line. And it looks like it always returns 0 in a very complicated fashion.

 

Moving to BinPacker.cpp:

  • Mainly more of the same critique, especially concerning writing to stdout for "errors." 

 

Matrix.h

  • Consider different names for the Ortho overrides, as they take slightly different parameters and it's not going to be exceedingly obvious which is which at any given call site.
  • The matrix class itself provides no hint as to its storage conventions, et cetera (column major, row major). It offers almost nothign over a bare array of 16 floats.

SpritePacker.h

  • Ah, here we go, a BinRect subclass. So this looks very much like conflating responsibilities and violating SRP all over the place. BinRect has a virtual CanPack just so SpriteBinRect can check a texture? Why does a texture matter? A rectangle packer packs rectangles. That some of those rectangles may be associated with textures is irrelevant and unneccessarily couples otherwise generic code to that concept.
  • The result of texture != 0 is itself a boolean; there is no need for the subsequent use of the ternary operator to simply select true or false.
  • Somewhat excessive passing of std::string by value.
  • SpritePacker as a subclass of BinPacker has the same problems as above (for SpriteBinRect).

 

SpritePacket.cpp

  • INPLACESWAP is a "clever" trick and not a good idea (especially when trying to swap the same things). Also, why the sudden capitals?
  • Consider moving the definition of the vertex/pixel shader code to some static constant area.
  • I'm going to skip the rest of this file as it seems to mostly be graphics stuff.

 

Types.h

  • The assignment operator should usually be T& operator=(const T& other); yours (in your color structures) copy excessively.

 

I skipped anything that looked like Qt code, because meh.

 

Most of the above is not too bad, the biggest problems I would say are the way you use run- and compile-time polymorphism, the way you deal with ownership, and the apparent consideration you put in to the shape and surface area of your APIs. Those three things, especially together, do suggest a certain amount of inexperience. I still think the nature of the demo was probably more problematic for your getting the job than the specifics of the code. How much the specifics of the code matters is really up to the individuals reading the code; some people will be more picky than I am (even I would be more picky in an actual interview scenario, versus scanning this on my lunch break), but some would be less and only look at the algorithmic details. 

 

That said, I hope you'll find my comments informative.




#5247198 Code Review

Posted by Josh Petrie on 17 August 2015 - 01:31 PM

I'd venture to guess that your lack of experience (two years) contributed fairly significantly to your being considered "too junior," but the demo you submitted probably didn't help. Not necessarily because of the code itself (which I have not even looked at yet), but simply because of what it is: texture packing is not that advanced a topic unless you're actually demonstrating some new, novel mechanism of solving the bin-packing problem efficiently (which would still probably be mostly of note to somebody in academia). It's also not hugely relevant to low-level rendering.

 

I'll take a look at the code later on and see if I can give you some feedback.




#5247145 Game Engine

Posted by Josh Petrie on 17 August 2015 - 11:41 AM

First define what you mean by "engine?"

 

At the most generic level, a game engine is just a bunch of code and/or tools that you use to build or run a program you call a "game." So what kind of game do you want to make, and what kinds of supporting code will it need? How much of that supporting infrastructure is uniquely critical to the kind of game you are building (which means you should it yourself)? How much of that supporting infrastructure is not uniquely critical (such as rendering or physics), which means you should just integrate existing middleware?

 

Note that by "uniquely critical" I mean "you want something different that existing middleware cannot trivially provide."

 

There's no single true path forward here, which is why in general if you have to ask "how do I build a game engine?" you probably shouldn't, and should instead simply focus on building concrete games with defined goals, and refactor your engine out of the reusable components of those games over time.




#5246491 default install folder for windows game

Posted by Josh Petrie on 14 August 2015 - 10:20 AM

ok, how does one handle multiple installs vs using the prescribed directories? if the exe is going in programFiles\caveman3 by default, and other data is going in user\<current>\whatever (i haven't figured out which types of data should go where yet for mod-friendly design AND using the prescribed directories).  and then you do a second install to programFiles\caveman3_2 (for example) - you'd need to differentiate the other data files for the two installs somehow - place them in separate folders and associate the folders with their particular installs. 

 

 

 

Why do you have two different installations of the .exe? Are they the same semantic version? If not, simply use the version number to create a subdirectory in %APPDATA%\YourCompany\YourGame\YourVersion\...

 

If they are the same version, well, that's a bit weird, but if you want to support that use, say, a hash of the installation directory of the .exe as a uniqueifying identifier for the %APPDATA% subdirectory.




#5246482 I want to make a simple multiplayer game

Posted by Josh Petrie on 14 August 2015 - 09:45 AM

So you're saying that when I play a match of Halo that all the player's positions are simulated?  I'm sorry but I don't believe that.

 

 
A game is nothing but a simulation, so yes, every player position is simulated.
 
It sounds like your incredulity is actually about local extrapolation of player position on the clients in the absence of authoritative data from the server, though. But this is also a very true thing. Just about every multiplayer game involving real-time interaction (including Halo) will do this, because it provides a significantly improved sense of responsiveness than actually waiting for responses from the authoritative server.



#5246474 A request for advice

Posted by Josh Petrie on 14 August 2015 - 09:23 AM

Sorry about the vagueness, 2 excuses for that:

1.because i am asking 3 seperate questions which all add up to asking advice.

2.A vague titel might get someone intrested enough to view and respond.

 

 

Don't worry about it. Your theory about a vague title getting somebody interested is probably not accurate, but there's nothing really wrong with the thread title or content and the user who chastised you had no business doing so (I've removed the post).




#5246128 Basic Programming Knowledge Need Some Advice

Posted by Josh Petrie on 12 August 2015 - 08:58 PM

Also, nobody commented on the fact that OP used "using namespace std" at the start of his translation unit? This is widely considered bad practice.

 

 

Definitely worth mentioning, although it's made less egregious an offense by being scoped to a given source file instead of a header, where it becomes a true pollutant.




#5246127 Basic Programming Knowledge Need Some Advice

Posted by Josh Petrie on 12 August 2015 - 08:56 PM

Header Guards and Pragma's can reduce the majority of your issues

 

 

Header guards do not prevent recompilation of TUs including a header that changes.

 

Your accessors and overloads won't be overly complicated that it will effect your performance by much. 

These are functions that are typically expected to be inlined anyways so it won't matter much.

 

 

 

Very true, but not related to my point, which had nothing to do with runtime performance.

 

Accessing a pointer from another class... for instance will HORRIFICALLY BLOAT your code. But accessing a local data type is really only two or three instructions.

 

 

This depends far more on the context of the access than accessing a "pointer from another class" versus a "local data type" (by which I presume you mean a field of the type of which a given function is a member, as opposed to a local structure definition, which itself is purely a language construct). Both are cheap in some cases, more expensive in others; fundamentally they're addressing a fixed offset from a given location (the "pointer from another class" versus the "this" pointer). Neither case is likely to "bloat" the generated assembly significantly more than the other, and neither case is affected by the placement of the code in a header versus a source file, because the compiler only sees the single TU. It's all the same to it. 

 

Even after I provided credited information, legitimate advice and criticism.  So consider this my formal resignation from this thread.

 

 
Some of your information is incorrect or inaccurate, unfortunately, and I have a very low tolerance for incorrect information in the For Beginners forum. Especially when it is accompanied by the hostile attitude you're presenting with this "resigning from the thread" business. It suggests you care more about the prestige you expected your commentary to offer than actually helping the beginning in question, and that's not an attitude that is welcome in FB.



#5246035 Basic Programming Knowledge Need Some Advice

Posted by Josh Petrie on 12 August 2015 - 12:23 PM

Reason being is easier to edit. And you know exactly what data you are accessing and how.

Oh and FWI if you are going to tell me its ok to prototype and define in the same file, I am sure you can find a tolerance for the same with header files

 

 

The counterargument to that, though, is that code in headers tends to cause more widespread recompilation because generally a header file exists to expose the declarations of types to other TUs, which must be recompiled if the header changes. They're not wholly equivalent.

 

Certainly if you have a small enough project that C++ recompilation isn't a massive performance drain, or if your header exists only for stylistic consistency and is only ever included by on TU, or if you really need certain functions inlined because your compiler can't do whole-program optimization or the like, it's a reasonable option. But it's costs should not be dismissed idly.




#5246014 Unresolved External Symbol

Posted by Josh Petrie on 12 August 2015 - 10:37 AM

Well, all three assemblies

 

 

"Assembly" is a managed code concept; you're writing native code.

 

I can call the Initialize function from within Game.cpp (in EngineBase.dll) without problem, but not from Metastorm.cpp (in Metastorm.exe)

 

 
But do you link the import library (the .lib corresponding to the .dll) in the project settings for the .exe?



#5246006 Why should I ever program a game again?

Posted by Josh Petrie on 12 August 2015 - 10:11 AM

You guys are clearly right. Programming will not die out. I guess I am simply a little disappointed about the fact that a game can be done with almost no coding.

 

 

 

Why should someone else's ability to create something awesome with skills different than yours impact your ability to create something awesome with your own skills? Why should it affect the happiness you derive from doing so?

 

It shouldn't. That way is the path to elitism. Be wary of it.

 

Now I had to realize that my programming knowledge is less important than, let's say a game designer's or a artists (2D/3D) knowledge.

 

 

Your ability to program was never more important than a designer's ability to design, or an artists ability to model. They are all equally valid and equally important in game development -- with some variations on individual projects depending on that projects needs, but allowing yourself to fall into the mindset that your abilities as a programmer are the "critical ones" to making a game is dangerous. It takes a village.

 

Programming will not "die out" any more than any other discipline will; the advent of Unity and Unreal and all these wonderful tools has lowered the barrier to entry to making games, which is wonderful because it exposes our entire industry to the creative work of individuals who might otherwise not have been able to leverage their creativity within our industry at all (and it allows those of us who otherwise could do to so quicker and more expediently when it is appropriate). Since we all build on eachother's work, we're all influenced and "steal from" the things we respect and admire, this is only good for us in the long run.

 

What Unity and Unreal have not done is touch the upper limit of specialized work that's possible in the industry. If you want to be worried about your future career as a developer, that's what you want to watch out for: something that can make the upper limits of quality and experience more attainable than they are now. There's really nothing out there currently or on the horizon that can do that better than what currently have: designers, artists, and programmers doing specialized work for a specialized, focused idea.




#5245767 Building a game from scratch

Posted by Josh Petrie on 11 August 2015 - 10:32 AM

Your goals and your stated level of experience don't match up. It's fine to have a longer-term goal of building an isometric action game (an "MMO" is practically-speaking unlikely, since you'll almost never have the popularity to actually achieve "massive" concurrency, even if you develop the technical acumen to build the proper infrastructure for it).

 

It's rather unlikely you'll be able to start by building this simple, text-based MUD, and then retroactively graft the rest of the stuff you need onto it as you increase your knowledge. Doing so even in theory requires an extremely clean, extremely high-quality separation of concerns between the appropriate subsystems of the game and you're unlikely to be able to produce that quality if you self-identify as a "C++ newb."

 

Instead, you should focus on making a game you believe you can make now within your skills budget, and then making successive games, increasing in complexity or adding some new aspect you've learned about. You can re-use common portions of your prior games as you build more, but don't try to make one game over this long stretch of time. It's a recipe for frustration and disaster.

 

Knowing that I'll eventually need graphics, is it ok to build a rudimentary MUD and work from that? Or is there a completely different mindset I should be taking? That is, will building a MUD first hinder me more than help me?

 

 

It won't hinder you; it's a good idea as it's text-based and lets you focus on other aspects of game development, making sure you have a solid grasp of those fundamentals before moving on. In fact I'd even suggest starting with something simpler that had *no* multiplayer component, especially if you haven't built such a thing before. Building even simple guess-the-number games, or Blackjack-style games, or simple old-school text adventures can teach you a lot about game development processes and a lot about your chosen language even before you add the complexity of multiplayer or graphics.

 

I don't think you should expect that you'll be able to bolt-on graphics after the fact. 

 

There are a *ton* of aspects to game development (art, itemization, the logic behind every object, etc.). Is there **a)** a canonical breakdown of these things—like the scientific method of game-design? **b)** a most important one I should be working on first?

 

 

There is no "canonical method" of anything involving game design, really. You should consequently focus on the aspects of design that are most relevant to the core gameplay loop of the project you're working on (this is another reason why it's better to start out with smaller, focused projects) or the ones that interest you the most and will help hold your attention on the project when the difficult and boring aspects of the process rear their head.

 

While I'm open to *not* "reinventing the wheel," my being such a nublet, and the fact that I've never seen a game with the mechanics I'd like to implement, makes me hesitant to use already-existing stuff. I'd like to build what I can, then, when I'm well-versed enough, look into using something else (or improving my own!) Is this ok, or are there some things such that there's *no* reason to code myself? (I'm not looking to pump out a quick game and make cash.)

 

 

 

You should build the things that are critical to your game's success, and "buy" (i.e., don't build) the things that are not. Similar with your investment in your education: if you're not interesting in being a low-level graphics programmer, don't learn OpenGL or Direct3D and write your own graphics rendering framework "just because." Find an existing one and use that. 

 

I'm under the impression that "building a game from scratch using C++" means I'll be coding *everything* in C++. Is this viable—or is it more like saying "I'm going to use binary to build a program?"

 

"Scratch" is a dangerous word that often doesn't end up meaning what people think it means in the context they're using it. You're always going to be relying on libraries and technology written by others, practically speaking, because that's what the language and the standard library itself is. That said, it's quite reasonable to build a game using C++ as your only programming language.

 

 

 

 




#5244727 Clone functions

Posted by Josh Petrie on 05 August 2015 - 03:25 PM

It's more like: a factory is a thing that creates other things based on some input key.

 

The pattern itself is not defined by "having a for loop which finds the ID or name and calling a clone function." That's just an implementation detail, and there are several other possible ways to implement a factory, both in terms of how the key associated with the result (for loops are not ideal, faster traversal would be better), and in terms of how to actual materialize the resulting object. And other things.

 

As far as materializing the object, two of the most common options are simply *creating new instances* or *cloning an existing, prototype instance*. The latter case, which is similar to what you've just described, would involve using a "prototype" pattern within the implementation of a factory pattern as well. In the case of the former example, however, it would be (as others have noticed) extremely poor style to call a method "Clone" if it simply returned a fresh, new object.

 

Remember that patterns are guidelines for discussion of concepts, they are not concrete implementation examples.






PARTNERS