Game Programming Mode-architecture, performance and gameplay
This series of blogs is:Game programming Patterns Chinese translation version.
Translated by GitHub address: Cyh24. If you are interested, you can contact bloggers to co-translate and create (WU) Fu (DAO) others.
Although the blog is very moisture, but also a blogger's elbow grease,
If you want to reprint, please attach this article link , not very grateful!
This series of blog "game Programming Mode"-Directory , you can click to enter.
Architecture, performance and gameplay
============================
Before we dive into a bunch of design patterns, I want to tell you what I personally understand about software architecture. This will help you to have a better understanding of the subsequent articles. Or, when you argue with someone about a software architecture or design pattern that is good or bad, it can give you some arguments.
What is software architecture
For this book, you can't find the linear algebra behind the three-dimensional graphics, or the calculus behind the game physics engine, even if you toss it over and over again, and it doesn't show you how to use the search tree in your AI algorithm, or how to simulate a mix of noises in a room.
Instead, the book shows you how to organize the code, rather than simply writing the code for each function. Of course, each program has a certain form of organization, even if you put all the code into the main () function, this is a form of organization. So, the interesting thing is, how do you design a good organizational structure? Or, how do you tell if an architecture is good or bad?
Personally, I've been thinking about this for at least 5 years. Of course, I have an instinct for good design as well as you, but at the same time, we are stuck in a bad code base. So I want you to be free of it. Of course, very few people have the opposite experience, and they have the opportunity to work with code that has good design. So what's the difference between a good design and a bad design?
What is a good software architecture
For me, a good design is that, when I make some changes, I don't need to change the code of the place I'm looking for, as if the entire program has been waiting for my changes. When I need to implement a task, I only need to invoke a few functions, it can be perfectly implemented without the drastic writing of many mend code.
It sounds perfect, but in fact it's not very operational. "As long as you write your own code, the resulting changes will not affect other places."
Let us explain a little. The key point of architecture is change. There are always people who need to change the code base. If you don't touch the code (perhaps because the code is perfect, complete, or so bad that nobody wants to touch it), then the design is lagging behind. The standard for evaluating a design is how it is coping with change. If it doesn't change, it's like a runner never leaves the starting line.
How do you modify your code?
When you want to change the code, such as adding a new feature, fixing a bug, or other reason, before you do, you need to know what the existing code is about. This is not to say that you have to thoroughly understand the whole program, but you need to keep the code that is relevant to your changes in mind.
We all want to be able to quickie in this step, to stall the past, but in fact, this step is the most time-consuming process in software development. However, once you've done this and you've got the code in your chest, the solution is in fact ready to go. You can't say that, but, overall, you know your problem and know more about the rest of the code, and it's easier to write your code.
When you keep tapping on the keyboard, writing code, knowing that the screen appears to be running successfully, is your task over? Of course not! Before you write a test program and prepare to submit the written code to the test, you have some cleanup work to do.
Wait, did I just mention the test ? All right, yes. While it's hard to write unit tests for some game code, there's still a lot of code in the codebase that can be tested completely.
Although not necessary, I recommend that you consider using automated tests as a way to test if you can. After all, you still have a lot of meaningful things to do over and over again.
It's possible that you've added a lot of code to your game, but you certainly don't want people to be able to run it because of your changes. Unless your changes are small, the one thing you usually need to do after you write your code is to reorganize it. If you do a good job with this step, then the next person is going to change the code, and he can't even feel that you've changed the code.
Simply put, the procedure for this procedure is as follows:
decouplingWhat can I do for you?
You can find a lot of decoupling definitions, but I think it's understandable: if two pieces of code are coupled, it means that you have to understand the other piece of code. However, if you do a decoupled operation, you can make the two pieces of code more independent. One of the great benefits of doing this is that the code associated with your program is now only one paragraph. You just need to understand the call to this code without having to go through another paragraph.
For me, the key goal of the software architecture is to make it possible for you to understand the fewest things you need to know when writing code to implement functionality.
Another understanding of decoupling is that when you want to change a piece of code, you don't need to modify another piece of code. There is no doubt that we will always modify something, so the smaller our code coupling, the less time we develop to change the code.
What cost does decoupling bring?
All things are decoupled, each change is linked to only one or two places, so you develop a man like the Wind . That sounds right, doesn't it?
That's why people are passionate about abstraction, modularity, design patterns, and software architectures. A code base with a good organizational structure can really make people work more enjoyable and efficient.
But, like everything else in life, this is not something that can be obtained casually. The production of a good architecture requires unremitting efforts and adherence to principles. Every time you change the code or implement a feature, you must work hard to integrate the code elegantly into your program. Throughout the development process, you need to be very careful about organizing these (and possibly thousands of) code that changes due to minor changes.
You need to consider the parts of the program that need to be decoupled and introduce abstract methods in these places. In the same way, you have to think about possible changes in the future and introduce scalable design.
A lot of people are very interested in this. They will assume that future developers (or themselves) will find the code base very open, powerful, and extensible when they use it. They imagined having a game engine to manage everything.
But here is actually a tradeoff of interests. Because, if each time you add an abstraction layer or support an extensible function, you consider the future flexibility, then you greatly increase the program development, debugging, maintenance time.
If you have a good guess of what your future needs are, you'll get a great harvest. But in general, predicting the future is a difficult thing to do, and when Modularity doesn't help, it can be a bit of a disadvantage, because the amount of code you need to deal with is really getting bigger anyway.
When people on your team start to be passionate about decoupling, you'll find that the code base architecture is out of control. You'll see all kinds of interfaces and abstractions everywhere. There are plug-in systems everywhere, abstract base classes, virtual methods, and a variety of extensibility points.
When you need some code that really helps you do something, you need to work hard to find it. When you need to make some changes, it is true that the code base provides a lot of interfaces for you to use, but to find them, you can only wish you luck. In theory, decoupling exists so that you need to know less code when you need to change it. However, so many layers of abstraction itself have brought you a burden.
In some cases, it is this code base that has led many people to oppose the use of software architecture and design patterns. You can easily implement these decoupling in your code, but don't forget that you are developing a game. Many developers have spent a lot of time developing a game engine because of their scalability, forgetting what the engine is for.
Performance and Speed
A common critique of software architecture and abstraction, especially game development, is that it makes your game performance less. Many design patterns make your code more flexible by means of virtual scheduling, interfaces, pointers, messages, and so on, but at the same time, these mechanisms consume some runtime.
A lot of software architecture is designed to make your program more flexible, so that you need to modify the effort to minimize. You use interfaces so that you can implement the corresponding methods of this interface in any class, not just for today's particular class. You use the Observer pattern and messaging mechanism to make the two modules in the game communicate with each other, and you can communicate with three or four modules in a very convenient way in the future.
However, performance is based on assumptions. You can do optimization practices with specific limitations. Can we assume that we don't have more than 256 enemies? Well, if you can, we can define the ID as a byte type. Can we be sure that only a specific type of method will be called here? Well, if you can, then we can use static scheduling or inline. Can we be sure that all entities will be of the same class? Well, if you can, then we'll use a continuous array to define them.
So, this is not to say that flexibility is not good. It allows us to modify our code more quickly, and development speed is a very important thing. No one, even will Wright(the father of virtual life), can design a very ideal game on paper. Game development must always be iterative and experienced.
The faster you can develop it, the more you will actually experience the game and optimize it. Even if you have come up with a very good set of mechanisms, you also need time to constantly tune. Because, a little uncoordinated in the game will destroy the whole game.
So, there is not a simple yes or no answer. You make your program more flexible, so you can create prototypes faster, but with a performance penalty, and if you try to improve the performance of your game, you're bound to lose the flexibility of your code.
My experience is that it's easier to make a fun game faster than to make a good game fun. One way to compromise is to keep your program flexible until your design is complete, and then discard some abstractions to improve your performance.
Bad code is good, too.
This book is all about how to make your code more maintainable, how to clean up your code, so my point is very clear, is to let you write code as far as possible in the direction of the good. Even so, even poorly designed code is valuable.
Writing a code base for a good architecture requires you to worry about designing, and it takes more time to maintain the good one design code base. Just like a camper after finding a camp, you always want to make your camp look better than before you find it.
It's good that you have this idea before you put in a task that takes a lot of time and effort to accomplish. But, as I mentioned earlier, game designers need a lot of experimentation and exploration, so you might write a bunch of code that you know you're going to throw away sooner or later, especially in the early days.
If you just want to find some good game ideas and ideas quickly, that means you'll spend a lot of time building good code libraries before you get feedback. And when you find these ideas are not very good to delete, you wasted the previous hard work of building an elegant code base.
Prototyping – A solution that's pieced together to achieve functionality – it's a perfectly reasonable way to practice programming. However, there are obviously some very big problems. You need to make sure that you can then delete the prototype code that you've written. I have often been able to see the following scenes happening over and over again:
boss :"Hey, man, we have a very good idea, can you develop a prototype, without a lot of technical details, as long as the prototype can, how quickly you can integrate these functions?" "
developer :"Well, if you don't have to test, you don't have to think about performance, you don't have to write a document, you can have a prototype in a few days without a bug."
boss :"Great!" Let's get started! "
A few days later,,,,
Boss: "Hey, man, this prototype is great!" Can you take a few days to wrap it up on the line? ”
So, you need to make use of these one-time code people, understand that although the code seems to work properly, but, in fact, it can not be maintained, you must remove the rewrite. If the situation is that you eventually have to keep the code, then you must be very careful to write.
Seeking balance
We need to find the balance between the following requirements:
1. We want to pursue a good code base, so that they can be well understood during the life cycle of the project;
2. We want to run more efficiently;
3. We want the current needs to be realized quickly;
These goals are, to a large extent, in a contradictory situation. For example, a good architecture can improve productivity in long-term project development, but in maintaining it, you need to follow some principles to maintain a good architecture after each iteration.
The quickest way to encode does not necessarily mean the fastest running efficiency. Instead, the optimizer requires a lot of engineering time, and once the program is optimized, the flexibility of the codebase decreases because: highly optimized code is often not very flexible and difficult to change in the next development.
We tend to be under such pressure to do what we do today and to worry about tomorrow. However, if we focus only on today's tasks and over-speed, then our code base will become a ubiquitous loophole, bugs, inconsistencies, which will weaken our future productivity.
There is no definitive answer, only a compromise approach. As I see from some of my emails, these problems are also troubling a lot of people. It sounds disappointing, especially for beginners who just want to play the game, but the reality is,"This problem is never the right answer, there are only different forms of the wrong solution."
But for me, it's so exciting! You look at all the other areas of the puzzle, there is a lot of interaction between the constraints and tradeoffs. After all, if a problem has a simple solution, then everyone will do so. And the knowledge that you can master in one weeks will usually end up being boring and worthless. For example, you won't hear people blockbuster by digging trenches.
For me, there is a lot in common with the game itself. For example, a game like chess cannot have an absolutely winning strategy, because every decision is limited to a different set of steps. This means that even if you spend your entire life, it is impossible to know a winning strategy. A poorly designed game can be crushed and rolled over and over again until you get bored and give up.
Simple
Recently, I was thinking, if there is any way to eliminate these constraints, I think it should be concise . I am now programming, always try to use the most neat, the most direct way to solve the problem, such code after you read it, you can fully understand its meaning, understand it to do things, will not cause other ambiguity.
My goal is to write data structures and algorithms in pairs. And I found that if I kept things simple, then the amount of code would fall, and the reduced code would be better understood by me, making it easier to change.
In general, if there is not too much header files and code, the efficiency of the operation will be relatively fast (certainly not always guaranteed, for example, many loops and recursive code, although the code is small, but not run fast).
Please note that I'm not saying that simple code requires less time to write. You're going to think that because you might give way. Simple code will end up with very little code, so less development time. However, keep in mind that the good of a solution is not evaluated from its code volume.
We seldom have a very simple elegant task to tell you what its needs are, and on the contrary, what we get is often a bunch of use cases. For example, in the case of z you want X to execute Y, but in the case of a, you want X to execute W, and so on. In short, it's a long list with different use-case behaviors.
The least-cost-of-mind approach is that a use case is a use case to go to be realized. We are often able to see how novice programmers work: They usually make a logical judgment of each case and write a big push on the if else stack.
This is really a little beauty is not ah, often when the input slightly changed, the program will not work properly. Our so-called elegant solution is to use a small logic that can cover a large number of use cases.
Finding this solution is a bit like pattern matching or solving a maze. You need to spend a lot of time finding the hidden patterns in these use cases. And when you find these laws, you usually have a great sense of satisfaction.
Get ready to do it!
Almost everyone skips the book's introductory chapters, so I appreciate it and congratulate you on being able to see it all the time. For your patience (although there is no gift, haha), however, I hope that the following summary of these suggestions can help you:
- Abstract and decoupled can make your program development fast and easy, but you do not want to spend too much time on it, unless you have a lot of confidence in the task requirements and flexibility of this code;
- Throughout the development cycle, you have to think about the performance of the design, but the bottom-level details of the optimization, I suggest or can be as far as possible to do the last;
- You need to quickly explore the design of the game space, but also do not go too fast, leaving a lot of pits, after all, you still have to still;
- If you know that the code is going to be discarded sooner or later, don't spend too much time doing it well. Some rock star hotel rooms are very messy, it is because they know tomorrow will check out;
Copyright NOTICE: If you want to reprint, please attach this article link, not very grateful!
Game Programming Patterns (Gameplay programming Mode)-architecture, performance and gameplay