Advertisement

What am I not understanding about programming?

Started by September 04, 2017 06:10 AM
36 comments, last by Finalspace 7 years, 3 months ago

Oh, by the way, since you specifically asked for architecture/structure, check this https://hero.handmade.network/episodes

He makes an entire engine + game and show you every line in more than 400 videos... 

 

I personally recommend steering well clear of the Handmade Hero stuff when trying to work out how to write good code.

Advertisement
4 minutes ago, Kylotan said:

I personally recommend steering well clear of the Handmade Hero stuff when trying to work out how to write good code.

I can't comment on that since I saw only 20 videos and also don't have the tools/knowledge to judge it, though I can say I definetly wish more developers would attempt what he is attempting :)

50 minutes ago, MarcusAseth said:

Oh, by the way, since you specifically asked for architecture/structure, check this https://hero.handmade.network/episodes

He makes an entire engine + game and show you every line in more than 400 videos... 

 

Have you looked at that index? How is this going to motivate someone ;) ?

Furthermore, if you have trouble understanding someone else's C++ code (whether it is good or bad code), stay away from someone else's C code. I studied a compiler implementation written in C in some kind of OO fashion (very deep union/struct alternations); the verbose codebase was a real monstrosity.

🧙

2 minutes ago, matt77hias said:

Have you looked at that index? How is this going to motivate someone ;) ?

lol

Still entertaining though, for when you want to just lay down on bed and passively assimilate some knowledge, it's just like listening to a podcast :D

 

6 minutes ago, MarcusAseth said:

just lay down on bed and passively assimilate some knowledge

Not enough time for that :D .

It would have been nice if he can summarize everything in <10min. Currently it will take you more than 500h< to go through all that, passively or not.

🧙

Advertisement
5 hours ago, LuridRequiem said:

I wanted to build a super basic version of PONG. I wrote classes to handle the window and Player Paddle and placed it all in a game loop function that I called in main(). Everything at that point ran fine, but it wasn't what it should've been. Nothing else was completed. In this main loop, I was basically calling objects in full. I know now that I shouldn't have done it like that, but at that point, I didn't know how I was supposed to build this game loop that would keep the game running.

I suspect you're hitting Analysis Paralysis by getting too hung up on doing things the "OO way".

Pong is really no different to any other kind of application:

  1. It gathers input
  2. It processes that input into some state
  3. It presents that state as output

The only notable variation is that for a real-time game those 3 step needs to occur every single frame.
So all we do is wrap them up in a game loop like this:


World world;

while (true) {
	Keys keysPressed = checkInputs();   // input
	update(keysPressed, world);         // process
	render(world);                      // output
}

 

World maintains the state of the game (paddles, players, scores, ball, etc) and its public methods model the interactions that you have available to you when playing. In the case of Pong it might have a method like: movePaddle(amount).

The update() function knows how to convert inputs (keypresses) into actions that modify the world. For example it knows that if you push the right-arrow key then it will invoke: world.movePaddle(1);

The job of the render() function is to translate the state held by World into something visual. If the process of rendering requires  state all of its own (textures, shaders, models, etc) then a simple render function isn't enough. That's fine. Just make it a method in a class:  renderer.render(world);  This class can now hold all that rendering gumpf, available only to the render() method.

 

Of course as you scale this up to larger and larger applications/games you'll find that these pieces become bloated. At which point you'll want to start sub-dividing ("refactoring") them.  For example you can move code out of your World class into Paddle and Ball classes and World just glues them together. Or you might move code out of render() (or Renderer) into renderPaddle, renderBall, etc.

This "refactoring" process helps keep your code organised and maintainable. But it's not where you start. You start simple and you subdivide structure into it only when needed. This is how we all do it!

With lots of experience we developers can sometimes foresee what sort of factoring is appropriate and then shoot straight for that. But in reality it's an unreliable process (because we're only human, we stumble across pitfalls or we learn something new or requirements change).  Ultimately it's a skill that you will never master and you will never stop improving!

 

I sometimes find it helpful to tackle a big problem by looking at what sort of thing I want the end result to be and then figuring out the immediate steps my program needs to do it, then subdividing those and repeating the process - essentially writing the program in the reverse order in which the data is processed, using mock data to pretend that the preceding steps are in. I keep doing this until I have tasks at a level of granularity that I know how to solve. I'll give an example of this using Pong.

First I might think, "I want to display the game state to the player using graphics. In order to do that, I need to open a window and then draw the game world once per frame." The most granular task in that sentence is "open a window", so I'd go and write the code that displays a window. So then I want to draw a game world once per frame; in order to do that, I need to draw the paddles, the ball, and the players' scores.

To draw the paddles and ball, I need to be able to draw rectangles at arbitrary screen positions. That should be granular enough for a task, so I go and I implement rectangle drawing. Now that I know how to draw rectangles, I can make up some paddle and ball positions and write a bit of code that draws the paddles and the ball on the screen every frame.

To draw the players' scores, I need some way to draw text. Since I don't know enough about fonts to do this myself, if I want to draw text I either need to find a font-rendering framework of some kind or write one. I'll try the first one since that's easier. Suppose for the sake of argument that I'm working with the SFML library; turns out it already has font rendering built in, so I can use that. Now I discover that SFML's font rendering requires me to load in an external TrueType font. I need a .ttf file and some code to load it into a font object, so I go and grab the former and write the latter. Now that I can draw text, I can draw the player's scores - I make up some fake score data and write the code that does that.

This gets the game rendering, but it doesn't actually do anything yet. It's just a static image that looks like a game. I need to actually implement gameplay. Pong's gameplay is defined as follows:

  • the ball moves at a constant speed in a given direction
  • players move their paddles up and down
  • if the ball reaches an edge of the screen with a paddle, then the player on the other side of the screen receives a point and the ball respawns
  • if the ball reaches an edge of the screen without a paddle, then its motion along the axis perpendicular to that edge is reversed (ie. it "bounces")
  • if the ball reaches the edge of a paddle, it also "bounces"

The first statement is simple enough to implement as a task. Players moving their paddles up and down requires subdividing into "moving a paddle" and "checking input devices to see if we should move." The ball-screen collision behaviour requires a way to see if the ball is touching the edge of the screen, and if so which side. Ball-paddle collision requires a rectangle intersection algorithm, then using that rectangle intersection algorithm to check for hits.

And so on.

1 hour ago, dmatter said:

I suspect you're hitting Analysis Paralysis by getting too hung up on doing things the "OO way".

Pong is really no different to any other kind of application:

  1. It gathers input
  2. It processes that input into some state
  3. It presents that state as output

The only notable variation is that for a real-time game those 3 step needs to occur every single frame.
So all we do is wrap them up in a game loop like this:



World world;

while (true) {
	Keys keysPressed = checkInputs();   // input
	update(keysPressed, world);         // process
	render(world);                      // output
}

 

World maintains the state of the game (paddles, players, scores, ball, etc) and its public methods model the interactions that you have available to you when playing. In the case of Pong it might have a method like: movePaddle(amount).

The update() function knows how to convert inputs (keypresses) into actions that modify the world. For example it knows that if you push the right-arrow key then it will invoke: world.movePaddle(1);

The job of the render() function is to translate the state held by World into something visual. If the process of rendering requires  state all of its own (textures, shaders, models, etc) then a simple render function isn't enough. That's fine. Just make it a method in a class:  renderer.render(world);  This class can now hold all that rendering gumpf, available only to the render() method.

 

Of course as you scale this up to larger and larger applications/games you'll find that these pieces become bloated. At which point you'll want to start sub-dividing ("refactoring") them.  For example you can move code out of your World class into Paddle and Ball classes and World just glues them together. Or you might move code out of render() (or Renderer) into renderPaddle, renderBall, etc.

This "refactoring" process helps keep your code organised and maintainable. But it's not where you start. You start simple and you subdivide structure into it only when needed. This is how we all do it!

With lots of experience we developers can sometimes foresee what sort of factoring is appropriate and then shoot straight for that. But in reality it's an unreliable process (because we're only human, we stumble across pitfalls or we learn something new or requirements change).  Ultimately it's a skill that you will never master and you will never stop improving!

 

You can try to program Pong in Elm (Functional Reactive programming). Very fast and a joy to debug due to the steps.

🧙

6 hours ago, dmatter said:

I suspect you're hitting Analysis Paralysis by getting too hung up on doing things the "OO way".

Pong is really no different to any other kind of application:

  1. It gathers input
  2. It processes that input into some state
  3. It presents that state as output

The only notable variation is that for a real-time game those 3 step needs to occur every single frame.
So all we do is wrap them up in a game loop like this:



World world;

while (true) {
	Keys keysPressed = checkInputs();   // input
	update(keysPressed, world);         // process
	render(world);                      // output
}

 

World maintains the state of the game (paddles, players, scores, ball, etc) and its public methods model the interactions that you have available to you when playing. In the case of Pong it might have a method like: movePaddle(amount).

The update() function knows how to convert inputs (keypresses) into actions that modify the world. For example it knows that if you push the right-arrow key then it will invoke: world.movePaddle(1);

The job of the render() function is to translate the state held by World into something visual. If the process of rendering requires  state all of its own (textures, shaders, models, etc) then a simple render function isn't enough. That's fine. Just make it a method in a class:  renderer.render(world);  This class can now hold all that rendering gumpf, available only to the render() method.

 

Of course as you scale this up to larger and larger applications/games you'll find that these pieces become bloated. At which point you'll want to start sub-dividing ("refactoring") them.  For example you can move code out of your World class into Paddle and Ball classes and World just glues them together. Or you might move code out of render() (or Renderer) into renderPaddle, renderBall, etc.

This "refactoring" process helps keep your code organised and maintainable. But it's not where you start. You start simple and you subdivide structure into it only when needed. This is how we all do it!

With lots of experience we developers can sometimes foresee what sort of factoring is appropriate and then shoot straight for that. But in reality it's an unreliable process (because we're only human, we stumble across pitfalls or we learn something new or requirements change).  Ultimately it's a skill that you will never master and you will never stop improving!

 

This is how I was trying to build my game loop, but I didn't understand how to take everything I was going to write, and put it in the appropriate functions. 

I also get caught up on how to get classes to work inside other objects. For example, If I have a player class and a weapon class, I wouldn't know how to set up the weapon instance inside player.  I don't know if this makes sense at all, because it's difficult to explain what I mean. I think another issue I have is separating abstraction and implementation from one another. Just because an item or weapon has all the variable attributes of those things doesn't make that thing what it's emulating in the real world. It's still code representing a real world object, and I get hung up on how to replicate that object in code. 

I feel like I'm rambling at this point, and not doing any good at explaining what I'm trying to accomplish. If you do, by all means, respond as thoroughly as possible if you'd be so kind to do so. 

This topic is closed to new replies.

Advertisement