0% found this document useful (0 votes)
46 views632 pages

C++ Edition

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views632 pages

C++ Edition

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 632

C++ Edition

Copyright © 2019-2023 Daniele Penazzo

2D Game Development: From Zero To Hero (C++ edition, version 0.7.7) is distributed under the terms of the

Creative Commons Attribution-NonCommercial-ShareAlike International 4.0 license.

If you want to view a copy of the license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or check the

LICENSE file in the book repository.

The PDF and EPub releases of this book can be found at the following address:

• https://therealpenaz91.itch.io/2dgd-f0th (Official Itch.io Page)

This book’s source code can be found in the following official repositories:

• https://gitlab.com/Penaz/2dgd_f0th (Official GitLab Repository)

• https://github.com/2DGD-F0TH/2DGD_F0TH/ (Official GitHub Mirror Repository)

This work shall be attributed to Daniele Penazzo and the ”2D Game Development: From Zero To Hero” community,

to see a full list of the contributors, please check the CONTRIBUTORS file in the repository, or head to the Contributors

section in this book.


Perseverance is the backbone of success.

Anonymous

To my family

To my friends, both international and not

To the ones who never give up

Daniele Penazzo
Contents

1 Foreword 1

2 Introduction 2

2.1 Why another game development book? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2.2 Conventions used in this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.1 Logic Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.2 Code Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.3 Block Quotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.4 Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2.5 Engine Used . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2.6 About editions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.3 Structure of this Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 The Maths Behind Game Development 9

3.1 Some useful symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.2 The modulo operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.3 Powers and Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3.4 Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3.4.1 You can add or subtract any number on both sides . . . . . . . . . . . . . . . . . . . . . 11

3.4.2 You can multiple or divide any non-zero number on both sides . . . . . . . . . . . . . . . 11

3.5 Exponentiations and Logarithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.6 Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.7 Derivatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.8 The Cartesian Plane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.9 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.9.1 Adding and Subtracting Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.9.2 Scaling Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.9.3 Dot Product . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.9.4 Vector Length and Normalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.9.5 “Clamping” a Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.10 Geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.10.1 Convex vs Concave polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.10.2 Self-intersecting polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.10.3 Straight Lines and their equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.10.3.1 Getting the equation of a straight line, given two points . . . . . . . . . . . . . . 21

3.10.3.2 Getting the equation, given the slope and a point . . . . . . . . . . . . . . . . . . 22

3.10.4 Projections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3.10.4.1 Projecting arbitrary lines on the axes . . . . . . . . . . . . . . . . . . . . . . . . 24

3.11 Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

III
2D Game Development: From Zero To Hero

3.11.1 What is a matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.11.2 Matrix sum and subtraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.11.3 Multiplication by a scalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.11.4 Transposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.11.5 Multiplication between matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.11.6 Other uses for matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.12 Trigonometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.12.1 Radians vs Degrees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.12.2 Sine, Cosine and Tangent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.12.3 Pythagorean Trigonometric Identity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.12.4 Reflections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.12.5 Shifts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.12.6 Trigonometric Addition and subtraction . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.12.7 Double-Angle Formulae . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.12.8 Inverse Formulas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.13 Numerical Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.13.1 Newton-Raphson method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.14 Coordinate Systems on computers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.15 Transformation Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.15.1 Stretching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.15.2 Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3.15.2.1 Choosing the direction of the rotation . . . . . . . . . . . . . . . . . . . . . . . . 37

3.15.2.2 Rotating referred to an arbitrary point . . . . . . . . . . . . . . . . . . . . . . . . 38

3.15.3 Shearing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.16 Basics of Probability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.16.1 A simple definition of probability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.16.2 Probability of independent events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.16.3 Probability of mutually exclusive events . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3.16.4 Probability of non-mutually exclusive events . . . . . . . . . . . . . . . . . . . . . . . . . 41

3.16.5 Conditional Probability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

3.16.6 Uniform Distributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

3.16.7 How probability is used in games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

3.16.8 Tiered Prize Pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.16.8.1 Introducing a “luck” stat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

4 Some Computer Science Fundamentals 49

4.1 Number representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4.1.1 The most used representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4.1.1.1 Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4.1.1.2 Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

CONTENTS IV
2D Game Development: From Zero To Hero

4.1.1.3 Octal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

4.1.1.4 Hexadecimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.1.2 Converting between decimal and binary . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

4.1.2.1 Two’s complement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

4.1.2.2 Floating point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

4.1.3 Converting between binary and octal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

4.1.4 Gray Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

4.2 Basics of Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

4.2.1 Truth tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

4.2.2 Common operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

4.2.2.1 AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

4.2.2.2 OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

4.2.2.3 NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

4.2.2.4 XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

4.2.3 Logic operations vs bitwise operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

4.2.3.1 Packing more information with less . . . . . . . . . . . . . . . . . . . . . . . . . 58

4.2.4 De Morgan’s Laws and Conditional Expressions . . . . . . . . . . . . . . . . . . . . . . . 59

4.3 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

4.4 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

4.5 Programming Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

4.5.1 Classifying programming languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

4.5.1.1 By how they build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

4.5.1.2 By Paradigm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

4.5.1.3 By the way types are determined . . . . . . . . . . . . . . . . . . . . . . . . . . 64

4.5.1.4 By the “strength” of typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

4.5.1.5 By memory management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4.5.2 Languages available for this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4.6 Computers are (not) precise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

4.6.1 Catastrophic cancellation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

4.7 Random Numbers are not really random . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

4.7.1 How to seed a random number generator . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4.8 Estimating the complexity of algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

4.8.1 O(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4.8.2 O(log(n)) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

4.8.3 O(n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

4.8.4 O(n·log(n)) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2
4.8.5 O(n ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
n
4.8.6 O(2 ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

4.9 A primer on calculating the order of your algorithms . . . . . . . . . . . . . . . . . . . . . . . . . 76

4.9.1 Some basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

CONTENTS V
2D Game Development: From Zero To Hero

4.9.2 What happens when we have more than one big-O? . . . . . . . . . . . . . . . . . . . . . 77

4.9.3 A problem with asymptotic complexity . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

4.9.4 What do we do with recursive algorithms? . . . . . . . . . . . . . . . . . . . . . . . . . . 79

4.9.5 How do big-O estimates compare to each other? . . . . . . . . . . . . . . . . . . . . . . 79

4.10 Simplifying your conditionals with Karnaugh Maps . . . . . . . . . . . . . . . . . . . . . . . . . . 80

4.10.1 “Don’t care”s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

4.10.2 A more complex map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

4.10.3 Guided Exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

4.11 Object Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

4.11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

4.11.2 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

4.11.3 Abstraction and Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

4.11.4 Inheritance and Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

4.11.5 Mixins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

4.11.6 The Diamond Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

4.11.7 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

4.11.8 Composition vs. Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

4.11.9 “Composition over Inheritance” design . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

4.11.10 Coupling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

4.11.11 The DRY Principle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

4.11.12 SOLID Principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

4.12 Designing entities as data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

4.13 Reading UML diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

4.13.1 Use Case Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

4.13.1.1 Actors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

4.13.1.2 Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

4.13.1.3 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

4.13.1.4 Sub-Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

4.13.2 Class Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

4.13.2.1 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

4.13.2.2 Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

4.13.2.3 Relationships between entities of the class diagram . . . . . . . . . . . . . . . . . 99

4.13.2.4 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102

4.13.3 Activity Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102

4.13.3.1 Start and End Nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103

4.13.3.2 Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103

4.13.3.3 Decisions (Conditionals) and loops . . . . . . . . . . . . . . . . . . . . . . . . . .103

4.13.3.4 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105

4.13.3.5 Swimlanes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105

4.13.3.6 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106

CONTENTS VI
2D Game Development: From Zero To Hero

4.13.3.7 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107

4.13.3.8 A note on activity diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107

4.13.4 Sequence Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108

4.13.4.1 Lifelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108

4.13.4.2 Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109

4.13.4.3 Object Instantiation and Destruction . . . . . . . . . . . . . . . . . . . . . . . . .109

4.13.4.4 Grouping and loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110

4.13.4.5 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110

4.13.5 Other diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .111

4.14 Generic Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .111

4.15 Advanced Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112

4.15.1 Dynamic Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112

4.15.1.1 Performance Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112

4.15.2 Linked Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .114

4.15.2.1 Performance Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115

4.15.3 Doubly-Linked Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116

4.15.4 Hash Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117

4.15.5 Binary Search Trees (BST) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118

4.15.6 Heaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119

4.15.7 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120

4.15.8 Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .121

4.15.9 Circular Queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122

4.16 The principle of locality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .123

4.17 Treating multidimensional structures like one-dimensional ones . . . . . . . . . . . . . . . . . . .123

4.18 Data Redundancy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125

4.19 Introduction to Multi-Tasking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127

4.19.1 Multi-Threading vs Multi-Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127

4.19.2 Coroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .128

4.20 Introduction to Multi-Threading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129

4.20.1 What is Multi-Threading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129

4.20.2 Why Multi-Threading? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129

4.20.3 Thread Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130

4.20.3.1 Race conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130

4.20.3.2 Critical Regions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132

4.20.4 Ensuring determinism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132

4.20.4.1 Immutable Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132

4.20.4.2 Mutex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132

4.20.4.3 Atomic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .135

5 A Game Design Dictionary 136

CONTENTS VII
2D Game Development: From Zero To Hero

5.1 Platforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136

5.1.1 Arcade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136

5.1.2 Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137

5.1.3 Personal Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137

5.1.4 Mobile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .139

5.1.5 Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .139

5.2 Input Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140

5.2.1 Mouse and Keyboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140

5.2.2 Gamepad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140

5.2.3 Touch Screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141

5.2.4 Dedicated Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141

5.2.5 Other Input Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141

5.3 Game Genres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

5.3.1 Shooters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

5.3.2 Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

5.3.3 Platformer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

5.3.4 RPG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142

5.3.5 MMO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143

5.3.6 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143

5.3.7 Rhythm Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143

5.3.8 Visual novels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143

5.3.9 Puzzle games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143

5.4 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144

5.4.1 Emergent Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144

6 Project Management Basics and tips 146

6.1 The figures of game design and development . . . . . . . . . . . . . . . . . . . . . . . . . . . .146

6.1.1 Producer/Project Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146

6.1.2 Game Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146

6.1.3 Writer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147

6.1.4 Developer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147

6.1.5 Visual Artist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148

6.1.6 Sound Artist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148

6.1.7 Tester . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148

6.2 Some general tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149

6.2.1 Be careful of feature creep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149

6.2.2 On project duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149

6.2.3 Brainstorming: the good, the bad and the ugly . . . . . . . . . . . . . . . . . . . . . . .149

6.2.4 On Sequels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150

6.3 Common Errors and Pitfalls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150

CONTENTS VIII
2D Game Development: From Zero To Hero

6.3.1 Losing motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150

6.3.2 The “Side Project” pitfall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150

6.3.3 Making a game “in isolation” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151

6.3.4 (Mis)Handling Criticism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151

6.3.4.1 Misusing of the Digital Millennium Copyright Act . . . . . . . . . . . . . . . . . .151

6.3.5 Not letting others test your game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .153

6.3.6 Being perfectionist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .153

6.3.7 Using the wrong engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .154

6.4 Software Life Cycle Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155

6.4.1 Iteration versus Increment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155

6.4.2 Waterfall Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155

6.4.3 Incremental Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155

6.4.4 Evolutionary Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .156

6.4.5 Agile Software Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157

6.4.5.1 User Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157

6.4.5.2 Scrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .158

6.4.5.3 Kanban . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .158

6.4.5.4 ScrumBan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .159

6.4.6 Lean Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .159

6.4.7 Where to go from here . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .160

6.5 Version Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .160

6.6 Metrics and dashboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .160

6.6.1 SLOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161

6.6.2 Cyclomatic Complexity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161

6.6.2.1 How cyclomatic complexity is calculated . . . . . . . . . . . . . . . . . . . . . .161

6.6.3 Code Coverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .163

6.6.4 Code Smells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .164

6.6.5 Coding Style infractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .164

6.6.6 Depth of Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .164

6.6.7 Number of methods / fields / variables . . . . . . . . . . . . . . . . . . . . . . . . . . . .165

6.6.8 Number of parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165

6.6.9 Other metrics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165

7 Writing a Game Design Document 166

7.1 What is a Game Design Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166

7.2 Possible sections of a Game Design Document . . . . . . . . . . . . . . . . . . . . . . . . . . . .166

7.2.1 Project Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166

7.2.2 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167

7.2.3 Storyline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167

7.2.3.1 The theme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167

CONTENTS IX
2D Game Development: From Zero To Hero

7.2.3.2 Progression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168

7.2.4 Levels and Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168

7.2.5 Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168

7.2.5.1 Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168

7.2.5.2 Game Mechanics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .169

7.2.5.3 Skills . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .169

7.2.5.4 Items/Powerups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .170

7.2.5.5 Difficulty Management and Progression . . . . . . . . . . . . . . . . . . . . . . .170

7.2.5.6 Losing Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171

7.2.6 Graphic Style and Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171

7.2.7 Sound and Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171

7.2.8 User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172

7.2.9 Game Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172

7.2.10 Accessibility Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173

7.2.11 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173

7.2.12 Marketing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173

7.2.12.1 Target Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174

7.2.12.2 Available Platforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174

7.2.12.3 Monetization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .174

7.2.12.4 Internationalization and Localization . . . . . . . . . . . . . . . . . . . . . . . . .175

7.2.13 Other/Random Ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175

7.3 Where to go from here . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175

8 The Game Loop 178

8.1 The Input-Update-Draw Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178

8.2 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .179

8.2.1 Events vs Real Time Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .179

8.3 Timing your loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180

8.3.1 What is a time step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180

8.3.2 Fixed Time Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180

8.3.3 Variable Time Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181

8.3.4 Semi-fixed Time Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181

8.3.5 Frame Limiting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182

8.3.6 Frame Skipping/Dropping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183

8.3.7 Multi-threaded Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183

8.4 Issues and possible solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184

8.4.1 Frame/Screen Tearing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184

8.5 Drawing to screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184

8.5.1 Clearing the screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .185

9 Collision Detection and Reaction 187

CONTENTS X
2D Game Development: From Zero To Hero

9.1 Why Collision Detection is done in multiple passes . . . . . . . . . . . . . . . . . . . . . . . . . .187

9.2 Narrow-Phase Collision Detection: did it really collide? . . . . . . . . . . . . . . . . . . . . . . . .187

9.2.1 Collision Between Two Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188

9.2.2 Collision Between A Point and a Circle . . . . . . . . . . . . . . . . . . . . . . . . . . . .189

9.2.3 Collision Between Two Circles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190

9.2.4 Collision Between Two Axis-Aligned Rectangles (AABB) . . . . . . . . . . . . . . . . . . .192

9.2.5 Line/Point Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .195

9.2.6 Line/Circle Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197

9.2.7 Point/Rectangle Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .199

9.2.8 Point/Triangle Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .199

9.2.9 Circle/Rectangle Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .201

9.2.10 Line/Line Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203

9.2.11 Line/Rectangle Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205

9.2.12 Point/Polygon Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .206

9.2.12.1 Jordan Curve Theorem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .206

9.2.12.2 Thinking outside the box: polygon triangulation . . . . . . . . . . . . . . . . . . .209

9.2.12.3 Bounding Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .209

9.2.12.4 Point/Polygon collision detection using triangulation . . . . . . . . . . . . . . . . .211

9.2.13 Circle/Polygon Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .214

9.2.14 Line/Polygon Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .216

9.2.15 Polygon/Polygon Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .218

9.2.16 Non-convex polygons collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .219

9.2.16.1 Polygon triangulation: the return . . . . . . . . . . . . . . . . . . . . . . . . . .221

9.2.17 Pixel-Perfect collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .222

9.3 Broad-phase collision detection: is a collision even possible? . . . . . . . . . . . . . . . . . . . .223

9.3.1 The Brute Force Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224

9.3.2 Building Quad Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .225

9.3.2.1 A more precise definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226

9.3.2.2 Querying quad trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227

9.3.3 Building AABB-Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227

9.3.3.1 Querying AABB-trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228

9.3.4 Collision groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .230

9.4 Other Collision Detection Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .231

9.4.1 Calculating the position of tiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .231

9.4.2 The “Tile + Offset” Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .234

9.5 Collision Reaction/Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .234

9.5.1 HitBoxes vs HurtBoxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .234

9.5.2 Collision Reaction Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .235

9.5.2.1 A naive approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .235

9.5.2.2 Shallow-axis based reaction method . . . . . . . . . . . . . . . . . . . . . . . . .237

CONTENTS XI
2D Game Development: From Zero To Hero

9.5.2.3 Interleaving single-axis movement and collision detection . . . . . . . . . . . . .239

9.5.2.4 The “Snapshot” Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .240

9.5.3 When two moving items collide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .241

9.6 Common Issues with time-stepping Collision Detection . . . . . . . . . . . . . . . . . . . . . . .242

9.6.1 The “Bullet Through Paper” problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242

9.6.2 Precision Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243

9.6.3 One-way obstacles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243

9.7 Separating Axis Theorem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243

9.7.1 Why only convex polygons? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .244

9.7.2 How it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .245

9.7.2.1 Finding the axes to analyze . . . . . . . . . . . . . . . . . . . . . . . . . . . . .246

9.7.2.2 Projecting the shapes into the axes and exiting the algorithm . . . . . . . . . . . .247

9.7.2.3 From arbitrary axes to “x and y” . . . . . . . . . . . . . . . . . . . . . . . . . . .248

9.8 Ray Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .249

9.8.1 What is Ray Casting? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .249

9.8.2 Other uses for ray casting: Pseudo-3D environments . . . . . . . . . . . . . . . . . . . .250

10 Scene Trees 251

10.1 What is a scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251

10.2 Scene trees and their functionalities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251

10.2.1 How scene trees can make drawing entities easier . . . . . . . . . . . . . . . . . . . . .251

10.3 Implementing a scene tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .252

11 Cameras 253

11.1 Screen Space vs. Game Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253

11.2 Cameras and projections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .254

11.3 Most used camera transitions and types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255

11.3.1 Static Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255

11.3.2 Grid Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255

11.3.3 Position-Tracking Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255

11.3.3.1 Horizontal-Tracking Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255

11.3.3.2 Full-Tracking Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256

11.3.4 Camera Trap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256

11.3.5 Look-Ahead Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .257

11.3.6 Hybrid Approaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258

11.4 Clamping your camera position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258

12 Game Design Tips 260

12.1 Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260

12.1.1 Do not pad tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260

12.1.2 Integrate tutorials in the lore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260

CONTENTS XII
2D Game Development: From Zero To Hero

12.1.3 Let the player explore the controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260

12.2 Consolidating and refreshing the game mechanics . . . . . . . . . . . . . . . . . . . . . . . . . .261

12.2.1 Remind the player about the mechanics they learned . . . . . . . . . . . . . . . . . . . .261

12.2.2 Introduce new ways to use old mechanics . . . . . . . . . . . . . . . . . . . . . . . . . .261

12.3 Rewarding the player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261

12.3.1 Reward the player for their “lateral thinking” . . . . . . . . . . . . . . . . . . . . . . . .261

12.3.2 Reward the player for their tenacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262

12.3.3 Reward the player for exploring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263

12.3.4 Reward the player for not immediately following the given direction . . . . . . . . . . . .263

12.3.5 Reward the player for not trusting you entirely . . . . . . . . . . . . . . . . . . . . . . .263

12.3.6 Reward Backtracking (but don’t make it mandatory!) . . . . . . . . . . . . . . . . . . . .264

12.3.7 The “lives” system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .264

12.3.7.1 1-UPs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .265

12.3.7.2 Other approaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .265

12.4 Loading Screens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .266

12.4.1 What to put in a loading screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .266

12.4.2 Letting the player “exit” the loading screen . . . . . . . . . . . . . . . . . . . . . . . . .266

12.4.3 Avoiding a loading screen altogether . . . . . . . . . . . . . . . . . . . . . . . . . . . . .267

12.5 Designing the story and gameplay flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .267

12.5.1 Linear Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .267

12.5.2 Branching gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268

12.5.3 Parallel gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .269

12.5.4 Threaded gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .269

12.5.5 Episodic gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .270

12.5.6 Adding parallel paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .270

12.5.7 Looping Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .271

12.5.7.1 Soft-reset mechanics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .271

12.6 Some game genres and their characteristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272

12.6.1 Roguelikes and Rogue-lites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272

12.6.1.1 Use of pseudo-randomness and procedural generation . . . . . . . . . . . . . . .272

12.6.1.2 Permadeath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272

12.6.1.3 Turn-based Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .273

12.6.1.4 Lack of mode-based gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . .273

12.6.1.5 Multiple ways to accomplish (or fail!) a task . . . . . . . . . . . . . . . . . . . . .273

12.6.1.6 Resource Management is key . . . . . . . . . . . . . . . . . . . . . . . . . . . .273

12.6.1.7 Peace was never an option . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .273

12.6.1.8 Dealing with the unknown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .273

12.7 Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .274

12.7.1 General Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .274

12.7.1.1 Make that last Health Point count . . . . . . . . . . . . . . . . . . . . . . . . . .274

CONTENTS XIII
2D Game Development: From Zero To Hero

12.7.1.2 Avoiding a decision can be a decision itself . . . . . . . . . . . . . . . . . . . . .274

12.7.1.3 Telegraphing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .275

12.7.1.4 Minigames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .275

12.7.1.5 When unlockables are involved, be balanced . . . . . . . . . . . . . . . . . . . .276

12.7.2 Shooters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276

12.7.2.1 Make the bullets stand out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276

12.7.3 RPGs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277

12.7.3.1 Grinding and farming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277

12.7.3.2 Leveling Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278

12.7.3.3 “Mastering” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279

12.8 Perceived Fairness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .280

12.8.1 You don’t need precise collision detection . . . . . . . . . . . . . . . . . . . . . . . . . .280

12.8.2 Immediate dangers should be well visible . . . . . . . . . . . . . . . . . . . . . . . . . .281

12.9 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .282

12.9.1 You cannot use the “Red Cross” in games . . . . . . . . . . . . . . . . . . . . . . . . . .283

12.9.2 Auto-saving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283

12.9.3 Feedback is important . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283

13 Creating your assets 286

13.1 Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286

13.2 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286

13.2.1 Some computer graphics basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286

13.2.1.1 The “color wheel” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286

13.2.1.2 Color representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .287

13.2.1.3 Primary, Secondary and Tertiary colors . . . . . . . . . . . . . . . . . . . . . . .289

13.2.1.4 Analogous Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289

13.2.1.5 Complementary Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289

13.2.1.6 Color Depth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290

13.2.1.7 Direct Color vs. Indexed Color . . . . . . . . . . . . . . . . . . . . . . . . . . . .293

13.2.1.8 Lossless Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .293

13.2.1.9 Lossy Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .293

13.2.1.10 Transparency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .294

13.2.1.11 Texture Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .294

13.2.2 General Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .295

13.2.2.1 Practice, Practice, Practice… . . . . . . . . . . . . . . . . . . . . . . . . . . . . .295

13.2.2.2 References are your friends . . . . . . . . . . . . . . . . . . . . . . . . . . . . .295

13.2.2.3 Don’t compare your style to others’ . . . . . . . . . . . . . . . . . . . . . . . . .295

13.2.2.4 Study other styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .295

13.2.2.5 Learn to deconstruct objects into shapes . . . . . . . . . . . . . . . . . . . . . .296

13.2.3 Sprite sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296

CONTENTS XIV
2D Game Development: From Zero To Hero

13.2.3.1 Sprite Sheet Gotchas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .297

13.2.4 Virtual Resolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .298

13.2.5 Using limited color palettes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .299

13.2.5.1 Dithering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .299

13.2.5.2 Palette Swapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301

13.2.6 Layering and graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301

13.2.6.1 Detail attracts attention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301

13.2.6.2 Use saturation to separate layers further . . . . . . . . . . . . . . . . . . . . . .302

13.2.6.3 Movement is yet another distraction . . . . . . . . . . . . . . . . . . . . . . . . .302

13.2.6.4 Use contrast to your advantage . . . . . . . . . . . . . . . . . . . . . . . . . . .302

13.2.6.5 Find exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .303

13.2.6.6 Summarizing Layering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .303

13.2.7 Pixel Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .305

13.2.7.1 What pixel art is and what it is not . . . . . . . . . . . . . . . . . . . . . . . . . .305

13.2.7.2 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .305

13.2.7.3 Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306

13.2.7.4 Sub-pixel animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306

13.2.8 Normal Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306

13.2.8.1 A simple example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307

13.2.9 Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .308

13.2.9.1 Tiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .308

13.2.9.2 Sprites and icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .311

13.3 Sounds And Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312

13.3.1 Some audio basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312

13.3.1.1 Sample Rate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312

13.3.1.2 Bit Depth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313

13.3.1.3 Lossless Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .314

13.3.1.4 Lossy Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .314

13.3.1.5 Clipping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .314

13.3.2 Sound Synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315

13.3.2.1 AM Synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315

13.3.2.2 FM Synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .316

13.3.2.3 FM Synthesis vs Sample-based music . . . . . . . . . . . . . . . . . . . . . . . .316

13.3.3 Basic Wave Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .317

13.3.3.1 Sine Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .317

13.3.3.2 Square Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .318

13.3.3.3 Triangle Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .318

13.3.3.4 Sawtooth Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .318

13.3.3.5 Noise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .319

13.3.4 ADSR Envelope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .319

CONTENTS XV
2D Game Development: From Zero To Hero

13.3.4.1 Attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .320

13.3.4.2 Decay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .320

13.3.4.3 Sustain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .320

13.3.4.4 Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .321

13.3.5 Digital Sound Processing (DSP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .321

13.3.5.1 Reverb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .322

13.3.5.2 Pitch Shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .322

13.3.5.3 Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .322

13.3.5.4 Doppler Effect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .322

13.3.6 Simulating older consoles’ audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .323

13.3.6.1 Commodore Vic20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .323

13.3.6.2 Commodore 64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .323

13.3.6.3 Commodore Amiga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .324

13.3.6.4 Sega Master System / GameGear . . . . . . . . . . . . . . . . . . . . . . . . . .325

13.3.6.5 Sega Genesis/MegaDrive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .325

13.3.6.6 NES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .325

13.3.6.7 SNES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326

13.3.6.8 AdLib / SoundBlaster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326

13.3.7 “Swappable” sound effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326

13.3.8 Some audio processing tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

13.3.8.1 Prefer cutting over boosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

13.3.9 DAW Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

13.3.9.1 What is a DAW Software? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

13.3.9.2 The Piano Roll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

13.3.10 Music Tracker Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .328

13.3.10.1 What is a Music Tracker Software? . . . . . . . . . . . . . . . . . . . . . . . . . .328

13.3.10.2 Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330

13.3.10.3 Instruments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330

13.3.10.4 Channels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331

13.3.10.5 Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331

13.3.11 Basic Rhythms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331

13.3.11.1 Four on the floor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331

13.3.11.2 Four on the floor with off-beat hi-hats . . . . . . . . . . . . . . . . . . . . . . . .332

13.3.11.3 A simple rock beat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332

13.3.12 Adaptive Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332

13.4 Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332

13.4.1 Font Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332

13.4.1.1 Serif and Sans-Serif fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333

13.4.1.2 Proportional and Monospaced fonts . . . . . . . . . . . . . . . . . . . . . . . . .333

13.4.2 Using textures to make text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334

CONTENTS XVI
2D Game Development: From Zero To Hero

13.4.3 Using Fonts to make text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334

13.5 Shaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334

13.5.1 What are shaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334

13.5.2 Shader Programming Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .334

13.5.3 The GLSL Programming Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .335

13.5.3.1 The data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .335

13.5.4 Some GLSL Shaders examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336

14 Design Patterns 338

14.1 Creational Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338

14.1.1 Singleton Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338

14.1.2 Dependency Injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .340

14.1.3 Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .340

14.2 Structural Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .341

14.2.1 Flyweight . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .341

14.2.2 Component/Composite Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342

14.2.3 Decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .344

14.2.4 Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345

14.2.4.1 Object Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .346

14.2.4.2 Class Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .346

14.2.5 Facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .347

14.2.6 Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .347

14.3 Behavioural Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .349

14.3.1 Command Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .350

14.3.2 Observer Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .351

14.3.3 Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .353

14.3.4 Chain of Responsibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354

14.3.5 Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355

14.4 Architectural Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355

14.4.1 Service Locator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .356

15 Useful Containers and Classes 357

15.1 Resource Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357

15.2 Animator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .357

15.3 Finite State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358

15.4 Menu Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .361

15.5 Particle Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .361

15.5.1 Particles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .361

15.5.2 Emitters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .364

15.5.3 Force Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .366

15.6 Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .367

CONTENTS XVII
2D Game Development: From Zero To Hero

15.6.1 Accounting for “leftover time” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .369

15.6.1.1 A naive solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .369

15.6.1.2 A different approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .370

15.7 Inbetweening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372

15.7.1 Bouncing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .374

15.8 Chaining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .375

16 Artificial Intelligence in Videogames 376

16.1 Path Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .376

16.1.1 Representing our world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .376

16.1.1.1 2D Grids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .376

16.1.1.2 Path nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .377

16.1.1.3 Navigation meshes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .379

16.1.2 Heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .381

16.1.2.1 Manhattan Distance heuristic . . . . . . . . . . . . . . . . . . . . . . . . . . . .381

16.1.2.2 Euclidean Distance heuristic . . . . . . . . . . . . . . . . . . . . . . . . . . . . .382

16.1.3 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .383

16.1.3.1 A simple “Wandering” Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . .384

16.1.3.2 A slightly better “Wandering” algorithm . . . . . . . . . . . . . . . . . . . . . . .388

16.1.3.3 The Greedy “Best First” Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . .390

16.1.3.4 The Dijkstra Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .392

16.1.3.5 The A* Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .393

16.2 Finite state machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .395

16.3 Decision Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .396

16.4 Behaviour Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .396

17 Other Useful Algorithms 398

17.1 World Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .398

17.1.1 Midpoint Displacement Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .398

17.1.2 Diamond-Square Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .401

17.1.3 Maze Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .403

17.1.3.1 Randomized Depth-First Search (Recursive Backtracker) . . . . . . . . . . . . . .404

17.1.3.2 Randomized Kruskal’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . .410

17.1.3.3 Recursive Division Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . .412

17.1.3.4 Binary Tree Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .415

17.1.3.5 Eller’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417

17.2 Dungeon Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419

17.3 Noise Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419

17.3.1 Randomized Noise (Static) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419

17.3.2 Perlin Noise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420

17.4 Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420

CONTENTS XVIII
2D Game Development: From Zero To Hero

17.4.1 Skeleton animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420

18 Procedural Content Generation 421

18.1 What is procedural generation (and what it isn’t) . . . . . . . . . . . . . . . . . . . . . . . . . . .421

18.2 Advantages and disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423

18.2.1 Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423

18.2.1.1 Less disk space needed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423

18.2.1.2 Larger games can be created with less effort . . . . . . . . . . . . . . . . . . . .423

18.2.1.3 Lower budgets needed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423

18.2.1.4 More variety and replayability . . . . . . . . . . . . . . . . . . . . . . . . . . . .423

18.2.2 Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .424

18.2.2.1 Requires more powerful hardware . . . . . . . . . . . . . . . . . . . . . . . . . .424

18.2.2.2 Less Quality Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .424

18.2.2.3 Worlds can feel repetitive or “lacking artistic direction” . . . . . . . . . . . . . . .424

18.2.2.4 You may generate something unusable . . . . . . . . . . . . . . . . . . . . . . .424

18.2.2.5 Story and set game events are harder to script . . . . . . . . . . . . . . . . . . .424

18.3 Where it can be used . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .425

18.4 Procedural Generation and Difficulty Management . . . . . . . . . . . . . . . . . . . . . . . . . .425

18.4.1 Static difficulty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .426

18.4.2 Adaptive Difficulty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .426

18.4.2.1 Rubberbanding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .426

18.4.3 Static vs. Adaptive Difficulty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .426

19 Developing Game Mechanics 428

19.1 General Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .428

19.1.1 I-Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .428

19.1.2 Tilemaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .429

19.1.2.1 Rectangular Tilemaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .429

19.1.2.2 Hexagonal Tilemaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .430

19.1.2.3 Isometric Tilemaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .432

19.1.3 Scrolling Backgrounds and Parallax Scrolling . . . . . . . . . . . . . . . . . . . . . . . . .433

19.1.3.1 Infinitely Scrolling Backgrounds . . . . . . . . . . . . . . . . . . . . . . . . . . .433

19.1.3.2 Parallax Scrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .434

19.1.4 Avoid interactions between different input systems . . . . . . . . . . . . . . . . . . . . .435

19.1.5 Sprite Stenciling/Masking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .436

19.1.6 Loading screens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .436

19.1.7 Simulating Inertia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .437

19.1.8 Corner correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .442

19.2 2D Platformers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .443

19.2.1 Simulating Gravity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .443

19.2.2 Avoiding “Floaty Jumps” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .443

CONTENTS XIX
2D Game Development: From Zero To Hero

19.2.3 Making jumps “float differently” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .445

19.2.4 Ladders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .446

19.2.5 Walking on slanted ground . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .446

19.2.6 Stairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .446

19.2.7 Ledge Grabbing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .446

19.2.8 Jump Buffering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .446

19.2.9 Coyote Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .447

19.2.10 Timed Jumps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .449

19.2.11 Wall Jumps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450

19.2.12 Screen Wrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450

19.3 Top-view RPG-Like Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450

19.3.1 Managing height . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450

19.3.1.1 Faking it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450

19.3.1.2 Managing height for real . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .451

19.4 Rhythm Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .451

19.4.1 The world of lag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .451

19.4.1.1 Input Lag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .452

19.4.1.2 Video Lag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .452

19.4.1.3 Audio Lag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .452

19.4.1.4 Lag Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .452

19.4.2 Synchronizing with the Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .453

19.4.2.1 Time domain vs. Frequency Domain . . . . . . . . . . . . . . . . . . . . . . . . .453

19.4.2.2 The Fast Fourier Transform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .454

19.4.2.3 Beat Detection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .454

19.5 “Bullet Hell” Style Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .454

19.5.1 Bullets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .455

19.5.2 The Ship Hitbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .455

19.5.3 Screen-clearing bombs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .456

19.5.4 Clearing bullets on pattern changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . .456

19.5.5 Find other chances to clear some bullets . . . . . . . . . . . . . . . . . . . . . . . . . . .457

19.5.6 Turn enemy bullets into collectibles at the end of a boss fight . . . . . . . . . . . . . . . .457

19.5.7 The “Chain Meter” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .457

19.5.8 Managing the player’s death . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .458

19.5.9 The Enemy AI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .458

19.5.10 Be fair to the player, but also to the computer . . . . . . . . . . . . . . . . . . . . . . . .458

19.5.11 Inertia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459

19.5.12 Some examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459

19.6 Match-x Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459

19.6.1 Managing and drawing the grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459

19.6.2 Finding and removing Matches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .460

CONTENTS XX
2D Game Development: From Zero To Hero

19.6.2.1 Why don’t we delete the matches immediately? . . . . . . . . . . . . . . . . . . .462

19.6.3 Replacing the removed tiles and applying gravity . . . . . . . . . . . . . . . . . . . . . .463

19.7 Cutscenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .465

19.7.1 Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .465

19.7.2 Scripted Cutscenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .465

20 Balancing Your Game 467

20.1 Do not annoy the player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .467

20.2 Favour the player when possible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .467

20.3 Difficulty curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .468

20.3.1 Simple Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .468

20.3.2 Flat Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .468

20.3.2.1 Linear Increase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .469

20.3.2.2 Logarithmic Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .469

20.3.2.3 Exponential Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .470

20.3.3 Wave patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .471

20.3.3.1 Linearly Increasing wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .471

20.3.3.2 Logarithmically Increasing wave . . . . . . . . . . . . . . . . . . . . . . . . . . .471

20.3.4 Interval Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .472

20.3.4.1 Simple Interval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .472

20.3.4.2 Widening Interval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .473

20.3.4.3 Widening Interval with Logarithmic trend . . . . . . . . . . . . . . . . . . . . . .474

20.3.5 This is not everything . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .474

20.3.5.1 Sawtooth pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .474

20.3.5.2 What not to do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475

20.3.5.3 Beyond difficulty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476

20.4 Economy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476

20.4.1 Supply and Demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476

20.4.2 Money sources and sinks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .477

20.4.3 Inflation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .478

20.4.4 Deflation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .478

20.5 A primer on Cheating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .478

20.5.1 Information-based cheating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479

20.5.2 Mechanics-based cheating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479

20.5.3 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479

20.5.4 Low-level exploits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479

20.6 How cheating influences gameplay and enjoyability . . . . . . . . . . . . . . . . . . . . . . . . .480

20.6.1 Single Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480

20.6.2 Multiplayer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480

20.6.2.1 P2P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480

CONTENTS XXI
2D Game Development: From Zero To Hero

20.6.2.2 Dedicated Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .482

20.7 Cheating protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .483

20.7.1 Debug Mode vs Release Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .484

20.8 Some common exploits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .484

20.8.1 Integer Under/Overflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .484

20.8.1.1 How the attack works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .485

20.8.2 Repeat attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .485

21 Accessibility in video games 487

21.1 What accessibility is and what it is not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .487

21.2 UI and HUD Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .487

21.3 Subtitles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .487

21.4 Mappable Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .487

21.5 Button Toggling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.6 Dyslexia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.6.1 Text Spacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.6.2 Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.7 “Slow Mode” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.8 Colorblind mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488

21.9 No Flashing Lights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .489

21.10 No motion blur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .489

21.11 Reduced Motion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .489

21.12 Assisted Gameplay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .489

21.13 Controller Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .489

21.14 Some special cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .490

22 Testing your game 491

22.1 When to test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491

22.1.1 Testing “as an afterthought” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491

22.1.2 Test-Driven Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491

22.1.3 The “Design to test” approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491

22.1.4 You won’t be able to test EVERYTHING . . . . . . . . . . . . . . . . . . . . . . . . . . . .491

22.2 Mocking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .492

22.3 Types of testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .492

22.3.1 Automated Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .492

22.3.2 Manual Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .493

22.4 Unit Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .493

22.5 Integration Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494

22.6 Regression Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494

22.7 Playtesting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494

22.7.1 In-House Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494

CONTENTS XXII
2D Game Development: From Zero To Hero

22.7.2 Closed Beta Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .495

22.7.3 Open Beta Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .495

22.7.4 A/B Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .495

23 Profiling and Optimization 496

23.1 Profiling your game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .496

23.1.1 Does your application really need profiling? . . . . . . . . . . . . . . . . . . . . . . . . .496

23.1.1.1 Does your FPS counter roam around a certain “special” value? . . . . . . . . . . .496

23.1.1.2 Is the animation of your game stuttering but the FPS counter is fine? . . . . . . . .496

23.1.2 First investigations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .496

23.1.2.1 Is your game using 100% of the CPU? . . . . . . . . . . . . . . . . . . . . . . . .496

23.1.2.2 Is your game overloading your GPU? . . . . . . . . . . . . . . . . . . . . . . . .497

23.1.2.3 Is your game eating up more and more RAM as it’s running? . . . . . . . . . . . .497

23.2 Optimizing your game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .498

23.2.1 Working with references vs. returning values . . . . . . . . . . . . . . . . . . . . . . . .498

23.2.2 Optimizing Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499

23.2.2.1 Off-screen objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499

23.2.3 Reduce the calls to the Engine Routines . . . . . . . . . . . . . . . . . . . . . . . . . . .499

23.2.4 Entity Cleanup and Memory leaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500

23.2.5 Using analyzers to detect Memory Leaks . . . . . . . . . . . . . . . . . . . . . . . . . .501

23.2.5.1 Static Scanners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501

23.2.5.2 Dynamic testing tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501

23.2.6 Resource Pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501

23.2.7 Lookup Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .503

23.2.8 Memoization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .503

23.2.9 Approximations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505

23.2.10 Eager vs. Lazy Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .506

23.2.10.1 Eager approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .506

23.2.10.2 Lazy approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .507

23.2.11 Detach your updating from drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . .507

23.3 Tips and tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .508

23.3.1 Be mindful of your “updates” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .508

23.3.2 Use the right data structures for the job . . . . . . . . . . . . . . . . . . . . . . . . . . .508

23.3.3 Dirty Bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .509

23.3.4 Far-Away entities (Dirty Rectangles) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .510

23.3.5 Tweening is better than animating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .510

23.3.6 Remove dead code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .510

23.4 Non-Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .511

23.4.1 “Switches are faster than IFs” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .511

23.4.2 Blindly Applying Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .513

CONTENTS XXIII
2D Game Development: From Zero To Hero

24 Marketing your game 515

24.1 An Important Note: Keep your feet on the ground . . . . . . . . . . . . . . . . . . . . . . . . . .515

24.2 The importance of being consumer-friendly . . . . . . . . . . . . . . . . . . . . . . . . . . . . .515

24.3 Pricing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .516

24.3.1 Penetrating the market with a low price . . . . . . . . . . . . . . . . . . . . . . . . . . .516

24.3.2 Giving off a “premium” vibe with a higher price . . . . . . . . . . . . . . . . . . . . . . .516

24.3.3 The magic of “9” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .517

24.3.4 Launch Prices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .517

24.3.5 Bundling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .517

24.3.6 Nothing beats the price of “Free” (Kinda) . . . . . . . . . . . . . . . . . . . . . . . . . .518

24.4 Managing Hype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .518

24.5 Downloadable Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .518

24.5.1 DLC: what to avoid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519

24.5.2 DLC: what to do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519

24.6 Digital Rights Management (DRM) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519

24.6.1 How DRM can break a game down the line . . . . . . . . . . . . . . . . . . . . . . . . . .521

24.7 Free-to-Play Economies and LootBoxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .521

24.7.1 Microtransactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .521

24.7.1.1 The human and social consequences of Lootboxes . . . . . . . . . . . . . . . . .521

24.7.2 Free-to-Play gaming and Mobile Games . . . . . . . . . . . . . . . . . . . . . . . . . . .522

24.8 Assets and asset Flips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523

24.9 Crowdfunding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523

24.9.1 Communication Is Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524

24.9.2 Do not betray your backers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524

24.9.3 Don’t be greedy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524

24.9.4 Stay on the “safe side” of planning . . . . . . . . . . . . . . . . . . . . . . . . . . . . .525

24.9.5 Keep your promises, or exceed them . . . . . . . . . . . . . . . . . . . . . . . . . . . . .525

24.9.6 A striking case: Mighty No. 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .525

24.10 Engagement vs Fun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .526

24.11 Streamers and Content Creators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .527

24.11.1 The game developers’ side . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .527

24.11.2 The Streamers’ side . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .527

24.11.3 Other entities and conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .528

25 Keeping your players engaged 529

25.1 Communities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529

25.1.1 Forums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529

25.1.2 Wikis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529

25.1.3 Update Previews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529

25.1.4 Speedrunning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .530

CONTENTS XXIV
2D Game Development: From Zero To Hero

25.1.5 Streaming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .531

25.2 Replayability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .531

25.2.1 Modding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .531

25.2.2 Fan games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .532

25.2.3 Mutators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .532

25.2.4 Randomizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .533

25.2.5 New Game+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .533

25.2.6 Transmogrification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .533

26 Dissecting games: three study cases 536

26.1 A bad game: Hoshi wo miru hito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536

26.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536

26.1.2 Balance Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536

26.1.2.1 You can’t beat starter enemies . . . . . . . . . . . . . . . . . . . . . . . . . . . .536

26.1.2.2 The Damage Sponge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536

26.1.2.3 Can’t run away from battles, but enemies can . . . . . . . . . . . . . . . . . . . .537

26.1.2.4 Statistics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .537

26.1.3 Bad design choices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .537

26.1.3.1 You get dropped in the middle of nowhere . . . . . . . . . . . . . . . . . . . . . .537

26.1.3.2 The starting town is invisible . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538

26.1.3.3 The Jump Ability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538

26.1.3.4 Items are invisible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538

26.1.3.5 Item management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538

26.1.3.6 Buying Weapons makes you weaker . . . . . . . . . . . . . . . . . . . . . . . . .538

26.1.3.7 Enemy Abilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.3.8 You can soft lock yourself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.4 Confusing Choices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.4.1 Starting level for characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.4.2 Slow overworld movement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.4.3 Exiting a dungeon or a town . . . . . . . . . . . . . . . . . . . . . . . . . . . . .539

26.1.4.4 The Health Points UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .540

26.1.5 Inconveniencing the player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .540

26.1.5.1 The battle menu order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .540

26.1.5.2 Every menu is a committal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .540

26.1.5.3 Password saves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .540

26.1.5.4 Each character has their own money stash . . . . . . . . . . . . . . . . . . . . .541

26.1.6 Bugs and glitches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .541

26.1.6.1 Moonwalking and save warping . . . . . . . . . . . . . . . . . . . . . . . . . . .541

26.1.6.2 The final maze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .541

26.1.6.3 The endings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .542

CONTENTS XXV
2D Game Development: From Zero To Hero

26.1.7 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .542

26.2 The first good game - VVVVVV: Slim story and essential gameplay . . . . . . . . . . . . . . . . .542

26.2.1 A Slim story that holds up great . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .542

26.2.2 Essential gameplay: easy to learn, hard to master . . . . . . . . . . . . . . . . . . . . . .543

26.2.3 Diversified challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .543

26.2.4 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .543

26.2.5 Amazing soundtrack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .544

26.2.6 Accessibility Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .544

26.2.7 Post-endgame Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .544

26.2.8 User-generated content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .544

26.2.9 “Speedrunnability” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .545

26.2.10 Characters are memorable, even if you don’t see them a lot . . . . . . . . . . . . . . . .545

26.2.11 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .545

26.3 Another good game - Undertale: A masterclass in storytelling . . . . . . . . . . . . . . . . . . . .545

26.3.1 The power of choice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .545

26.3.2 The game doesn’t take itself very seriously (sometimes) . . . . . . . . . . . . . . . . . .545

26.3.3 All the major characters are very memorable . . . . . . . . . . . . . . . . . . . . . . . .546

26.3.4 The game continuously surprises the player . . . . . . . . . . . . . . . . . . . . . . . . .546

26.3.5 Player choices influence the game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .546

26.3.6 Great (and extensive!!) soundtrack . . . . . . . . . . . . . . . . . . . . . . . . . . . . .547

26.3.7 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .547

27 Project Ideas 548

27.1 Tic-Tac-Toe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .548

27.1.1 Basic Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .548

27.1.2 Advanced Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549

27.1.3 Master Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549

27.2 Space Invaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549

27.2.1 Basic Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .550

27.2.2 Advanced Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .551

27.2.3 Master level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .551

27.3 Breakout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552

27.3.1 Basic Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552

27.3.2 Advanced Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552

27.3.3 Master Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553

27.4 Shooter Arena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .554

27.4.1 Basic Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .554

27.4.2 Advanced level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555

27.4.3 Master Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555

28 Game Jams 557

CONTENTS XXVI
2D Game Development: From Zero To Hero

28.1 Have Fun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557

28.2 Stay Healthy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557

28.3 Stick to what you know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557

28.4 Hacking is better than planning (But still plan ahead!) . . . . . . . . . . . . . . . . . . . . . . . .557

28.5 Graphics? Sounds? Music? FOCUS! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558

28.6 Find creativity in limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558

28.7 Involve Your Friends! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .559

28.8 Write a Post-Mortem (and read some too!) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .559

28.9 Most common pitfalls in Game Jams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .559

29 Where To Go From Here 561

29.1 Collections of different topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561

29.1.1 Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561

29.1.2 Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561

29.1.3 Multiple formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561

29.2 Pixel Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.2.1 Multiple Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.3 Sound Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.3.1 Multiple Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.4 Game Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.4.1 Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.5 Game Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.5.1 Web Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.5.2 Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

29.6 References and Cheat Sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .562

A Glossary 564

B Engines, Libraries And Frameworks 568

C Some other useful tools 578

D Free assets and resources 583

E Contributors 586

CONTENTS XXVII
2D Game Development: From Zero To Hero

1 Foreword

Every time we start a new learning experience, we may be showered by a immeasurable amount of doubts and

fears. The task, however small, may seem daunting. And considering how large the field of Game Development can

be, these fears are easily understandable.

This book is meant to be a reference for game developers, oriented at 2D, as well as being a collection of “best

practices” that you should follow when developing a game by yourself (or with some friends).

But you shouldn’t let these “best practices” jail you into a way of thinking that is not yours, actually my first tip in

this book is do not follow this book. Yet.

Do it wrong.

Learn why these best practices exist by experience, make code so convoluted that you cannot maintain it anymore,

don’t check for overflows in your numbers, allow yourself to do it wrong.

Your toolbox is there to aid you, your tools don’t have feelings that can be hurt (although they will grumble at you

many times) in the same way that you cannot hurt a hammer when missing the nail head. You cannot break a

computer by getting things wrong (at least 99.9999% of the time). Breaking the rules will just help you understand

them better.

Write your own code, keep it as simple as you can, and practice.

Don’t let people around you tell you that “you shouldn’t do it that way”, if you allow that to happen you’re depriving

yourself of a great opportunity to learn. Don’t let others’ “lion tamer syndrome” get to you, avoid complex structures

as much as possible; cutting and pasting code will get you nowhere.

But most of all, never give up and try to keep it fun.

There will be times where you feel like giving up, because something doesn’t work exactly as you want it to, or

because you feel you’re not ready to put out some code. When you don’t feel ready, just try making something

simple, something that will teach you how to manipulate data structures and that gives you a result in just a couple

days of work. Just having a rectangle moving on the screen, reacting to your key presses can be that small confidence

boost that can get you farther and farther into this world.

And when all else fails, take a pen, some paper and your favorite Rubber Duck (make sure it is impact-proof) and

think.

Coding is hard, but at the same time, it can give you lots of satisfaction.

I really hope that this book will give you tips, tricks and structures that one day will make you say “Oh yeah, I can

use that!”. So that one day you are able to craft an experience that someone else will enjoy, while you enjoy the

journey that brings to such experience.

1 FOREWORD 1
2D Game Development: From Zero To Hero

2 Introduction
A journey of a thousand miles begins with a single step

Laozi - Tao Te Ching

Welcome to the book! This book aims to be an organized collection of the community’s knowledge on game devel-

opment techniques, algorithms and experience with the objective of being as comprehensive as possible.

2.1 Why another game development book?

It’s really common in today’s game development scene to approach game development through tools that abstract

and guide our efforts, without exposing us to the nitty-gritty details of how things work on low-level and speeding

up and easing our development process. This approach is great when things work well, but it can be seriously

detrimental when we are facing against issues: we are tied to what the library/framework creators decided was the

best (read “applicable in the widest range of problems”) approach to solving a problem.

Games normally run at 30fps, more modern games run at 60fps, some even more, leaving us with between 33ms

to 16ms or less to process a frame, which includes:

• Process the user input;

• Update the player movement according to the input;

• Update the state of any AI that is used in the level;

• Move the NPCs according to their AI;

• Identify Collisions between all game objects;

• React to said Collisions;

• Update the Camera (if present);

• Update the HUD (if present);

• Draw the scene to the screen.

These are only some basic things that can be subject to change in a game, every single frame.

When things don’t go well, the game lags, slows down or even locks up. In that case we will be forced to take the

matter in our hands and get dirty handling things exactly as we want them (instead of trying to solve a generic

problem).

When you are coding a game for any device that doesn’t really have “infinite memory”, like a mobile phone, consoles

or older computers, this “technical low-level know-how” becomes all the more important.

This book wants to open the box that contains everything related to 2D game development, plus some small tips

and tricks to make your game more enjoyable. This way, if your game encounters some issues, you won’t fear diving

into low-level details and fix it yourself.

Or why not, make everything from scratch using some pure-multimedia interfaces (like SDL or SFML) instead of fully

fledged game engines (like Unity).

2 INTRODUCTION 2
2D Game Development: From Zero To Hero

This book aims to be a free (as in price) teaching and reference resource for anyone who wants to learn 2D game

development, including the nitty-gritty details.

Enjoy!

2.2 Conventions used in this book

2.2.1 Logic Conventions

When talking about logic theory, the variables will be represented with a single uppercase letter, written in math

mode: A

The following symbol will be used to represent a logical “AND”: ∧

The following symbol will be used to represent a logical “OR”: ∨

The logical negation of a variable will be represented with a straight line on top of the variable, so the negation of

the variable A will be Ā

2.2.2 Code Listings

Listings, algorithms and anything that is code will be shown in monotype fonts, using syntax highlighting where

possible, inside of a dedicated frame:

Listing 1: Example code listing

1 #i n c l u d e < iostream >

3 void example ( std :: string phrase ){

4 // This is a simple example function


5 std :: cout << phrase << std :: endl ;
6 }
7

8 c l a s s ExampleClass {

9 // This is a simple example class


10 ExampleClass () {
11 // This is an example constructor
12 }
13 };

2.2.3 Block Quotes

There will be times when it’s needed to write down something from another source verbatim, for that we will use

block quotes, which are styled as follows:

Hi, I’m a block quote! You will see me when something is… quoted!

I am another row of the block quote! Have a nice day!

2 INTRODUCTION 3
2D Game Development: From Zero To Hero

2.2.4 Boxes

In your journey through this book, you may find some boxes, let’s see which ones you may come across.

Tip!

This is a tip box, here you will find tips that are loosely related to the chapter at hand.

These small tips will help you make a better game, or wiggle your way through some-

thing difficult.

Pitfall Warning!

This is a pitfall box, it will warn you of traps behind the corner, as well as possible

shortcomings of a certain solution.

Random Trivia!

This is a trivia box, it will give out some small facts that can help you understand things

better, or just give you a small break from all the learning.

Note!

This is just a note box, it’s not a pitfall, a tip or a trivia. This is used for reminders and

just as a general purpose note

Advanced Wizardry!

This will warn you of complex sections, or sections treating advanced topics that have

limited game development usefulness. Such sections may be skimmed over.

2.2.5 Engine Used

Most editions of this book does not use any engine. All algorithms will be presented pretending there is some

“generic engine” behind the scenes that handles sprites, vectors and the like. The objective of this book is teaching

algorithms, tips and tricks and game design in the most engine-agnostic (and language-agnostic, if you’re looking

at the “pseudocode edition”) way possible.

If instead you’re reading a version that features “language extensions”, all algorithms will be in your favourite

language, using your favourite engine.

2 INTRODUCTION 4
2D Game Development: From Zero To Hero

2.2.6 About editions

This book comes in various editions, and they come with some caveats.

• Pseudocode Edition: This is the standard edition, using a C-like syntax that tries to be as readable as

possible and abstracts itself from any kind of engine.

• Python Edition: Python is considered one of the easiest language to start coding on. Many tend to complain

about its performance, but its similarity to Godot Engine’s GDScript and its flexibility make it a good candidate

for starters.

• C++ Edition: C++ is probably the most used language in game development (along with C#) but it can be

really difficult to manage. It has no garbage collection, forcing you to manage the memory manually, and

pointers can prove to be a difficult concept for many.

• JavaScript Edition: Javascript is the de-facto “internet language” and its influence is spreading to desktop

applications and video games too. Many games now can be played on the browser thanks to it and the HTML5

canvas elements. This is a language that can be very forgiving and frustrating at the same time.

• Lua Edition: Lua is one of the most spread scripting languages in the world of video games. Since it has a very

small interpreter, it can be added to a lot of code bases without weighing them down much. It is not a proper

object-oriented language, but it has very strong metaprogramming capabilities (where you can “program the

programming language”). There are also some libraries that allow for classes and object-oriented concepts

to fit in Lua.

2.3 Structure of this Book

This book is structured in many chapters, here you will find a small description of each and every one of them.

• Foreword: You didn’t skip it, right?

• Introduction: Here we present the structure of the book and the reasons why it came to exist. You are

reading it now, hold tight, you’re almost there!

• The Maths Behind Game Development: Here we will learn the basic maths that are behind any game, like

vectors, matrices and screen coordinates.

• Some Computer Science Fundamentals: Here we will learn (or revise) some known computer science

fundamentals (and some less-known too!) and rules that will help us managing the development of our game.

• A game design dictionary: Here we will introduce some basic concepts that will help us in understanding

game design: platforms, input devices and genres.

• Project Management Basics and Tips: Project management is hard! Here we will take a look at some

common pitfalls and tips that will help us deliver our own project and deliver it in time.

• Writing a Game Design Document: In this section we will take a look at one of the first documents that

comes to exist when we want to make a game, and how to write one,

• The Game Loop: Here we will learn the basics of the “game loop”, the very base of any video game.

• Collision Detection and Reaction: In this section we will talk about one of the most complex and compu-

tationally expensive operations in a video game: collision detection.

• Scene Trees: Here we will briefly talk about probably the most important structure in games and game

2 INTRODUCTION 5
2D Game Development: From Zero To Hero

engines: the scene tree.

• Cameras: In this section we will talk about the different types of cameras you can implement in a 2D game,

with in-depth analysis and explanation.

• Game Design Tips: In this chapter we will talk about level design and how to walk your player through the

learning and reinforcement of game mechanics, dipping our toes into the huge topic that is game design.

• Creating your own assets: Small or solo game developers may need to create their own assets, in this

section we will take a look at how to create our own graphics, sounds and music.

• Design Patterns: A head-first dive into the software engineering side of game development, in this section

we will check many software design patterns used in many games.

• Useful Containers and Classes: A series of useful classes and containers used to make your game more

maintainable and better performing.

• Artificial Intelligence in Video games: In this section we will talk about algorithms that will help you coding

your enemy AI, as well as anything that must have a “semblance of intelligence” in your video game.

• Other Useful Algorithms: In this section we will see some algorithms that are commonly used in game,

including path finding, world generation and more.

• Procedural Content Generation: In this chapters we will see the difference between procedural and random

content generation and how procedural generation can apply to more things than we think.

• Developing Game Mechanics: Here we will dive into the game development’s darkest and dirtiest secrets,

how games fool us into strong emotions but also how some of the most used mechanics are implemented.

• Balancing Your Game: A very idealistic vision on game balance, in this chapter we will take a look inside

the player’s mind and look at how something that may seem “a nice challenge” to us can translate into a

“terrible balance issue” to our players.

• Accessibility in video games: Here we will learn the concept of “accessibility” and see what options we

can give to our players to make our game more accessible (as well as more enjoyable to use).

• Testing your game: This section is all about hunting bugs, without a can of bug spray. A deep dive into the

world of testing, both automated and manual.

• Profiling and Optimization: When things don’t go right, like the game is stuttering or too slow, we have to

rely on profiling and optimization. In this section we will learn tips and tricks and procedures to see how to

make our games perform better.

• Marketing Your Game: Here we will take a look at mistakes the industry has done when marketing and

maintaining their own products, from the point of view of a small indie developer. We will also check some of

the more controversial topics like loot boxes, micro transactions and season passes.

• Keeping your players engaged: a lot of a game’s power comes from its community, in this section we will

take a look at some suggestion you can implement in your game (and out-of-game too) to further engage your

loyal fans.

• Dissecting Games: A small section dedicated to dissecting the characteristics of one (very) bad game, and

two (very) good games, to give us more perspective on what makes a good game “good” and what instead

makes a bad one.

• Project Ideas: In this section we take a look at some projects you can try and make by yourself, each project

is divided into 3 levels and each level will list the skills you need to master in order to be able to take on such

2 INTRODUCTION 6
2D Game Development: From Zero To Hero

level.

• Game Jams: A small section dedicated on Game Jams and how to participate to one without losing your mind

in the process, and still deliver a prototype.

• Where to go from here: We’re at the home stretch, you learned a lot so far, here you will find pointers to

other resources that may be useful to learn even more.

• Glossary: Any world that has a g symbol will find a definition here.

• Engines and Frameworks: A collection of frameworks and engines you can choose from to begin your game

development.

• Tools: Some software and tool kits you can use to create your own resources, maps and overall make your

development process easier and more manageable.

• Premade Assets and resources: In this appendix we will find links to many websites and resource for

graphics, sounds, music or learning.

• Contributors: Last but not least, the names of the people who contributed in making this book.

Have a nice stay and let’s go!

2 INTRODUCTION 7
Part 1: The basics
2D Game Development: From Zero To Hero

3 The Maths Behind Game Development

Do not worry about your difficulties in Mathematics. I can assure you mine

are still greater.

Albert Einstein

This book assumes you already have some knowledge of maths, but we will also try to keep the bar of entry as low

as possible.

Also we will represent derivatives with the f ′ (x) symbol, instead of the more verbose ∂f
∂x .

In this chapter we’ll take a quick look (or if you already know them, a refresher) on the basic maths needed to make

a 2D game.

3.1 Some useful symbols

While reading this book, we may need to delve into some mathematical lingo that not everyone may understand

immediately, so here’s a small glossary of some of mathematical the symbols we may use.

• x∈S Denotes a “set membership”, so the object to the left of the symbol is an element of the set at the

right: x is an element inside the set S;

• A⊂B Denotes a “subset relationship”: A is a subset of B;

• A ⊆ B Denotes a “subset relationship” where equality is possible: A is a subset of B, but also it may happen

that A equals B;

• A∪B Denotes “set union”, the result is composed by all elements of A and B, combined;

• A∩B Denotes “set intersection”, the result is composed by all elements of A that are also found in B;

• ∀ Means “for all”;


• ∃ Means “exists”;
• ∃! Means “exists only one”;
• P → Q Means “implies”, so you can read this as “P implies Q” or “if P is true then Q is true”;
• P ↔ Q Logical equivalence: means “if and only if” or “is equivalent”, so you can read this as “P is equivalent

to Q” or “P if and only if Q”;

3.2 The modulo operator

Very basic, but sometimes overlooked, function in mathematics is the “modulo” function (or “modulo operator”).

Modulo is a function that takes 2 arguments, let’s call them “a” and “b”, and returns the remainder of the division

represented by a/b.

So we have examples like mod(3, 2) = 1 or mod(4, 5) = 4 and mod(8, 4) = 0.

In most programming languages the modulo function is hidden behind the operator “%”, which means that the

function mod(3, 2) is represented with 3%2.

The modulo operator is very useful when we need to loop an ever-growing value between two values (as will be

3 THE MATHS BEHIND GAME DEVELOPMENT 9


2D Game Development: From Zero To Hero

shown in infinitely scrolling backgrounds).

Pitfall Warning!

Be careful when using the modulo operator with negative arguments: it may lead to

unexpected results, which may depend on the programming language you are using.

3.3 Powers and Roots

We start our revision of maths by remembering powers and roots. A power is just a short way to multiply a number

by itself a certain amount of times.

For example: 23 = 2 · 2 · 2 = 8, 2 is multiplied by itself 3 times, giving 8 as a result.

Some other examples can be 44 = 4 · 4 · 4 · 4 = 256 and 09532 = 0 · 0 · ... · 0 = 0

One rule that we need to remember is that any number, when elevated to the zero-th power is always 1, so 2560 =1
as well as 20 = 1.

Note!

Technically 00 might be considered “undefined”, but in most non-rigorous mathemati-

cal environments 00 = 1 is accepted.


Roots are the inverse operation of powers, which means that if 42
2
= 16 then 16 = 4

So we can say that

The nth root of a number x is a number r so that r n =x


3

4

9532
Taking the examples of earlier, we have that 8 = 2, 4 = 4 and 0 = 0. Omitting the index n on the root is
a short way to write the “square root”, which is the root with index 2. That means:


2

4= 4=2

Pitfall Warning!

When talking “real numbers”, there is no −1: that would fall into the “complex num-

bers” category, which are a matter outside the scope of this revision. That’s because

there is no real number that multiplied by itself an even amount of times that would

give a negative number. To make things more complex, roots with odd indices of nega-

tive numbers are part of the real numbers instead:
3
−8 = −2 because (−2)3 = −8

3 THE MATHS BEHIND GAME DEVELOPMENT 10


2D Game Development: From Zero To Hero

3.4 Equations

Equations are a way to express equality between two expressions, we’ve seen equations all our lives, just “hidden”.

Every operation is an equation.

In their more known form, equations can have one or more “unknowns”, usually represented with letters (the most

used are, in order x, y and z) and “solving an equation” means finding values for the unknowns that make the

equation true.

Here’s a simple equation:

2 · x = 10

Which can be read as “x is the number, that multiplied by 2, gives 10”, the solution of this equation is x = 5, because
2 · 5 = 10.

There are some basic rules, here’s a quick rundown.

3.4.1 You can add or subtract any number on both sides

This is one of the rules that will help us making things a bit easier. Let’s take the following example:

15 + 2x = 45

We can subtract 15 on both sides to make our life easier:

−15 + 15 + 2x = 45 − 15

2x = 30

3.4.2 You can multiple or divide any non-zero number on both sides

This is another one of those rules that makes things a lot easier, taking the previous example:

2x = 30

We can divide each side by 2 (or multiply it by 1


2 ) to get to the final result:

1 1
· 2x = 30 ·
2 2
2x 30
=
2 2

3 THE MATHS BEHIND GAME DEVELOPMENT 11


2D Game Development: From Zero To Hero

x = 15

3.5 Exponentiations and Logarithms

Similarly to powers involving simple numbers, we can involve letters in powers too, making them “exponentiations”.

2x = 32

In this case x is the number that makes the previous equation true (by the way, the result is x = 5).

Its inverse is called a “logarithm”, and it’s represented as follows:

log2 32 = x

In the previous example “2” is called the “base” of the logarithm. So this formula is read as “x is the base 2 logarithm

of 32” (the result is still 5, by the way).

Here is a quick table of rules that can be used to make logarithms easier to calculate.

Table 1: Some rules that would help us calculating logarithms

Rule Formula

Product logb (x · y) = logb x + logb y


Quotient logb ( xy ) = logb x − logb y
Power logb (xp ) = p · logb x

Root logb ( p x) = logpb x

3.6 Limits
Advanced Wizardry!

We’re entering some complex math territory here, so I will give you an “intuitive” defi-

nition of a limit. Having an idea of what it is will suffice for the needs of this book

Limits are an interesting beast: we can see them as the value a function approaches as the input approaches some

value. Limits are written as follows:

lim f (x) = y
x→a

3 THE MATHS BEHIND GAME DEVELOPMENT 12


2D Game Development: From Zero To Hero

In this case it can be read as “y is the limit, for x approaching a, of f (x)”. Limits can be seen as, “the more x gets

closer to a, the more f (x) gets closer to y”.

y and a can be any value, including infinity. In fact the following statement is true:

lim x = +∞
x→+∞

The further we count down the line of numbers the closer we get to infinity. Which also means that:

1
lim =0
x→+∞ x

Because as we are counting up with x, we are dividing 1 by bigger and bigger numbers until (at the limit) we reach

0.

Pitfall Warning!

There are some situations where a limit cannot be determined immediately (or some-
∞ 0
times at all). Some of these are +∞ − ∞, 0 · ∞, ∞, 0, ∞0 , 00 and 1∞ .

3.7 Derivatives
Note!

This is not a complete guide to derivatives, there is so much more to it than written

in here. This is mostly for informational purposes when the term “derivative” will be

used in this book.

Derivatives are technically just a limit, to be precise they are the following limit:

f (x + h) − f (h)
lim
h→0 h

They also have a nifty property that is used extensively in calculus: if f ′ (x) > 0 then f (x) is increasing, while if
′ ′
f (x) < 0 then f (x) is decreasing. This means that the equation f (x) = 0 can be used to find local extrema: also

known as “local minimums” and “local maximums”.

There are some rules to quickly derivative functions, here we list some of the most basic.

3 THE MATHS BEHIND GAME DEVELOPMENT 13


2D Game Development: From Zero To Hero

Table 2: Some simple derivation rules (k is any constant number and e is Euler’s number)

Function Derivative

k 0
x k
k · xk−1
ex ex

Then there are rules for sums, multiplications and divisions.

Table 3: Some derivation rules for combined functions (a and b are constants)

Functions Derivative

af (x) + bg(x) af ′ (x) + bg ′ (x)


f (x)g(x) f ′ (x)g(x) + f (x)g ′ (x)
f (x) f ′ (x)g(x)−f (x)g ′ (x)
g(x) (g(x))2

f (g(x)) f ′ (g(x)) · g ′ (x)

3.8 The Cartesian Plane

The Cartesian plane is a plane that features a 2-dimensional coordinate system. This way we can represent points

with a pair of coordinates (x, y).

II y I
8

-8 -7 -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 7 8

-1
x
-2

-3

-4

-5

-6

-7

III -8
IV

Figure 1: Example of a Cartesian plane

3 THE MATHS BEHIND GAME DEVELOPMENT 14


2D Game Development: From Zero To Hero

Using a Cartesian plane we can represent the position of items, as well as their shape, space occupation, as well as

vectors that represent forces, velocity and direction.

It is an essential tool for 2D game development, and it will be one of the abstractions we will use to represent items

in a 2-Dimensional plane.

3.9 Vectors

For our objective, we will simplify the complex matter that is vectors as much as possible.

In the case of 2D game development, a vector is just a pair of values (x,y).

Vectors usually represent a force applied to a body, its velocity or acceleration and are graphically represented with

an arrow.

On a Cartesian plane it can be seen as “the x and y quantities you need to move to get from a point to another”.

y I
8

1
(4,1)
1 2 3 4 5 6 7 8

x
Figure 2: Image of a vector

From the previous example, the vector v = (4, 1) can be thought of as the following:

you need to move 4 units on the x axis and 1 on the y axis to go from the origin to the point P (4, 1)

The pain of learning about vectors is paid off by their capacity of being added and subtracted among themselves,

as well as being multiplied by a number (called a “scalar”) and between themselves.

3.9.1 Adding and Subtracting Vectors

Adding vectors is as easy as adding its “members”. Let’s consider the following vectors:

v = (4, 1)

u = (1, 4)

The sum vector s will then be:

s = v + u = (4 + 1, 1 + 4) = (5, 5)

3 THE MATHS BEHIND GAME DEVELOPMENT 15


2D Game Development: From Zero To Hero

Graphically it can be represented by placing the tail of the arrow v on the head of the arrow u, or vice-versa:

y I
8

1 2 3 4 5 6 7 8

x
Figure 3: Graphical representation of a sum of vectors

A different example could be the following:

v = (2, 4)

u = (1, 5)

The sum vector s will be:

s = u + v = (2 + 1, 4 + 5) = (3, 9)

3.9.2 Scaling Vectors

There may be situations where you need to make a vector x times longer. This operation is called “scalar multipli-

cation” and it is performed as follows:

v = (1, 2)

3 · v = (1 · 3, 2 · 3) = (3, 6)

y I
8

1 2 3 4 5 6 7 8

x
Figure 4: Example of a vector multiplied by a value of 3

Obviously this works with scalars with values between 0 and 1:

3 THE MATHS BEHIND GAME DEVELOPMENT 16


2D Game Development: From Zero To Hero

v = (4, 2)

1
2 · v = ( 12 · 4, 12 · 2) = (2, 1)

y I
8

1 2 3 4 5 6 7 8

x
Figure 5: Example of a vector multiplied by a value of 0.5

When you multiply the vector by a value less than 0, the vector will rotate by 180°.

v = (1, 2)

−2 · v = (−2 · 1, −2 · 2) = (−2, −4)

y I
8

1 2 3 4 5 6 7 8

x
Figure 6: Example of a vector multiplied by a value of -2

3.9.3 Dot Product

The dot product (or scalar product, projection product or inner product) is defined as follows:

Given two n-dimensional vectors v = [v1 , v2 , ...vn ] and u = [u1 , u2 , ..., un ] the dot product is defined as:


n
v·u= (vi · ui ) = (v1 · u1 ) + ... + (vn · un )
i=1

So in our case, we can easily calculate the dot product of two two-dimensional vectors v = [v1 , v2 ] and u = [u1 , u2 ]
as:

3 THE MATHS BEHIND GAME DEVELOPMENT 17


2D Game Development: From Zero To Hero

v · u = (v1 · u1 ) + (v2 · u2 )

Let’s make an example:

Given the vectors v = [1, 2] and u = [4, 3], the dot vector is:

v · u = (1 · 4) + (2 · 3) = 4 + 6 = 10

3.9.4 Vector Length and Normalization

Given a vector a = [a1 , a2 , ..., an ], you can define the length of the vector as:


||a|| = a21 + a22 + ... + a2n

Or alternatively


||a|| = a·a

We can get a 1-unit long vector by “normalizing” it, getting a vector that is useful to affect (or indicate) direction

without affecting magnitude. A normalized vector is usually indicated with a “hat”, so the normalized vector of

a = [a1 , a2 , ..., an ] is

a
â =
||a||

Knowing that the length of a vector is a scalar (a number, not a vector), normal scalar multiplication rules apply.

(See Scaling Vectors)

3.9.5 “Clamping” a Vector

This is not an operation “per se”, but there are occasions where we need to limit the length of a vector: this usually

happens when we are working with velocity, as not limiting it would allow an object to change position faster and

faster, making the game less playable and even breaking time-stepping collision detection algorithms.

To clamp a vector, we need to find its magnitude and direction first, which is the “normalized vector”. Let’s think

about the vector v , its magnitude and direction are:


||v|| = v·v
v
v̂ =
||v||

3 THE MATHS BEHIND GAME DEVELOPMENT 18


2D Game Development: From Zero To Hero

After that, we can build a new vector using the “clamped magnitude” (which we’ll call ||v||clamp ), calculated as such:



||v|| when ||v|| < ||v||max
||v||clamp =

||v||max otherwise

To build the new vector, we just need to multiply ||v||clamp by v̂ :

vclamp = ||v||clamp · v̂

The new vector will have the same direction as the old one, but its magnitude will be clamped, just like we wanted.

3.10 Geometry

Among all the maths we found so far (and the maths we will explain later), we cannot avoid talking a bit about

geometry: in this book we will talk about the minimal amount of geometry necessary to understand the underlying

concepts of what’s coming up.

3.10.1 Convex vs Concave polygons

A polygon is considered convex essentially when any line (not tangent to an edge or corner) drawn through the

shape crosses the shape itself only twice (at its ends).

C B

D A

E F
Figure 7: Example of a convex shape

Any shape where you can find at least one line that crosses the shape more than twice is considered “non-convex”

(commonly referred as “concave”).

3 THE MATHS BEHIND GAME DEVELOPMENT 19


2D Game Development: From Zero To Hero

B
C

A
D
G

E F
Figure 8: Example of a concave shape

Note!

Not all non-convex shapes are technically called “concave” (they should be called “non-

convex”), but for the sake of simplicity we’ll use the term “non-convex” and “concave”

interchangeably in this book.

3.10.2 Self-intersecting polygons

Contrary to what many think, polygons can self-intersect too, which can make calculations a lot harder.

C
A

B
D
Figure 9: Example of a self-intersecting polygon

For the sake of game development, we will usually talk about simple polygons which are polygons that don’t self-

intersect and have no holes in them. More strictly we will (for 99.9% of the time) talk about convex simple poly-

gons.

3.10.3 Straight Lines and their equations

One of the main topics we will encounter over and over in our game development adventure will be “straight lines”.

We will need to draw them, see if two straight lines collide, project stuff onto them, and much more. So it’s important

that we know them well.

3 THE MATHS BEHIND GAME DEVELOPMENT 20


2D Game Development: From Zero To Hero

Here’s a straight line:

ax + by + c = 0

That’s not what you expected, right? What you’ve seen is the “general form” of a straight line’s equation, because

you can represent lines using equations (also circles, and other stuff). This is not a much-used form, though, probably

the most used form is called the “slope-intercept form”:

y = mx + q

Random Trivia!

To transform a “general form” equation into the relative “slope-intercept from” just

remember the following formulas:

a c
m=− q=−
b b
This doesn’t work well when b = 0, which will be subject of the next “pitfall”.

Where in this case m is the slope of our straight line, and q represents the so-called y-intercept (the value of y when

x = 0). If q = 0 the line goes through the origin of the Cartesian coordinate system, if m = 0 the line is horizontal.

Pitfall Warning!

“Vertical straight lines” is where the slope-intercept form fails, in fact vertical straight

lines have an equation in the form of x = k , which would mean that b = 0 which is
problematic (see previous trivia).

3.10.3.1 Getting the equation of a straight line, given two points

We all know that given two points we can strike one and only one line. How many times did you measure two points

(maybe while doing some D.I.Y.) and stroke a line between them?

It will be useful in our adventure to be able to get the equation of a straight line starting from two points, so let’s call

our two points P (x1 , y1 ) and Q(x2 , y2 ), then the straight line that crosses both those points will have equation:

y − y1 y2 − y 1
=
x − x1 x2 − x1

This may seem really complicated, but with some small calculations we can reach a formula for our straight line in

any form (generic or “slope-intercept”).

3 THE MATHS BEHIND GAME DEVELOPMENT 21


2D Game Development: From Zero To Hero

Pitfall Warning!

Again, this formula fails when we are dealing with “vertical lines”, because the denom-

inator at the right side of the equation will be zero. But in that case we’ll already know

the formula: it will be x = x1 (which in turn will be equal to x2 )

3.10.3.2 Getting the equation, given the slope and a point

If we have a point P (xp , yp ) and the slope m (for instance if we need to find a line perpendicular to another line),
in that case we can use the following formula:

y − yp = m(x − xp )

Pitfall Warning!

Guess what? This (again) doesn’t allow us to create “vertical lines”, because we need

a slope value, which we don’t have when it comes to vertical lines. You can see (non

rigorously) a vertical line as a line with “infinite slope”.

3.10.4 Projections

In some situations (as you will see in the SAT), we may need to get to project polygons onto a line, this usually

involves projecting points to a line.

Given the formulas we’ve seen earlier, and doing some thinking, we can easily project a point onto any straight line.

Let’s see how to do it.

First of all, the line we will be projecting onto will have equation y = mx + q , just as in the slope-intercept formula.

We will assume that we have a point P (xp , yp ) that we want to project onto a line r with equation y = mx + q ,
with m ̸= 0 (thus excluding horizontal lines). We will call the projected point “P onto r” with the name Pr (xr , yr ).

3 THE MATHS BEHIND GAME DEVELOPMENT 22


2D Game Development: From Zero To Hero

Pr

r
Figure 10: Projecting the point P onto the line r

First, we need to find the line that goes through P and is perpendicular to r , this is really easy. To find a slope m1
of a line perpendicular to another line with slope m we use the formula

1
m1 = −
m

Pitfall Warning!

This is why we excluded the case m = 0 (horizontal lines), if we didn’t we would have
1
the chance of having m1 = 0 which doesn’t make sense.
In this case we can easily conclude that if m = 0, the projection of the point P onto

the line r has coordinates (xP , y) (with y taken from the line we’re projecting onto).

Now we have a point and a slope, so we can use one of the formulas we’ve already seen to find the line with that

slope that crosses P:

1
y − yp = m1 (x − xp ) ⇔ y − yp = − (x − xp )
m

To find Pr we just need to find the point where the two lines collide, which is the solution to the equation system:



y = mx + q

y − yp = − 1 (x − xp )
m

Which finds solution in:

3 THE MATHS BEHIND GAME DEVELOPMENT 23


2D Game Development: From Zero To Hero



x = xp +myp −mq
m2 +1

y = mxp +m2 yp +q
m2 +1

The coordinates x and y we just found are actually the coordinates xr and yr of our projected point Pr .

Pitfall Warning!

Due to the fact that we used m1 = − m


1
the previous results are not valid for m = 0.
2
The denominator of the results gives no issue, since m + 1 = 0 does not have a solu-
tion in real numbers (and we won’t need to delve into the Complex number territory).

3.10.4.1 Projecting arbitrary lines on the axes

Similarly to what we’ve done with points, we can project arbitrary lines (or, to be precise, the ends of such lines)

onto the axes. This will help us in doing some calculations later (when we’ll talk about SAT).

To project any line r to the x-axis we can just “pass all the line’s points through” the following function:

projx (Pr (x, y)) = (x, 0)

for each point Pr in the line r .

If we want to project such line on the y-axis, we can just use this other function:

projy (Pr (x, y)) = (0, y)

for each point Pr in the line r .

We can see an intuitive representation of projecting a line onto the axes below:

3 THE MATHS BEHIND GAME DEVELOPMENT 24


2D Game Development: From Zero To Hero

y I
8

1 2 3 4 5 6 7 8

x
Figure 11: Projecting a line onto the axes

3.10.4.1.1 How does it work?

Let’s take the point P (2, 5) from the previous figure. We want to project it on the x axis: that means we need to

find a line that is 90 degrees with the x axis and passes through P .

Such line is the line with equation x = 2, now to find the projection of P onto the x axis, we will just need to solve a
simple equation system.



x = 2

y = 0

Where y = 0 is the equation of the x axis. So our projected point is Px (2, 0).

Similar thing goes for projecting the point on the y axis: the line that is 90 degrees with the y axis and goes through

P has equation y = 5, the y axis has equation x = 0, thus the system of equation is solved with Py (0, 5).

3.11 Matrices

3.11.1 What is a matrix

Matrices are essentially an m × n array of numbers, which are used to represent linear transformations.

Here is an example of a 2 × 3 matrix.

 
2 1 4
A2,3 =  
3 2 0

3 THE MATHS BEHIND GAME DEVELOPMENT 25


2D Game Development: From Zero To Hero

3.11.2 Matrix sum and subtraction

Summing and subtracting m×n matrices is done by summing or subtracting each element, here is a simple example.

Given the following matrices:

   
2 1 4 1 3 0
A2,3 =   B2,3 =  
3 2 0 4 2 4

We have that:

       
2 1 4 1 3 0 2+1 1+3 4+0 3 4 4
A2,3 + B2,3 =  + = = 
3 2 0 4 2 4 3+4 2+2 0+4 7 4 4

3.11.3 Multiplication by a scalar

Multiplication by a scalar works in a similar fashion to vectors, given the matrix:

 
2 1 4
A2,3 =  
3 2 0

Multiplication by a scalar is performed by multiplying each member of the matrix by the scalar, like the following

example:

     
2 1 4 3·2 3·1 3·4 6 3 12
3 · A2,3 = 3 ·  = = 
3 2 0 3·3 3·2 3·0 9 6 0

3.11.4 Transposition

Given an m × n matrix A, its transposition is an n × m matrix AT constructed by turning rows into columns and

columns into rows.

Given the matrix:

 
2 1 4
A2,3 =  
3 2 0

The transpose matrix is:

 
2 3
 
 
AT2,3 = 1 2
 
4 0

3 THE MATHS BEHIND GAME DEVELOPMENT 26


2D Game Development: From Zero To Hero

3.11.5 Multiplication between matrices

Given 2 matrices with sizes m × n and n × p (mind how the number of rows of the first matrix is the same of the
number of columns of the second matrix):

 
2 3  
 
  2 3 4
A3,2 = 1 2 B2,3 =  
  0 1 0
4 0

We can calculate the multiplication between these two matrices, in the following way.

First of all let’s get the size of the resulting matrix, which will be always m × p.

Now we have the following situation:

   
2 3   ? ? ?
   
  2 3 4
= 
1 2 ×  ? ? ?
  0 1 0  
4 0 ? ? ?

Matrix multiplication is called a “rows by columns” multiplication, so to calculate the first row - first column value

we’ll need the first row of one matrix and the first column of the other.

   
2 3   ? ? ?
   
  2 3 4
= 
1 2 ×  ? ? ?
  0 1 0  
4 0 ? ? ?

The values in the example will be combined as follows:

2·2+3·0=4

Obtaining the following:

   
2 3   4 ? ?
   
  2 3 4
= 
1 2 ×  ? ? ?
  0 1 0  
4 0 ? ? ?

Let’s try the next value:

3 THE MATHS BEHIND GAME DEVELOPMENT 27


2D Game Development: From Zero To Hero

   
2 3   4 ? ?
   
  2 3 4
= 
1 2 ×  ? ? ?
  0 1 0  
4 0 ? ? ?

The values will be combined as follows:

2·3+3·1=9

Obtaining:

   
2 3   4 9 ?
   
  2 3 4  
1 2  ×   = ? ? ?
  0 1 0  
4 0 ? ? ?

Same goes for the last value, when we are done with the first row, we keep going similarly with the second row:

   
2 3   4 9 8
   
  2 3 4
= 
1 2 ×  ? ? ?
  0 1 0  
4 0 ? ? ?

Which leads to the following calculation:

1·2+2·0=2

Which we will insert in the result matrix:

   
2 3   4 9 8
   
  2 3 4
= 
1 2 ×  2 ? ?
  0 1 0  
4 0 ? ? ?

You can try completing this calculation yourself, the final result is as follows:

   
2 3   4 9 8
   
  2 3 4
= 
1 2 ×  2 5 4
  0 1 0  
4 0 8 12 16

3 THE MATHS BEHIND GAME DEVELOPMENT 28


2D Game Development: From Zero To Hero

Note!

Multiplication between matrices is non commutative, which means that the result of

A×B is not equal to the result of B × A: actually one of the results may not even

be possible to calculate.

3.11.6 Other uses for matrices

Matrices can be used to quickly represent equation systems, with equation that depend on each other. For instance:

 
  x  
2 3 6  

 4
  y  =  
1 4 9   5
z

Can be used to represent the following system of equations:



2x + 3y + 6z = 4

1x + 4y + 9z = 5

Or, as we’ll see, matrices can be used to represent transformations in the world of game development.

3.12 Trigonometry

When you want to develop a game, you will probably find yourself needing to rotate items relative to a certain point

or relative to each other. To do so, you need to know a bit of trigonometry, so here we go!

3.12.1 Radians vs Degrees

In everyday life, angles are measured in degrees, from 0 to 360 degrees. In some situations in maths, it is more

comfortable to measure angles using radians, from 0 to 2π .

You can convert back and forth between radians and degrees with the following formulas:

180
angle in degrees = angle in radians ·
π

π
angle in radians = angle in degrees ·
180

This book will always refer to angles in radians, so here are some useful conversions, ready for use:

3 THE MATHS BEHIND GAME DEVELOPMENT 29


2D Game Development: From Zero To Hero

Table 4: Conversion between degrees and Radians

Degrees Radians

0° 0
π
30° 6
π
45° 4
π
60° 3
π
90° 2

180° π
360° 2π

3.12.2 Sine, Cosine and Tangent

The most important trigonometric functions are sine and cosine. They are usually defined in reference to a “unit

circle” (a circle with radius 1).

Given the unit circle, let a line through the origin with an angle θ with the positive side of the x-axis intersect such
unit circle. The x coordinate of the intersection point is defined by the measure cos(θ), while the y coordinate is

defined by the measure sin(θ).

II y I

-1 1

-1

III IV

Figure 12: Unit Circle definition of sine and cosine

For the purposes of this book, we will just avoid the complete definition of the tangent function, and just leave it as

a formula of sine and cosine:

sin(θ)
tan(θ) =
cos(θ)

3 THE MATHS BEHIND GAME DEVELOPMENT 30


2D Game Development: From Zero To Hero

3.12.3 Pythagorean Trigonometric Identity

One of the most important identities in Trigonometry is the “Pythagorean Trigonometric Identity”, which is expressed

as follows, valid for each angle θ :

sin2 (θ) + cos2 (θ) = 1

Using this identity, you can express functions in different ways:

cos2 (θ) = 1 − sin2 (θ)

sin2 (θ) = 1 − cos2 (θ)

Also remember that sin2 (θ) = (sin(θ))2 and cos2 (θ) = (cos(θ))2 .

3.12.4 Reflections

Sometimes we may need to reflect an angle to express it in an easier way, and their trigonometric formulas will be

affected, so the following formulas may come of use:

Table 5: Some reflection formulas for trigonometry

Reflection Formulas

sin(−θ) = −sin(θ)
cos(−θ) = cos(θ)
sin( π2 − θ) = cos(θ)
cos( π2 − θ) = sin(θ)
sin(π − θ) = sin(θ)
cos(π − θ) = −cos(θ)
sin(2π − θ) = −sin(θ) = sin(−θ)
cos(2π − θ) = cos(θ) = cos(−θ)

3.12.5 Shifts

Trigonometric functions are periodic, so you may have an easier time calculating them when their arguments are

shifted by a certain amount. Here we can see some of the shift formulas:

3 THE MATHS BEHIND GAME DEVELOPMENT 31


2D Game Development: From Zero To Hero

Table 6: Some Shift Formulas for Trigonometry

Shift Formulas

sin(θ ± π2 ) = ±cos(θ)
cos(θ ± π2 ) = ∓sin(θ)
sin(θ + π) = −sin(θ)
cos(θ + π) = −cos(θ)
sin(θ + k · 2π) = sin(θ)
cos(θ + k · 2π) = cos(θ)

3.12.6 Trigonometric Addition and subtraction

Sometimes you may need to express a trigonometric formula with a complex argument by splitting such argument

into different trigonometric formulas. If such argument is a sum or subtraction of angles, you can use the following

formulas:

Table 7: Some addition and difference identities in trigonometry

Addition/Difference Identities

sin(α ± β) = sin(α)cos(β) ± cos(α)sin(β)


cos(α ± β) = cos(α)cos(β) ∓ sin(α)sin(β)

3.12.7 Double-Angle Formulae

Other times (mostly on paper) you may have an argument that is a multiple of a known angle, in that case you can

use double-angle formulae to calculate them.

Table 8: Some double-angle formulae used in trigonometry

Double-Angle Formulae

sin(2θ) = 2sin(θ)cos(θ)
cos(2θ) = cos2 (θ) − sin2 (θ)

3.12.8 Inverse Formulas

As with practically all maths formulas, there are inverse formulas for sine and cosine, called arcsin and arccos,
which allow to find an angle, given its sine and cosine.

In this book we won’t specify more, besides what could be the most useful: the 2-argument arctangent.

3 THE MATHS BEHIND GAME DEVELOPMENT 32


2D Game Development: From Zero To Hero

This formula allows you to find the angle of a vector, relative to the coordinate system, given the x and y coordinates

of its “tip”, such angle θ is defined as:

y
θ = arctan( )
x

II y I
8

(x,y)
4

-8 -7 -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 7 8

-1
x
-2

-3

-4

-5

-6

-7

III -8
IV

Figure 13: Graphical plotting of the angle of a vector

3.13 Numerical Analysis

Here we will give some pointers over some algorithms and methods that may be useful to better explain some topics

treated in this book. Feel free to skip or quickly read this section if you don’t want to dive into too much detail over

this kind of maths.

3.13.1 Newton-Raphson method

Advanced Wizardry!

This section treats of how to approximate a function value in an iterative way. This will

be useful to know what the “Fast Inverse Square Root” algorithm uses. Feel free to

skim through this section.

Also known as Newton’s method, this is an iterative algorithm that is used to get progressively better approximations

to the roots of a function.

The algorithm starts with a “guess”, called x0 , and produces the first approximation using the formula:

f (x0 )
x1 = x0 −
f ′ (x0 )

Each subsequent guess (and thus iteration) can be obtained similarly by using the formula:

3 THE MATHS BEHIND GAME DEVELOPMENT 33


2D Game Development: From Zero To Hero

f (n)
xn+1 = xn −
f ′ (n)

And such guess will be more precise than the previous one (if we don’t consider some situations where approaching

the root can be problematic or not possible). The algorithm will stop when you reach an approximation that is “good

enough”.

Obviously all limitations of standard functions apply, such as domain and trouble with divisions by zero.

3.14 Coordinate Systems on computers

When it comes to 2D graphics on computers, our world gets quite literally turned upside down.

In our maths courses we learned about the Coordinate Plane, with an origin and an x axis going from left to right and

a y axis going from bottom to top, where said axis cross it’s called the “Origin”.

II y I
8

-8 -7 -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 7 8

-1
x
-2

-3

-4

-5

-6

-7

III -8
IV

Figure 14: Image of a coordinate plane

When it comes to 2D graphics on computers and game development, the coordinate plane looks like this:

Figure 15: Image of a screen coordinate plane

The origin is placed on the top left of the screen (at coordinates (0,0)) and the y axis is going from top to bottom.

It’s a little weird at the beginning, but it’s not hard to get used to it.

3 THE MATHS BEHIND GAME DEVELOPMENT 34


2D Game Development: From Zero To Hero

3.15 Transformation Matrices

There will be a time, in our game development journey where we need to rotate an object, and that’s bound to be

pretty easy because rotation is something that practically all engines and tool kits do natively. But also there will be

times where we need to do transformations by hand.

An instance where it may happen is rotating an item relative to a certain point or another item: imagine a squadron

of war planes flying in formation, where all the planes will move (and thus rotate) relative to the “team leader”.

In this chapter we’ll talk about the 3 most used transformations:

• Stretching/Squeezing/Scaling;

• Rotation;

• Shearing.

And to do so, we will use the following reference image, complete with a quadrant of the Cartesian plane.

y I
8

1 2 3 4 5 6 7 8

x
Figure 16: Reference image for transformation matrices

3.15.1 Stretching

Stretching is a transformation that enlarges all distances in a certain direction by a defined constant factor. In 2D

graphics you can stretch (or squeeze) along the x-axis, the y-axis or both.

If you want to stretch something along the x-axis by a factor of k , you will have the following system of equations:



 x′ = k · x
 ′
 y =y

which is translated in the following matrix form:

    
x′ k 0 x
 =  

y 0 1 y

3 THE MATHS BEHIND GAME DEVELOPMENT 35


2D Game Development: From Zero To Hero

Likewise, you can stretch something along the y-axis by a factor of k by using the following matrices:

    
x′ 1 0 x
 =  
y′ 0 k y

Stretching our reference image along the x and y axes respectively would look something like this:

y I y I
8 8

7 7

6 6

5 5

4 4

3 3

2 2

1 1

1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8

x x
Figure 17: Stretching along the x and y axes

You can mix and match the factors and obtain different kinds of stretching, if the same factor k is used both on the
x and y-axis, we are performing a scaling operation, like follows:

    
x′ k 0 x
 =  
y′ 0 k y

In instead of stretching you want to squeeze something by a factor of k , you just need to use the following matrices

for the x-axis:

    
x′ 1
0 x
  = k  
y′ 0 1 y

and respectively, the y-axis:

    
x′ 1 0 x
 =  
y′ 0 1
k y

3.15.2 Rotation

If you want to rotate an object by a certain angle θ, you need to decide upon two things (besides the angle of

rotation):

• Direction of rotation (clockwise or counterclockwise);

• The point of reference for the rotation.

3 THE MATHS BEHIND GAME DEVELOPMENT 36


2D Game Development: From Zero To Hero

3.15.2.1 Choosing the direction of the rotation

We will call TR the transformation matrix for the “rotation” functionality.

Similarly to stretching, rotating something of a certain angle θ leads to the following matrix form:

   
x′ x
  = TR  
y′ y

If we want to rotate something clockwise, relative to its reference point, we will have the following transformation

matrix:

 
cos(θ) sin(θ)
TR =  
−sin(θ) cos(θ)

This could how our square could look, after a rotation:

y I
8

1 2 3 4 5 6 7 8

x
Figure 18: The result of applying a rotation matrix

If instead we want our rotation to be counterclockwise, we will instead use the following matrix:

 
cos(θ) −sin(θ)
TR =  
sin(θ) cos(θ)

Pitfall Warning!

These formulas assume that the x-axis points right and the y-axis points up, if

the y-axis points down in your implementation, you need to swap the matrices.

3 THE MATHS BEHIND GAME DEVELOPMENT 37


2D Game Development: From Zero To Hero

3.15.2.2 Rotating referred to an arbitrary point

The biggest problem in rotation is rotating an object relative to a certain point: you need to know the point of rotation

(xp , yp ) in relation to the origin of the coordinate system you’re using, and modify the matrices as follows:

     
x′ x − xp x
  = TR   +  p
y′ y − yp yp

In short, you need to rotate the item by first “bringing it centered to the origin”, rotate it, and then bring it back into

its original position.

3.15.3 Shearing

During stretching, we used the elements that are in the “main diagonal” to stretch our objects. If we modify the

elements in the “anti-diagonal”, we will obtain shear mapping (or shearing).

Shearing will move points along a certain axis with a “strength” defined by the distance along the other axis: if we

shear a rectangle, we will obtain a parallelogram.

A shear parallel to the x-axis will have the following matrix:

    
x′ 1 k x
 =  
y′ 0 1 y

While a shear parallel to the y-axis will instead have the following matrix:

    
x′ 1 0 x
 =  

y k 1 y

Here is how shearing would look, as an example:

y I y I
8 8

7 7

6 6

5 5

4 4

3 3

2 2

1 1

1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8

x x
Figure 19: Shearing along the x and y axes

3 THE MATHS BEHIND GAME DEVELOPMENT 38


2D Game Development: From Zero To Hero

3.16 Basics of Probability

Games can make heavy use of probability: for instance when spawning items and treasures. Having a basic grasp

of how probability works can make things a lot easier.

3.16.1 A simple definition of probability

We will define the probability of an event A with a fraction:

T he outcome is A
P (A) =
All Outcomes

The numerator is called “event space”, while the denominator is called “sample space”.

For instance: let’s take a coin. We want to calculate the probability that a coin toss ends with “head”: first we count

how many outcomes are possible. Since a coin can land on “tails” or “heads”, we have 2 possible outcomes, and

head is only one of them.

For practicality, we will call “Heads” H and “Tails” T.

Thus:

1
P (H) = = 0.5
2

This result can be converted to a percentage, by multiplying it by 100. That means that there’s a 50% chance that

a coin toss ends in “heads”, shocking, I know.

What if we wanted to know the probability of a coin “not landing on heads”?

Here’s a useful formula:

P (A) = 1 − P (A)

Thus, by applying such formula on our coin example we have:

1 1
P (H) = 1 − P (A) = 1 − = = P (T )
2 2

Perfect. Everything as expected.

3.16.2 Probability of independent events

But what if we wanted to calculate the probability of more than one event?

3 THE MATHS BEHIND GAME DEVELOPMENT 39


2D Game Development: From Zero To Hero

If our events are independent (that means that the result of one doesn’t affect the result of others), we can use the

following formula:

P (A and B) = P (A ∩ B) = P (A) · P (B)

Let’s return to our coin example: if we wanted to know the probability of two coin tosses landing both on heads, we

would have:

1 1 1
P (H and H) = P (H) · P (H) = · =
2 2 4

Let’s demonstrate that intuitively: since the example is simple, we can literally count the possible outcomes:

Table 9: Counting the possible outcomes of two coin tosses

First Toss Second Toss

Heads Heads

Heads Tails

Tails Heads

Tails Tails

Now we know that there are 4 possible outcomes, and the “Heads + Heads” is only one of them. This confirms our

formula.

In the exact same way, we can calculate the probability of a “Heads + Tails” result:

1 1 1
P (H and T ) = P (H) · P (T ) = · =
2 2 4

And the previous table confirms our calculations.

Pitfall Warning!

Someone may argue that the probability of “Heads + Tails” is 1


2 , but that would not be
correct. We are still strictly tied to the events, that means that “Heads + Tails” (First

toss is heads, second toss is tails), is different from “Tails + Heads” (first toss is tails,

second is heads).

3.16.3 Probability of mutually exclusive events

In case the events are mutually exclusive (that means, if one event happens, none of the others can happen), the

following formula may be helpful in some occasions:

3 THE MATHS BEHIND GAME DEVELOPMENT 40


2D Game Development: From Zero To Hero

P (A or B) = P (A ∪ B) = P (A) + P (B)

Going back to our coin example: the probability of a coin toss being “either heads or tails” is 1
2 + 1
2 = 1.

Another example could be done using a 6-sided dice: each face can be on top with a probability of 1
6 . Let’s calculate
the probability of either 1 or 6 being face up:

1 1 2 1
P (1 or 6) = P (1) + P (6) = + = =
6 6 6 3

Note!

Considering the latest “tossing two coins” example, we can calculate the probability

of “one coin lands on heads and the other lands on tails” with the previous formulas,

since coin tosses tick both the “independence” and “mutual exclusivity” boxes.

1 1 1
P ((H and T ) or (T and H)) = P (H and T ) + P (T and H) = + =
4 4 2

3.16.4 Probability of non-mutually exclusive events

Not all events are mutually exclusive. Let’s think, for instance, about a deck of cards: what if you wanted to know

the probability of drawing either a card of hearts or a face card (Jack, Queen or King)?

We need to use a different formula in that case, which is the following one:

P (A or B) = P (A ∪ B) = P (A) + P (B) − P (A and B)

Note!

Why are we subtracting P (A and B)? Because if we didn’t, we would be counting the

face cards of hearts twice: once when we count the card of hearts, and once when we

count the face cards.

Let’s continue with our example.

13
A standard deck has 52 cards, 13 for each seed. This means we would have 13 cards of hearts: P (A) = 52 .

12
The same deck of cards also has 3 “face cards” for each seed, totalling 12: P (B) = 52 .

3
Since there are face cards of the hearts seed, we need to account for those too, totalling 3: P (A and B) = 52 .

This means that the probability we’re looking for is calculated as follows:

3 THE MATHS BEHIND GAME DEVELOPMENT 41


2D Game Development: From Zero To Hero

13 12 3 22 11
P (A orB) = P (A) + P (B) − P (A and B) = + − = =
52 52 52 52 26

3.16.5 Conditional Probability

Advanced Wizardry!

Conditional probability doesn’t have a lot of uses in game development, but it’s worth

mentioning it if you want to have a probabilistic approach to AI. Feel free to quickly

skim through this section.

Sometimes you may need to consider the probability of a certain event, given that another event happens. This is

called “conditional probability”, and it can be calculated as follows:

P (A and B) P (A ∩ B)
P (A|B) = =
P (B) P (B)

Conditional probability can be used to enrich the decision making used in enemy AI, for instance.

Let’s take a concrete example, taken straight from the famous tabletop RPG Dungeons&Dragons, and see how

probability can be applied to decision making.

You’re fighting against an enemy. Both you and the enemy are close to fatal damage: you have 1HP, while

the enemy has 3HP left.

To attack an enemy you need to roll a 20-sided dice (called a d20): if the number rolled is 13 or higher you

will hit, else you will miss.

If you hit, you will roll a 6-sided dice (called a d6): the number rolled will decide how much damage you will

deal, so you need 3 or more.

We need to find the probability of killing the enemy within the next turn to decide our next move.

First of all, let’s name the events:

• H Will be the event “hit”, which means that the d20 rolled a number that is 13 or higher.

• F Will be the event “fatal damage”, which means that the d6 rolled a number that is 3 or higher.

Now we will calculate the probabilities we need for our calculation:

8 2
P (H) = =
20 5
4 2
P (F ) = =
6 3

Our objective is calculating “the probability of doing at least 3HP of damage, given that we hit the enemy”. This is

represented as:

3 THE MATHS BEHIND GAME DEVELOPMENT 42


2D Game Development: From Zero To Hero

P (F ∩ H)
P (F |H) =
P (H)

This means we will have to calculate another probability, which is quite easy:

2 2 4
P (F ∩ H) = P (F ) · P (H) = · =
3 5 15

Now we are ready to calculate everything we need:

P (F ∩ H) 4
4 5 2
P (F |H) = = 15
2 = · =
P (H) 5
15 2 3

Given a 66% chance of success, you may decide that attacking is worth the risk. Such decision may be hard-coded

into an AI, for instance if the probability is higher than 50% the AI may choose to attack instead of retreating and

call for backup.

3.16.6 Uniform Distributions

In most cases, we will speak in terms of “uniform distributions”, that means that we will be operating on a system

where all outcomes have the same probability of happening.

That means that all dices are “fair”, all coins are “fair” and all our “bingo bags” have only one instance of a certain

number, all of the same size, shape and feel (thus making it impossible for a number to appear more often than any

other).

In the grand scheme of things, we are assuming that the random() function of our programming language is a uniform

distribution, where any number may come out with the same probability of any other.

3.16.7 How probability is used in games

You can use probability to govern how items spawn: surely you want more precious items to spawn more rarely (with

less probability), while more common items should spawn more often.

Let’s say we want an item to spawn with 20% probability: how can we do it?

20% probability can be rewritten as the decimal 0.2, such decimal can be obtained with the fraction 1
5 . We have
practically solved the problem: we decide on one number between 1 and 5 (inclusive) and we will know that such

number will be “extracted” 20% of the time.

Listing 2: 1 (out of 5) will be extracted with about 20% probability

1 #i n c l u d e < cstdlib >

2 #i n c l u d e < ctime >

3 #i n c l u d e < iostream >

5 i n t main () {

3 THE MATHS BEHIND GAME DEVELOPMENT 43


2D Game Development: From Zero To Hero

6 i n t happened = 0;

7 // We seed the randomizer with out system time


8 std :: srand ( std :: time ( nullptr ));
9 // Monte Carlo Method we do 10000 " extractions "
10 f o r ( i n t i = 0; i < 10000; i ++) {

11 // Get a random number between 1 and 5


12 i n t n = std :: rand () % 5 + 1;

13 i f (n == 1) {

14 // If it 's 1, we have a match !


15 happened ++;
16 }
17 }
18 // We print the result
19 std :: cout << happened << std :: endl ;
20 }

We will obtain the following result.

Figure 20: Running the probability_20 example shows the probability floating around 20%

But what if we wanted to be a lot more precise? Let’s say we want to spawn an item with 13% probability, how would

we go at it?

13
It’s actually pretty simple: out 13% probability can be represented by the fraction 100 . Each number between 1 and
1
100 (inclusive) has a 100 chance of being extracted. Since extracting one number bars any other number to appear

in that extraction we can use the “mutually exclusive events” formula.

1 1 1 13
P (1 or 2 or ... or 13) = P (1) + P (2) + ... + P (13) = + + ... + =
100 100 100 100

Tip!

If the example is not 100% clear yet, try reading the previous formula right-to-left. That

may help.

This means that the event “a number between 1 and 13 appears” has a 13% probability of appearing. We can

simplify that statement with “a number less or equal than 13”. We can experiment that easily with the following

code:

3 THE MATHS BEHIND GAME DEVELOPMENT 44


2D Game Development: From Zero To Hero

Listing 3: A number less or equal than 13 (out of 100) has 13% probability of appearing

1 #i n c l u d e < cstdlib >

2 #i n c l u d e < ctime >

3 #i n c l u d e < iostream >

5 i n t main () {

6 i n t happened = 0;

7 // We seed the randomizer with out system time


8 std :: srand ( std :: time ( nullptr ));
9 // Monte Carlo Method we do 10000 " extractions "
10 f o r ( i n t i = 0; i < 10000; i ++) {

11 // Get a random number between 1 and 100


12 i n t n = std :: rand () % 100 + 1;

13 i f (n <= 1) {

14 // If it 's less or equal than 13 , we have a match !


15 happened ++;
16 }
17 }
18 // We print the result
19 std :: cout << happened << std :: endl ;
20 }

Figure 21: Running the probability_le_13 example shows the probability floating around 13%

Tip!

You can extend the example above to fractions of a percentage by using bigger num-

bers: if you wanted a 13.5% probability, you would use all numbers less than or equal

to 135, out of 1000.

3.16.8 Tiered Prize Pools

We can use what we learned with probability to create a tiered prize pool. For instance we decide that killing a

certain enemy will always drop something, the tier of such item is according to the follow probability list:

• 50% probability for a common item to drop (for instance a scrap of leather);

• 30% probability for an uncommon item to drop (like a lower-grade potion);

• 15% probability for a rare item to drop (a good sword, for instance);

• 5% probability for an epic item to drop (a unique armor, for example);

3 THE MATHS BEHIND GAME DEVELOPMENT 45


2D Game Development: From Zero To Hero

30% 5%
Uncommon Epic

50% 15%
0 Common Rare
100

Figure 22: Intuitive representation of our prize pool

In that case we can chain ifs to bring our tiered prize pool to life:

Listing 4: How to implement a tiered prize pool selector

1 #i n c l u d e < cstdlib >

2 #i n c l u d e < ctime >

4 // We seed the randomizer with out system time


5 std :: srand ( std :: time ( nullptr ));
6

7 i n t get_tiered_drop () {

8 // 1 = Common , 2 = Uncommon , 3 = Rare , 4 = Epic


9 i n t n = std :: rand () % 100 + 1;

10 i f (n <= 50) {

11 // Common Tier
12 r e t u r n 1;

13 }
14 i f (n <= 80) {

15 // Uncommon Tier
16 // Since n <=50 has already returned false , we know this
17 // branch will only happen if 50 <n <=80
18 r e t u r n 2;

19 }
20 i f (n <= 95) {

21 // Rare Tier
22 // Since both n <=50 and n <=80 both returned false , we know
23 // this branch will only happen if 80 <n <=95
24 r e t u r n 3;

25 }
26 // Epic Tier
27 // All other branches failed , so we 'll get here only if
28 // 95 <n <=100
29 r e t u r n 4;

30 }

3.16.8.1 Introducing a “luck” stat

In many RPGs there is a “luck” statistic that affects how item drops happen, in that case we will need to change how

tiered prize pools are given out. Things can get complicated quite quickly.

Let’s imagine a simple situation: one point of “luck” gives a 1% probability of getting an item of each tier higher
than “Common”, while at the same time reducing the probability of finding a “common” item.

3 THE MATHS BEHIND GAME DEVELOPMENT 46


2D Game Development: From Zero To Hero

At a first glance, it seems simple: take each “non-common” class and “add 1”, then take the “common” class and

“remove 1 for each point given”. But what would happen if the luck stat is higher than the probability of a “common”

item? It should probably start taking away probability from “uncommon” items to give out “rare” and “epic” items.

Let’s see a possible implementation:

Listing 5: A possible implementation of a luck stat

1 #i n c l u d e < algorithm >

3 enum Rarity { EPIC , RARE , UNCOMMON , COMMON };

4 // Our probabilities , from least to most common


5 i n t pool [4][2] = {

6 { EPIC , 5} ,
7 { RARE , 15} ,
8 { UNCOMMON , 30} ,
9 { COMMON , 50} ,
10 };
11

12 // Our " luck stat ": each point gives 1% more chance to get a higher - tier item
13 i n t LUCK = 25;

14

15 // We cap the Luck stat at 100 , the limit is 100% epic items
16 LUCK = std :: min ( LUCK , 100) ;
17

18 // We " overload " the prize pool , making the sum go over 100%
19 i n t overloaded_pool [4][2];

20 i n t overload_factor = 0;

21

22 f o r ( i n t i = 0; i < 4; i ++) {

23 i n t new_prob = pool [ i ][1] + LUCK ;

24 // We accumulate the overload factor for further calculation


25 overload_factor = overload_factor + new_prob ;
26 overloaded_pool [ i ][0] = pool [i ][0];
27 overloaded_pool [ i ][1] = new_prob ;
28 }
29

30 // We calculate how much we " overloaded " the prize pool


31 overload_factor = overload_factor - 100;
32

33 // We rebalance the prizes to a total of 100 , from most to least common


34 i n t rebalanced_pool [4][2];

35 // We need to start from the most common , which means we will iterate backwards
36 f o r ( i n t i = 3; i > 0; i - -) {

37 const i n t item = pool [i ][0];

38 const i n t probability = pool [i ][1];

39 // This will be modified later , if the pool is " overloaded "


40 i n t new_probability = probability ;

41 // If the prize pool is still " overloaded "


42 i f ( overload_factor > 0) {

43 // We calculate a " discharge factor " of sorts

3 THE MATHS BEHIND GAME DEVELOPMENT 47


2D Game Development: From Zero To Hero

44 i n t value_to_remove = std :: min ( probability , overload_factor );

45 // We reduce our " overload "


46 overload_factor = overload_factor - value_to_remove ;
47 // And put the new probability for the class
48 new_probability = probability - value_to_remove ;
49 }
50 // We append the new pool item
51 rebalanced_pool [ i ][0] = item ;
52 rebalanced_pool [ i ][1] = new_probability ;
53 }

3 THE MATHS BEHIND GAME DEVELOPMENT 48


2D Game Development: From Zero To Hero

4 Some Computer Science Fundamentals

The computing scientist’s main challenge is not to get confused by the

complexities of his own making.

Edsger W. Dijkstra

In order to understand some of the language that is coming up, it is necessary to learn a bit of the computer science

language and fundamentals.

This chapter will briefly explain some of the language and terms used, their meaning and how they contribute to

your activity of developing games.

4.1 Number representations

When you work with computers, it’s impossible to avoid learning a bit of number representations. Computers work

with a different logic than humans do: humans have complex minds and thoughts, while most of the time computers

work in ones and zeroes. Most of what we see on a screen can be reduced to electrons going through a semiconductor

in kind of an orderly fashion: changing from 0 volts (ground) to 5 volts.

4.1.1 The most used representations

Here we will take a quick look at the most used representations. Some are more fundamental than others, but they

are all useful in their own way.

Each representation will use a subscript to represent its representation. If no subscript is present it means the

standard decimal representation is used.

4.1.1.1 Decimal

This is the standard decimal notation everyone is used to, we have 10 digits at our disposal:

0123456789

And we place them in certain positions (units, tens, hundreds, thousands, etc…) to represent a certain quantity. We

will use this as a basis for all other representations.

So if you want to represent 9 + 1 you will use the 1 digit, followed by the 0 digit to make 10.

4.1.1.2 Binary

This is the most used representation in computer science, we have only two digits at our disposal: 0 1.

Thus if you want to make 1bin + 1bin , you will have to use the 1 digit, followed by the 0 digit, thus making 10bin ,
which is the binary representation of 2.

Here are the first 10 numbers for comparison purposes:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 49


2D Game Development: From Zero To Hero

Table 10: Comparison between decimal and binary representations

Decimal Binary

0 0

1 1

2 10

3 11

4 100

5 101

6 110

7 111

8 1000

9 1001

10 1010

Binary numbers can be used at low level to represent any kind of “binary condition” too: yes/no, true/false are

usually mapped to 1 and 0 respectively. This will probe useful in some cases where we will use “binary numbers” to

represent groups of “binary conditions” in a compact way, but that’s an advanced thing we’ll see later.

4.1.1.3 Octal

In the octal representation we have 8 digits at our disposal:

01234567

Thus the representation of the decimal number 8 in the octal system is 10oct .

The octal number system doesn’t find much use in computer science besides being a quicker way to represent binary

numbers. The conversion is quite easy and will be explained in a bit.

Here’s a quick comparison between decimal and octal representations:

Table 11: Comparison between decimal and octal representations

Decimal Octal

0 0

1 1

2 2

3 3

4 SOME COMPUTER SCIENCE FUNDAMENTALS 50


2D Game Development: From Zero To Hero

Decimal Octal

4 4

5 5

6 6

7 7

8 10

9 11

10 12

4.1.1.4 Hexadecimal

Hexadecimal is definitely the second most used representation in computer science, due to how easy it is to represent

4 bytes in a very compact notation.

In the hexadecimal notation, we have sixteen digits at our disposal:

0123456789ABCDEF

Here’s a table of the first 20 numbers to clarify a bit how things work:

Table 12: Comparison between decimal and hexadecimal representations

Decimal Hex

0 0

1 1

2 2

3 3

4 4

5 5

6 6

7 7

8 8

9 9

10 A

11 B

12 C

13 D

4 SOME COMPUTER SCIENCE FUNDAMENTALS 51


2D Game Development: From Zero To Hero

Decimal Hex

14 E

15 F

16 10

17 11

18 12

19 13

20 14

4.1.2 Converting between decimal and binary

The algorithm to convert between decimal and binary is quite simple. It is an iterative algorithm that consists in

integer dividing the number by 2, until the result of the division is 1. The modulo of such divisions will make up our

binary number.

An example is worth a thousand words: let’s convert the number 38 to binary.

First of all, we integer divide 38 by two: the result is 19, there is no remainder, so we’ll use zero.

Dividend Remainder

38 0

19

Let’s continue: we integer divide 19 by two: the result is 9, with 1 as remainder.

Dividend Remainder

38 0

19 1

We iterate some more, by integer dividing until we get 1 as a dividend, at that point we make the last division, which

will have remainder 1:

Dividend Remainder

38 0

19 1

9 1

4 SOME COMPUTER SCIENCE FUNDAMENTALS 52


2D Game Development: From Zero To Hero

Dividend Remainder

4 0

2 0

1 1

Now we just need to read our remainders from bottom to top. So the binary representation of 38dec is 100110bin .

Note!

This is actually a much more generic algorithm: you can convert from decimal to octal

and hexadecimal for instance, just by dividing by 8 and 16 respectively. You can convert

38 to octal and hexadecimal as an exercise: the results are 46oct and 26hex .

4.1.2.1 Two’s complement

So far we’ve seen how to convert positive integers from decimal to binary, but how do we represent negative

integers?

That’s where “two’s complement” representation comes into play: there is a bunch of theory behind why it’s called

this way, and how it works, but what we need to know will be how to represent a negative number.

Let’s start with a simple example with 3 binary digits (this means we’re pretending our computer can process only

up to 3 bits):

Decimal Binary

-4 100

-3 101

-2 110

-1 111

0 000

1 001

2 010

3 011

As you can see, the most significant bit being set (that means having value of 1) is a telltale sign that a number

is negative. But there are some interesting features about two’s complement that make it a very nice method of

representing integers.

This is because it makes easier to implement hardware that does operations on such numbers. If we sum 3 and −3
in two’s complement we will obtain the following:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 53


2D Game Development: From Zero To Hero

011
+ 101
1000

This may look completely wrong, but since our “computer” can only process up to 3 bits, the left-most bit will be

discarded, giving us the right result: 000bin .

Now let’s see how to represent negative numbers in two’s complement.

To represent a negative binary number in two’s complement you flip all the bits of such number, then add 1.

As usual, an example is worth a thousand words. We want to convert the number −38 into binary.

First of all we need to define what our range of numbers will be, so that we know how many bits we will use. This is

done because this range will be equally split between positive and negative numbers. In this example I will choose

a normal 8-bit representation, which can represent numbers spacing from -128 to 127.

The first step is to convert 38 to binary, which as we saw is 100110bin . We will pad this binary number to 8 bits,

obtaining 00100110bin as a result.

Now we just need to invert the all the bits in the number, obtaining 11011001bin as a result.

Last step is adding 1 to what we got in the previous step, thus the final result is 11011010bin .

Note!

The more perceptive of you may have noticed a problem: what if we tried to represent

the number 128 with 8 bits?

We would obtain 1000000bin which is actually the representation of -128 in two’s com-

plement. This is called an “integer overflow”, so be careful when mixing unsigned and

signed integers.

4.1.2.2 Floating point

[This section is a work in progress and it will be completed as soon as possible]

4.1.3 Converting between binary and octal

As mentioned before, octal can be used as a “shorthand way” to represent binary. The conversion is pretty simple.

To convert from binary to octal, take the binary digits in groups of 3 (with the necessary padding) and convert

them in octal. Then just “stick them together”.

Let’s take our number 38, it has the following representation:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 54


2D Game Development: From Zero To Hero

100 110bin

100bin converts to 4oct , while 110bin converts to 6oct . If we stick them together we obtain the final result: 46oct .

4.1.4 Gray Code

Advanced Wizardry!

Gray code isn’t really used in game development, but it will be briefly explained here

since it will be used in Karnaugh Maps

Gray code (sometimes known as “reflected binary code”) is a particular ordering of the binary system where two

successive values differ by only one bit.

Gray code is used in many fields, from Digital (and cable) TV (for error-correction) to analog to digital conversion. In

this book we will use it as a representation inside Karnaugh Maps.

Here is a simple representation of the first 10 numbers in decimal, binary and gray code:

Decimal Binary Gray Code

0 0000 0000

1 0001 0001

2 0010 0011

3 0011 0010

4 0100 0110

5 0101 0111

6 0110 0101

7 0111 0100

8 1000 1100

9 1001 1101

10 1010 1111

4.2 Basics of Logic

If we want our algorithms to be smart enough to be useful, we have to deal with conditionals. That’s where logic

comes in. In this section we will take a quick look at truth tables as well as logic operations.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 55


2D Game Development: From Zero To Hero

4.2.1 Truth tables

Truth tables are used to represent the output of a logic operation. It represents the inputs on the left side, while on

the right side the result is shown.

Truth tables in this book will have the following look:

A B f

0 0 0

0 1 0

1 0 1

1 1 0

4.2.2 Common operators

After we distinguish “true” (1) from “false” (0), we will need to start mixing and matching them (similarly to what

we do with numbers). That’s where operators come into play: they are a bit different than what we’re used to in

arithmetics, but they are quite intuitive.

4.2.2.1 AND

The “AND” operator is a binary operator that outputs 1 when both inputs are 1. Here is its truth table:

A B AND

0 0 0

0 1 0

1 0 0

1 1 1

This operator is used to express conditionals where you want two conditions to be true at the same time.

4.2.2.2 OR

The “OR” operator (sometimes called “inclusive or”, as opposed to the XOR operator) is a binary operator that

outputs 1 when either of the inputs is 1, including the case when both are 1. Here is its truth table:

A B OR

0 0 0

0 1 1

1 0 1

4 SOME COMPUTER SCIENCE FUNDAMENTALS 56


2D Game Development: From Zero To Hero

A B OR

1 1 1

This operator is used to express conditionals where you want at least one condition to be true.

4.2.2.3 NOT

The “NOT” operator is a unary operator that takes a single input and “inverts” it. That means that if the input is 1,

the “NOT” operator will output 0, if the input is 0 the “NOT” operator will output 1 instead.

Here is its truth table:

A NOT

0 1

1 0

4.2.2.4 XOR

The “XOR” operator (called “exclusive or”) is an operator that takes two input and outputs 1 when only one of the

two inputs is 1. If both inputs have the value 1, the “XOR” operator will output 0.

Here is its truth table:

A B XOR

0 0 0

0 1 1

1 0 1

1 1 0

This operator is used when you want to express conditionals where only one of the two inputs is true.

4.2.3 Logic operations vs bitwise operations

Advanced Wizardry!

The confines between logic operations and bitwise operations can get blurry. This

section introduces bitwise operations and alternative representations of data as a way

to fit more data in less space. Feel free to skim over this section.

So far we’ve seen operations that work on single binary digits, which can be seen as the numeric representation of

logical statements (0 meaning “false” and 1 meaning “true”). These are logic operations.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 57


2D Game Development: From Zero To Hero

Such operations can be applied on a bit-by-bit basis to groups of bits, that’s when we talk about about “bitwise

operations”.

0110 0010 AN D
0101 1010
0100 0010

As you can see the bitwise AND operation takes each bit of the two bytes and does an “AND” operation on each one

of them.

4.2.3.1 Packing more information with less

Let’s imagine the following situation: we have a structure that represents a tile in a maze. We want to efficiently

store whether each side of a certain tile has a wall.

This can be solved by using a 4-bit positive integer and having each bit represent a side of the tile: if that bit is 1,

there is a wall, 0 otherwise.

After creating a convention, we can start storing data. For instance we can have the bits representing walls starting

from top, going clockwise.

This convention could be summarized as follows:

• 0001 represents a “top wall”;


• 0010 represents a “right wall”;
• 0100 represents a “bottom wall”;
• 1000 represents a “left wall”.

This means that 0110 represents a tile having two walls: on the right and bottom side (this is the integer number 6,

by the way). If we wanted to check if a certain tile has a wall, we would just need to AND it (bitwise) with the number

that represents such wall.

If the result of such operation is not zero, the wall we searched for is in our tile. Continuing with our example, if we

test for a right wall we will obtain zero:

0110 AN D
0001
0000

But if we test for a bottom wall, we will obtain something that is not zero:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 58


2D Game Development: From Zero To Hero

0110 AN D
0100
0100

4.2.4 De Morgan’s Laws and Conditional Expressions

De Morgan’s laws are fundamental in computer science as well as in any subject that involves propositional logic.

We will take a quick look at the strictly coding-related meaning.

De Morgan’s laws can be written as:

not (A and B) = not A or not B

not (A or B) = not A and not B

In symbols:

(A ∧ B) = Ā ∨ B̄

(A ∨ B) = Ā ∧ B̄

These laws allow us to express our own conditionals in different ways, allowing for more readability and maybe avoid

some boolean manipulation that can hinder the performance of our game.

4.3 Algorithms

When you talk about computer science, you always hear about algorithms: what is an algorithm?

An algorithm can be informally defined as a finite sequence (as in “not infinite”) of instructions that are followed to

solve certain problems.

There are numerous examples of algorithms, among them we can find:

• Finding the Greatest Common Divisor (GCD) of two numbers;

• Finding the largest number in a list;

• Calculating the nth Fibonacci number;


• …

Algorithms are usually represented in flow charts, or it’s more modern counterpart: the UML activity diagram. Some-

times algorithms can be represented in “plain language” (in that case we may end up talking about “pseudocode”)

or in a programming language.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 59


2D Game Development: From Zero To Hero

4.4 Recursion

Starting from the (arguably hard) theme of recursion may seem weird, but it is important to understand recursion

as soon as possible so we can make the best use of it.

There is a joke I like telling around about recursion:

To understand recursion, you must first understand recursion.

What is recursion? Recursion is the usage of a function that calls itself.

Your first question will probably be: wouldn’t that make the program lock up forever in some kind of loop? It may.

But if you’re careful, recursion is an amazing tool that allows you to earn a lot of clarity and brevity.

Let’s imagine a simple algorithm: we want to make our program count backwards from a number n to 0. In a simple

“loop” fashion, we may write the following:

Listing 6: Counting from n to 0 using a loop

1 #i n c l u d e < iostream >

2 void count_backwards ( i n t n){

3 // Condition for the loop


4 while (n != 0) {

5 // The function body


6 std :: cout << n << std :: endl ;
7 // We update the condition to count down
8 n = n - 1;
9 }
10 }

Pretty simple, right? A real-world example would be counting back from 10 to 0: we print 10, we subtract 1 to get

9, we print 9, subtract 1 to get 8, …

Let’s turn our thinking around for a second. We can see counting back from to 10 to 0 like this: we print 10 and then

we count backwards from 9. Counting backwards from 9 would just mean printing 9 and then counting back from 8,

etc…

We just turned our simple loop into a recursive function:

Listing 7: Counting from n to 0 using recursion

1 void count_backwards ( i n t n){

2 // Stop condition
3 i f (n == 0) {

4 // If we don 't do this , we won 't print 0


5 std :: cout << n << std :: endl ;
6 return ;

7 }
8 // Procedure

4 SOME COMPUTER SCIENCE FUNDAMENTALS 60


2D Game Development: From Zero To Hero

9 std :: cout << n << std :: endl ;


10 // Recursive call
11 count_backwards (n -1) ;
12 }

Recursive functions have three main components:

• A base case (sometimes called a “stop condition”): this allows the function to stop calling itself when a certain

condition is reached;

• A procedure that elaborates on data or simply does something (in our example, it just prints the number);

• A recursive call to the same function we are writing, the call is done in a way that every call gets closer to

the “stop condition”. It can be done by calling the function on a subset of its argument (if it is a list), until the

list has only 1 item or on a smaller number (if the function argument is a number instead).

Recursion can be classified in many ways:

• By the number of recursive calls: single vs multiple recursion;

• By how the recursive call is made: direct (a function calls itself directly) vs indirect (a function A is called

by another function B, which in turn is called by function A)

• By the position of the recursive call: head vs tail recursion.

I want to underline the last distinction: what we’ve seen in the previous listing is called “tail recursion”: the recursive

call is done after everything else (the procedure).

Head recursion is instead done when the recursive call is done before the procedure starts, so we can transform our

“count down” function to a “count up” just by switching from “tail” to “head” recursion and adding a print statement.

Listing 8: Counting from 0 to n using head recursion

1 #i n c l u d e < iostream >

3 void count_forwards ( i n t n){

4 // Stop condition
5 i f (n == 0) {

6 // If we don 't do this , we won 't print 0


7 std :: cout << n << std :: endl ;
8 return ;

9 }
10 // Recursive call
11 count_forwards (n -1) ;
12 // Procedure
13 std :: cout << n << std :: endl ;
14 }

4 SOME COMPUTER SCIENCE FUNDAMENTALS 61


2D Game Development: From Zero To Hero

4.5 Programming Languages

Programming languages are a programmer’s way to talk to a computer (or a console): they are a way to make an

electronic apparatus do something (without involving analogue electronics).

4.5.1 Classifying programming languages

Programming languages can be distinguished by many traits, it is important to know such differences, even though

you may have already chosen your programming language.

4.5.1.1 By how they build

The way that a programming language gets you from code to “working product” can heavily influence both the final

product as well as the speed of development.

4.5.1.1.1 Compiled Languages

Compiled languages need to go through a building process before it is possible for the product to be run anywhere.

This has some advantages, as well as some disadvantages.

Figure 23: Example of a compiler output (G++)

Among the disadvantages we have that the final product is usually non-portable, that means it cannot be run any-

where besides the machine it was compiled for. This means that you will have to create separate builds for each

console, as well as different builds for each operating system.

Another disadvantage can be development speed: before you can test anything your game needs to be rebuilt. Some-

times the rebuild process can be quick (thanks to some techniques that avoid building things that didn’t change),

sometimes it can be long.

A very strong advantage of compiled languages is speed. Being essentially compiled to machine code, compiled

languages have an easier time squeezing every last drop of performance from the platform you’re building for. In

addition, some languages can use features to physically remove unused code from the build: this way release builds

can be much faster than debug ones, because the debug code is physically removed.

Among compiled languages we can find C and C++, as well as Rust and Go.

4.5.1.1.2 Interpreted Languages

4 SOME COMPUTER SCIENCE FUNDAMENTALS 62


2D Game Development: From Zero To Hero

Interpreted languages, in their strictest sense, are at the other side of the spectrum: the program is not compiled

ahead of time but instead the source code is fed into an interpreter, which executes each row of instructions, one

after the other.

Most interpreted languages feature an interactive REPL[g] (read-eval-print loop) which allows to test code in real

time.

Figure 24: Python’s REPL Shell

They have the disadvantage of being usually slower than compiled languages and it’s not easy to create builds

that physically remove unused (debug) code without having to modify the sources manually. Also each console or

operating system will need to have the interpreter installed, which may be an issue.

The advantage is in development speed: you can edit the source code and immediately run the interpreter to see

the result, without having to wait for a new build to complete. Another advantage is portability: you don’t need to

create a new build for every system you want to run your game in, as long as an interpreter is available your game

will run.

An example of a purely interpreted language is BASIC.

4.5.1.1.3 Hybrid Approaches

In any project, the ability to code quickly is as important as the performance of the final product: there is a thin

balance to strike between “having a product with good performance” and “having a product that is released when

needed”. If your product releases too late, it doesn’t matter how performing it is, the market will have chosen

another product. If your product releases early but it underperforms, it will be replaced by better products.

Thus some hybrid approaches have been invented: one of these is, for instance, bytecode-compiled languages.

Bytecode-compiled languages (sometimes called “Languages with intermediate representation”) are something that

is not quite compiled, but it’s not precisely interpreted either: the code is converted into bytecode, which is then

fed to the interpreter (or “virtual machine”) to run.

Being a representation that is “closer to the hardware” than the original source code, there is a gain in performance,

while keeping the flexibility of interpreted code.

Random Trivia!

Some programming languages, like Haskell and Vala use the C programming language

as an intermediate language, since C was meant to be an abstraction of the assembly

language.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 63


2D Game Development: From Zero To Hero

Other approaches include Just-In-Time compiling, which trades off some longer starting times (sometimes called

“warm-up times”) for better overall performance.

Among the bytecode-compiled languages we can find Java and Python, while Lua can be considered a Just-In-Time

Compiled language (thanks to LuaJIT).

4.5.1.2 By Paradigm

A programming paradigm is how the programming language lets you program. There is not a single, definitive way

to code, thus programming languages can be distinguished by their paradigm.

4.5.1.2.1 Imperative Languages

Imperative languages are probably the most spread in modern programming: they make use of “orders” (called

“statements”) to change the status of the program.

This paradigm makes use of variables, statements, subroutines to make the program look like a set of instructions,

a recipe, to make the program do what it needs to do (an algorithm).

Imperative languages include C, COBOL, Basic and Fortran.

4.5.1.2.2 Functional Languages

Functional languages make programs work by applying and composing functions (in the mathematical sense). Func-

tions can be bound to variables and chained together (composed) to reach the result.

Functional languages include Haskell, Common Lisp and Scheme.

4.5.1.2.3 Multi-paradigm Languages

Many programming languages tend to “meld together” many programming paradigms, allowing (for instance) for

functional style programming in imperative languages.

This means that functions can be bound to variables and passed around as any other object, they can be composed

to reach the result if the programmer decides to do so (for instance for readability).

Multi-paradigm languages include Python, Lua and Go.

4.5.1.3 By the way types are determined

Sometimes underrated, how types are evaluated can completely change the way you program your game. Not

knowing precisely how your language of choice treats types can lead to hard-to-debug issues.

4.5.1.3.1 Static Typing

Statically typed languages have their types decided ahead of time (usually when the program is compiled) and

usually they cannot be changed.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 64


2D Game Development: From Zero To Hero

This means that you have to have full awareness of which types will be used while writing your game. Which can be

difficult at times.

Statically-typed languages include C, C++ and C#, as well as Java.

4.5.1.3.2 Dynamic Typing

Dynamically typed languages have their types decided at runtime. This allows for simpler syntax, but at the cost of

lower performance, due to the fact that types are determined and verified at runtime.

Dynamically-typed languages include JavaScript and Ruby.

4.5.1.3.3 Duck Typing

Duck typing is probably the most misunderstood typing system. It can be described by the following sentence:

If it walks like a duck and it quacks like a duck, then it must be a duck.

This means that types are inferred by their behaviour (their capabilities), thus creating a series of -like objects that

behave more or less the same. This means that types can make use of the iteration capabilities of the language as

long as they implement some basic methods that allow iteration (like nextElement() and length()).

This means that we have “file-like” objects, which behave like files, are used like files, but not necessarily have

a counterpart in mass storage (they could be in-memory files), or “iterables” (sometimes called “list-like”) which

behave like lists of items, but may actually be something else (for instance strings could be seen as a “list of letters”).

In the end, in duck typing, interfaces are treated as some kind of “informal protocol” that tells the language how

to use an object. The “protocol” doesn’t even need to be implemented fully: if you have a “file-like” object that

implements only the reading method, you can still use it in the same way you’d use a file, as long as you don’t try

to write to it.

Duck Typing is used in the Python programming language.

4.5.1.4 By the “strength” of typing

How types are treated after each variable is instantiated can be the source of a lot of headaches while coding, thus

it is paramount to be aware of how strong your preferred language’s typing system is.

4.5.1.4.1 Strong Typing

Strongly typed languages don’t allow one type to be treated like it was another type without an explicit conversion

(usually called “cast”). This prevents unforeseen automatic type conversions that may lead to bugs and faults being

undetected at compile time or runtime.

Some examples of strongly typed languages are C++, C#, Python and Java.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 65


2D Game Development: From Zero To Hero

4.5.1.4.2 Weak Typing

Weak typed languages allow one type to be treated like another without explicit conversion. This may make the

syntax simpler, but may be source of unforeseen bugs.

For instance a string may be treated as it was a number, this means that in some languages (where the operator

+ means both “addition between numbers” and “joining strings together”) you may find that a result is a sum of

numbers instead of two strings joined together.

An example of a weakly typed language is JavaScript.

Random Trivia!

What about the good old C language? C has strong typing for the great majority of the

time, unless we consider the void* generic pointer. This kind of pointer can be used in

other pointer variables without an explicit cast.

4.5.1.5 By memory management

Another way to classify programming languages is how you can (or have to) manage your memory.

4.5.1.5.1 Languages without Garbage Collection

Some programming languages allow you to play with your system’s memory as you wish: they give you all the tools

(pointers, references, …) to manually allocate and free memory.

This comes with its advantages and drawbacks: higher performance is surely a big advantage. A huge disadvan-

tage is the fact that memory management is completely manual: dangling pointers and unreachable memory are

commonplace, because there is nothing to clear after you.

Non Garbage-collected languages include C and C++.

4.5.1.5.2 Garbage-collected Languages

Some other languages prefer taking away part of the control on memory to help avoiding the problems that non

Garbage-collected languages bring: there is something that cleans after you, which is the Garbage Collector.

The big disadvantage of this approach is that the garbage collector needs reference counting, CPU cycles to run,

which means that the whole program runs slower.

Garbage collected languages include Java and Python.

4.5.2 Languages available for this book

Here is a quick rundown of how the languages used in the various editions of this book (excluding “pseudocode”,

which is not really a programming language) are classified.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 66


2D Game Development: From Zero To Hero

• C++, a compiled programming language with strong static typing. It is multi-paradigm (although it was born

as an imperative language) and has no garbage collector.

• JavaScript, an interpreted language (although some engines support Just-In-Time compiling), with weak dy-

namic typing that supports some duck typing principles. It is multi-paradigm and features a garbage collector.

• Lua, a bytecode-compiled (or Just-In-Time compiled) language, with strong dynamic typing that supports

some duck typing principles. It is multi-paradigm and garbage-collected.

• Python, a bytecode-compiled language, with strong duck typing. It is multi-paradigm and garbage-collected.

4.6 Computers are (not) precise

There are many differences between humans and computers, among those there is one that will keep haunting us

in our journey: humans make calculations in “base 10” (decimal), computers make calculation in “base 2” (binary).

This requires computers to represent numbers differently, usually with the exponent+fraction representation (IEEE

754). Also computers have limited resources, thus have no concept of “infinity” (and conversely of “infinitesimal”).

Let’s assume a computer with a fixed (and reduced) precision and we execute the following C++ program (you can

just copy it verbatim):

Listing 9: A simple float precision test

1 #i n c l u d e < iostream >

2 #i n c l u d e < iomanip >

4 i n t main ()

5 {
6 // This will reduce and fix the computer 's precision for this execution
7 std :: cout << std :: setprecision (20) ;
8

9 f l o a t d1 (1.0) ;

10 std :: cout << " This should be 1.0: " << d1 << std :: endl ;
11

12 f l o a t d2 (0.1) ;

13 std :: cout << " This should be 0.1: " << d2 << std :: endl ;
14

15 f l o a t d3 (0.1*0.1) ;

16 std :: cout << " This should be 0.01: " << d3 << std :: endl ;
17

18 bool x (0.1 + 0.1 + 0.1 == 0.3) ;

19 std :: cout << " This should be true (1) : " << x << std :: endl ;
20

21 r e t u r n 0;

22 }

We save it as “precision_test.cpp” and compile it with the following command line (on Linux):

1 g ++ - Wall - Wextra - Werror -O0 precision_test . cpp -o precision_test . bin

4 SOME COMPUTER SCIENCE FUNDAMENTALS 67


2D Game Development: From Zero To Hero

This program will temporarily set a reduced precision in our number representation, and try to output the values of

the numbers 1, 0.1 and 0.12 = 0.01, let’s see the results:

Figure 25: Results of the simple float precision test

With the number 1 it’s all good, but… what is going on with 0.1? What is all that garbage? The number 0.01 is even

worse! That’s not even close! Why 0.1 + 0.1 + 0.1 comes out as not 0.3! What is maths anymore?

We have just met one of the (many) limitations of computers: computers cannot represent certain numbers without

“approximating”. Compilers and libraries exist to work around these issues, but we need to be ready to avoid

surprises.

Just to reiterate: this is not a problem of the single programming language, we can see that C++ is affected, but

also Python has the same issue:

Figure 26: Python 2 has the same issues with precision as C++

Figure 27: Python 3 doesn’t fare much better when it comes to precision

This is a computer issue in general: this may not be a huge problem for general use but, if we try to be too precise

with our calculations, this may come back to bite us.

4.6.1 Catastrophic cancellation

Advanced Wizardry!

Catastrophic cancellation is one of the many pitfalls that you may encounter when

dealing with very small numbers. This doesn’t happen really often in the world of

game development, feel free to just skim through this mostly informative section.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 68


2D Game Development: From Zero To Hero

With a name as dangerous-sounding as “catastrophic cancellation”, this sure looks like a dangerous phenomenon,

but it’s only dangerous if we don’t know what it is.

Catastrophic Cancellation (sometimes called “cancellation error”) is an event that may happen when subtracting

two (usually large) numbers that are close to each other in value.

Warning: from here on, in this section, there will be some technical language. I will try to make it as simple and

understandable as possible.

Let’s imagine a computer, such computer’s memory can handle at most 8 decimals while its A.L.U.[g] (the unit that

takes case of “doing maths”) can handle at most 16 decimal places.

Now let’s take two numbers:

x = 0.5654328749846 y = 0.5654328510104

When we transfer such numbers in our memory, the computer will approximate such numbers to fit in its memory

constraints. We’ll represent that by applying to each number a function f l() that we can read as “float representation

of this number”. So we’ll end up having:

f l(x) = 0.56543287 f l(y) = 0.56543285

This is generally called an “assignment error”, where during the assignment to a variable, a number loses part of its

information.

Let’s try an calculate how off those approximations are (by calculating the percent “relative error”), just to get an

idea of what we lost by just loading the numbers on our “fake computer”:

|x − f l(x)|
δx = = 0.00000088%
x
|y − f l(y)|
δy = = 0.00000017%
y

We can see that our approximations are very close to the numbers we want to calculate, now let’s calculate x − y.
Making things by hand we would have:

x − y = 0.239772 × 10−7

That’s a tiny number right there. Now let’s calculate f l(x) − f l(y), remembering that the A.L.U. will fill up to 16
decimals:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 69


2D Game Development: From Zero To Hero

f l(x) − f l(y) = 0.5654328700000000 − 0.5654328500000000 = 0.0000000200000000 = 0.2 × 10−7

That doesn’t look so bad, unless we look at the “relative error”:

|0.239772 × 10−7 − 0.2 × 10−7 |


δ= = 16.6%
0.239772 × 10−7

We are off by 16% of the total result, this is actually really bad.

What happened? If you look closely, the numbers are really close and even have 7 decimal digits in common, since

our computer can memorize only 8 digits, the 9th to 13th decimal digits that looked so unimportant suddenly become

a huge part of the result (due to the subtraction) but are already lost.

4.7 Random Numbers are not really random

Computers are deterministic machines, given the same set of instructions and inputs, they will always return the

same output. Someone may think about “random number generators” and sure, those programs look like they spit

random numbers on your screen, but they actually don’t.

The most important number when generating random numbers is called seed and it’s the number used by the

generator to produce random numbers.

Let’s see an example of a random number generator in C++ (you can copy this program verbatim to try it):

Listing 10: A simple random number generation program

1 #i n c l u d e < iostream >

2 i n t main () {

3 // First of all we get the seed


4 unsigned i n t seed ;

5 std :: cout << " Type the seed : " ;


6 std :: cin >> seed ;
7 // Now we seed the randomizer
8 srand ( seed );
9 // Small presentation
10 std :: cout << " This generator will now generate 10 random numbers " << std :: endl ;
11 // Output 10 random numbers
12 f o r ( i n t i = 0; i < 10; ++ i) {

13 std :: cout << rand () << std :: endl ;


14 }
15 // Finish the program
16 r e t u r n 0;

17 }

We can save this program as random_seed.cpp compile this program with the following command:

1 g ++ - Wall - Wextra - Werror -O0 random_seed . cpp -o random_seed . bin

4 SOME COMPUTER SCIENCE FUNDAMENTALS 70


2D Game Development: From Zero To Hero

When we run the program, it will ask us to input a seed (which in our case is a number), after that it will just print

10 random numbers based on that seed. What would happen if we ran the program twice and use the same seed?

Figure 28: Running a random number generator with the same seed will always output the same numbers

Random numbers generated by computers are never truly random, that’s why they are more properly called “pseudo-

random numbers”.

4.7.1 How to seed a random number generator

From what we have seen earlier, the seed of our random number generator is something we need to be mindful

about.

Choosing a static seed will make our game completely deterministic (if played in the same conditions), like we didn’t

use random numbers at all.

Some games use internal timers to see the random number generator, be it the time that the game has been running,

the time that has passed from the beginning of the mission or something similar. This allows you to have some kind

of “controlled RNG” that still has a bit of reproducibility.

Some choices expose the game to the possibility of RNG manipulation: where the player has partial or total control

over the random number generator, by performing specific actions at specific times, for instance.

A very easy way to seed a generator is using the system time. Here’s a more advanced random number generator

that uses system time as its seed: if you run the program reasonably slow (not quicker than once a second) you will

see the numbers changing.

Listing 11: A random number generation program that uses system time as seed

4 SOME COMPUTER SCIENCE FUNDAMENTALS 71


2D Game Development: From Zero To Hero

1 #i n c l u d e < iostream >

2 #i n c l u d e < time .h >

3 i n t main () {

4 // First of all we get the seed


5 unsigned i n t seed = time ( nullptr );

6 // We print it for reference


7 std :: cout << " The current seed is : " << seed << std :: endl ;
8 // Now we seed the randomizer
9 srand ( seed );
10 // Small presentation
11 std :: cout << " This generator will now generate 10 random numbers " << std :: endl ;
12 // Output 10 random numbers
13 f o r ( i n t i = 0; i < 10; ++ i) {

14 std :: cout << rand () << std :: endl ;


15 }
16 // Finish the program
17 r e t u r n 0;

18 }

We can save this program as rand.cpp compile this program with the following command:

1 g ++ - Wall - Wextra - Werror -O0 rand . cpp -o rand . bin

This is the result of the program being run twice, one second apart:

Figure 29: Using the system time as RNG seed guarantees a degree of randomness

4.8 Estimating the complexity of algorithms

Now more than ever, you need to be able to be efficient. How do you know how “efficient” some piece of algorithm

is?

4 SOME COMPUTER SCIENCE FUNDAMENTALS 72


2D Game Development: From Zero To Hero

Seeing how much time it takes is not an option, computer specifications change from system to system, so we need

something that could be considered “cross-platform”.

This is where notations come into play.

There are 3 types of Asymptotic notation you should know: Ω, Θ and O.

Ω() represents a lower bound: this means that the algorithm will take at least as many cycles as specified.

O() represents an upper bound: it’s the most used notation and means that the algorithm will take at most as

many cycles as specified.

Θ() is a tight bound, used when the big-O notation and the big-Ω notation have the same value, which can help
define the behavior of the algorithm better.

We will now talk about the most common Big-O notations, from “most efficient” to “least efficient”.

Pitfall Warning!

Be mindful of one specific thing: these notations simply tie how the algorithm performs

in relation to how a certain variable grows (usually a dataset). If you know for certain

that a dataset stays relatively small, an algorithm with a “worse O() may not make a

huge difference or may even be more efficient.

4.8.1 O(1)

An algorithm that executes in O(1) is said to execute “in constant time”, which means that no matter how much

data is input in the algorithm, said algorithm will execute in the same time.

An example of a simple O(1) algorithm is an algorithm that, given a list of elements (with at least one element),

returns True if the first element is null.

Listing 12: Example of an O(1) algorithm

1 bool isFirstElementNull ( i n t *[] elements ){

2 r e t u r n elements [0] == nullptr ;

3 }

To be precise, this algorithm will perform both in O(1) and Ω(1), so it will perform in Θ(1).

4.8.2 O(log(n))

An algorithm that executes in O(log(n)) is said to execute in “logarithmic time”, which means that given an input of

n items, the algorithm will execute log(n) cycles at most.

An example of a O(log(n)) algorithm is the so-called “binary search” on a ordered list of items.

Listing 13: Example of an O(log(n)) algorithm (Binary Search)

4 SOME COMPUTER SCIENCE FUNDAMENTALS 73


2D Game Development: From Zero To Hero

1 i n t binarySearch ( i n t [] lst , i n t item ){

2 i n t first = 0;

3 i n t last = lst . size () - 1;

4 bool found = f a l s e ;

5 while ( first <= last && ! found ){

6 // Find the middle element


7 i n t midpoint = ( i n t ) ( first + last ) / 2;

8 i f ( lst [ midpoint ] == item ){

9 // We found it !
10 r e t u r n midpoint ;

11 } else {
12 i f ( item < lst [ midpoint ]) {

13 // Continue on the " first half "


14 last = midpoint - 1;
15 } else {
16 // Continue on the " second half "
17 first = midpoint + 1;
18 }
19 }
20 }
21 if (! found ){
22 // We return -1 to tell " not found "
23 r e t u r n -1;

24 }
25 }

The best case is the time when you get the element to find to be the “middle element” of the list, in that case the

algorithm will execute in linear time: Θ(1) - You need at least one lookup (Ω(1)) and at most one lookup (O(1)).

In the worst case, the element is not present in the list, so you have to split the list and find the middle element until

you realize that you don’t have any more elements to iterate - this translates into a tight bound of Θ(log2 n)

4.8.3 O(n)

An algorithm that executes in O(n) is said to execute in “linear time”, which means that given an input of n items,

the algorithm will execute at most n cycles.

An example of a simple O(n) algorithm is the one that prints a list, element by element.

Listing 14: Example of an O(n) algorithm (printing of a list)

1 #i n c l u d e < iostream >

2 void printList ( i n t [] list ){

3 f o r ( auto element : list ){

4 std :: cout << element << std :: endl ;


5 }
6 }

4 SOME COMPUTER SCIENCE FUNDAMENTALS 74


2D Game Development: From Zero To Hero

It’s evident that this algorithm will call the print function n times, where n is the size of the list. This translates in a

Θ(n) complexity, which is both O(n) and Ω(n).

There is no “best” or “worst” case here, the algorithm prints n elements, no matter their order, the alignment of

planets and stars or the permission of its parents.

4.8.4 O(n·log(n))

An algorithm that executes in O(n·log(n)) executes in a time slightly longer than a linear algorithm, but it’s still con-

sidered “ideal”. These algorithms are said to execute in “quasi-linear”, “log-linear”, “super-linear” or “linearithmic”

time.

Given an input of n elements, these algorithms execute n·log(n) steps, or cycles.

Some algorithms that run in O(n·log(n)) are:

• Quick Sort

• Heap Sort

• Fast Fourier Transforms (F.F.T.)

These algorithms are more complex than a simple example and would require a chapter on their own, so we’ll leave

examples aside for now.

4.8.5 O(n2 )

Quadratic algorithms, as the algorithms that execute in O(n2 ) are called, are the door to the “danger zone”.

These algorithms can eat your CPU time quite quickly, although they can still be used for small computations some-

what efficiently.

Given an input of n elements, these algorithms execute n2 cycles, which means that given an input of 20 elements,

we’d find ourselves executing 400 cycles.

A simple example of a quadratic algorithm is “bubble sort”. A pseudo-code implementation is written here.

Listing 15: Example of an O(n²) algorithm (bubble sort)

1 void bubbleSort ( i n t [] A){

2 n = A . size () ;
3 // Traverse Through all Elements
4 f o r ( i = 0; i < n; ++ i) {

5 // Last i elements are in place due to the nature of the sort


6 f o r ( j = 0; j < n - i - 1; ++ j ) {

7 // Swap if the element found is greater than the next element


8 i f (A[j] > A[j +1]) {

9 i n t tmp = A[j ];

10 A[ j] = A[j +1];
11 A[ j +1] = tmp ;
12 }

4 SOME COMPUTER SCIENCE FUNDAMENTALS 75


2D Game Development: From Zero To Hero

13 }
14 }
15 }

Anything with complexity higher than O(n2 ) is usually considered unusable.

4.8.6 O(2n )

Algorithms that execute in exponential time are considered a major code red, an will usually be replaced with heuristic

algorithms (which trade some precision for a lower complexity).

Given an input of 20 elements, an algorithm that executes in O(2n ) will execute 220 = 1 048 576 cycles!

4.9 A primer on calculating the order of your algorithms

4.9.1 Some basics

When you estimate an algorithm, you usually want to calculate how it functions “in the worst case”, which usually

means that all loops get to their end (of the list or the counter) and everything takes the longest time possible.

Let’s start with an example:

Listing 16: A simple O(1) algorithm

1 // A simple O (1) algorithm : assigning to a variable


2 i n t my_variable = 1;

This is a simple assignment operation, we are considering this instantaneous. So its complexity is O(1).

Now let’s see another algorithm:

Listing 17: A simple o(n) algorithm

1 // A simple O (n) algirithm : iterating through a list


2 #i n c l u d e < iostream >

4 f o r ( auto item : my_list ) {

5 std :: cout << item << std :: endl ;


6 }

In this case we are iterating through a list, we can see that as the list grows, the number of times we print an element

on our screen grows too. So if the list is n items long, we will have n calls to the output statement. This is an O(n)
complexity algorithm.

Now let’s take something we already saw and analyze it: the bubble sort algorithm:

Listing 18: The bubble sort algorithm, an O(n²) algorithm

1 void bubbleSort ( i n t [] A){

4 SOME COMPUTER SCIENCE FUNDAMENTALS 76


2D Game Development: From Zero To Hero

2 n = A . size () ;
3 // Traverse Through all Elements
4 f o r ( i = 0; i < n; ++ i) {

5 // Last i elements are in place due to the nature of the sort


6 f o r ( j = 0; j < n - i - 1; ++ j ) {

7 // Swap if the element found is greater than the next element


8 i f (A[j] > A[j +1]) {

9 i n t tmp = A[j ];

10 A[ j] = A[j +1];
11 A[ j +1] = tmp ;
12 }
13 }
14 }
15 }

This will require a small effort on our part: we can see that there are 2 nested loops in this code. What’s our worst

case? The answer is “The items are in the reverse order”.

When the items are in the reverse order, we will need to loop through the whole list to get the biggest item at the

end of the list, then another time to get the second-biggest item on the second-to-last place on the list… and so on.

So every time we bring an item to its place, we iterate through all the list once. This happens for each item.

So, in a list of length “n”, we bring the biggest item to its place “n times” and each “time” requires scanning “n”

elements: the result is n · n = n2 .

The algorithm has time complexity of O(n2 ).

4.9.2 What happens when we have more than one big-O?

There are times when we have code that looks like the following:

Listing 19: A more complex algorithm to estimate

1 // -------------------------------------
2 // A is an array of integers
3 i n t n = A . size () ;

4 bool swapped = f a l s e ;

5 do {

6 swapped = f a l s e ;
7 f o r ( i = 0; i < n; ++ i) {

8 i f (A[i -1] > A[i ]) {

9 i n t tmp = A [i -1];

10 A[i -1] = A[i ];


11 A[i] = tmp ;
12 swapped = t r u e ;
13 }
14 }
15 } while ( swapped ) ;
16

4 SOME COMPUTER SCIENCE FUNDAMENTALS 77


2D Game Development: From Zero To Hero

17 // -------------------------------------
18

19 f o r ( auto item : A){

20 std :: cout << item << std :: endl ;


21 }

As we can see the first part is the bubble sort algorithm, followed by iterating through the (now ordered) list, to print

its values.

We can calculate the total estimate as O(n2 ) + O(n) and that would be absolutely correct, but as the list grows,
the growth rate of O(n) is very minor if compared to O(n2 ), as can be seen from the following figure:

Figure 30: O(n) growth rate, compared to O(n²)

So we can drop the O(n) and consider the entire algorithm as an O(n2 ) algorithm in its entirety: this means that

when dealing with complexity estimates, you always keep the terms that have the largest “growth rate” (check the

Big-O estimates comparison section for more details).

4.9.3 A problem with asymptotic complexity

An important problem with asymptotic complexity is that it tends to hide coefficients and smaller terms, no matter

how important they may be.

Let’s take an example: we need to order a list of 500000 elements and we found two algorithms:

• Algorithm 1 works in O(n2 )


• Algorithm 2 works in O(n), but its “non-simplified” complexity is O(1000000n)

Which one would be more efficient? From a first inspection it may seem surprising that until we reach 1 million

elements, algorithm 1 is better performing.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 78


2D Game Development: From Zero To Hero

If we plot how the CPU cycles behave for each algorithm, we can see how the reality is different.

1.6e+12
1000000n

1.4e+12

1.2e+12

1e+12

8e+11

6e+11

4e+11

2e+11

0
0 200000 400000 600000 800000 1e+06 1.2e+06

Figure 31: When coefficients have important values, asymptotic complexity may trick us

4.9.4 What do we do with recursive algorithms?

When recursive algorithms are involved, things get a lot more complex, and they involve building recursion trees

and sometimes you’ll have to use the so-called “master theorem for divide-and-conquer recurrences”.

Such methods are outside the scope of this book as of now.

4.9.5 How do big-O estimates compare to each other?

Here we can see how big-O estimates compare to each other, graphically and how important it is to write not-

inefficient algorithms.

If we had to write it as an inequality, from more to least efficient, we would have something like this (only considering

Big-O notation):

O(1) < O(log n) < O(n) < O(n · log n) < O(n2 ) < O(2n )

4 SOME COMPUTER SCIENCE FUNDAMENTALS 79


2D Game Development: From Zero To Hero

Figure 32: Big-O Estimates, plotted

There is a very specific reason why the O(2n ) estimate is missing from the previous plot: we wouldn’t be able to

see anything worthwhile if it was included, as seen from the following plot:

Figure 33: How O(2n ) overpowers lower complexities

[This section is a work in progress and it will be completed as soon as possible]

4.10 Simplifying your conditionals with Karnaugh Maps

Karnaugh maps are a useful tool to simplify boolean algebra expressions, as well as identifying and potentially solving

race conditions.

The output of a Karnaugh Map will always be an “OR of ANDs”.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 80


2D Game Development: From Zero To Hero

The best way to explain them is to give an example.

Let’s take the following truth table:

Table 23: The first truth table we’ll simplify with Karnaugh Maps

A B f

0 0 0
0 1 1
1 0 1
1 1 0

Said table can contain any number of variables (we’ll see how to implement those). To be precise, this table repre-

sents the formula A XOR B (XOR means ‘exclusive or’).

Let’s arrange it into a double-entry table, like this (Values of A are on top, values of B are on the left):

A
0 1
0 0 1
B
1 1 0

Figure 34: Karnaugh Map for A XOR B

Now we have to identify the biggest squares or rectangles that contain 2n elements equal to 1 so that we can cover

all the “1” values we have (they can overlap). In this case we’re unlucky as we have only two small rectangles that

contain one element each:

A
0 1
0 0 1
B
1 1 0

Figure 35: Karnaugh Map where the elements of the two “rectangles” have been marked green and red

In this case, we have the result we want with the following formula: f = (A ∧ B̄) ∨ (Ā ∧ B)

Not an improvement at all, but that’s because the example is a really simple one.

4.10.1 “Don’t care”s

Karnaugh Maps show more usefulness when we have the so-called “don’t care”s, situations where we don’t care

(wow!) about the result. Here’s an example.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 81


2D Game Development: From Zero To Hero

Table 24: Truth table with a “don’t care” value

A B f

0 0 0
0 1 1
1 0 1
1 1 x

Putting this truth table into a Karnaugh map we get something a bit more interesting:

A
0 1
0 0 1
B
1 1 x

Figure 36: Karnaugh Map with a “don’t care” value

Now we have a value that behaves a bit like a “wild card”, that means we can pretend it’s either a 0 or 1, depending

on the situation. In this example we’ll pretend it’s a 1, because it’s the value that will give us the biggest “rectangles”.

A
0 1
0 0 1
B
1 1 1

Figure 37: Karnaugh Map where we pretend the “don’t care” value is equal to 1

Now we can find two two-elements rectangles in this map.

The first is the following one:

A
0 1
0 0 1
B
1 1 1

Figure 38: First Rectangle in the Karnaugh map

In this case, we can see that the result is 1 when B = 1, no matter the value of A. We’ll keep this in mind.

The second rectangle is:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 82


2D Game Development: From Zero To Hero

A
0 1
0 0 1
B
1 1 1

Figure 39: Second Rectangle in the Karnaugh map

In this case, we can see that the result is 1 when A = 1, no matter the value of B.

This translates into a formula of: f = (A) ∨ (B), considering that we don’t care about the result that comes out
when A = 1 and B = 1.

Note!

If instead of 1, we ended up choosing 0 for our “don’t care”, we would have obtained

f = (A ∧ B̄) ∨ (Ā ∧ B) (the extended form of A XOR B , which we saw earlier). For

our needs, this would have been a good solution too.

4.10.2 A more complex map

When we have more variables, like the following truth table:

A B C D f

0 0 0 0 0
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 0
0 1 1 0 1
0 1 1 1 0
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 x

4 SOME COMPUTER SCIENCE FUNDAMENTALS 83


2D Game Development: From Zero To Hero

Now we’ll have to group up our variables and put them in a Karnaugh Map using Gray Code, practically each row or

column differs from the adjacent ones by only one bit.

The resulting Karnaugh map is the following (AB on columns, CD on rows):

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 x 1
10 0 1 1 1

Figure 40: A more complex Karnaugh map

We can see two rectangles that contain 2n items, one with 2 items, the other with 8, considering the only “don’t

care” value as 1.

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 x 1
10 0 1 1 1

Figure 41: First rectangle of the more complex Karnaugh map

In this first rectangle, we can see that the values of C and D don’t matter towards the result, as well as the value of

B. The only variable that gives the result on this rectangle is A = 1. We’ll keep that in mind

Let’s see the second rectangle:

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 x 1
10 0 1 1 1

Figure 42: Second rectangle of the more complex Karnaugh map

In this case A doesn’t give any contribution to the result, but at the same time we need B = 1, C = 1 and D = 0
to get the wanted result.

D = 0 translates into D̄ = 1, which brings the formula to: f = A ∨ (B ∧ C ∧ D̄).

If we didn’t have that “don’t care” value, everything would have been more complex.

4.10.3 Guided Exercise

Let’s remove the “don’t care” value and have the following truth table:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 84


2D Game Development: From Zero To Hero

A B C D f

0 0 0 0 0
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 0
0 1 1 0 1
0 1 1 1 0
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0

Let’s put it into a Karnaugh Map:

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 0 1
10 0 1 1 1

Figure 43: Guided Exercise: Karnaugh Map (1/4)

Find the biggest rectangles:

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 0 1
10 0 1 1 1

Figure 44: Guided Exercise: Karnaugh Map (2/4)

4 SOME COMPUTER SCIENCE FUNDAMENTALS 85


2D Game Development: From Zero To Hero

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 0 1
10 0 1 1 1

Figure 45: Guided Exercise: Karnaugh Map (3/4)

AB
00 01 11 10
00 0 0 1 1
01 0 0 1 1
CD
11 0 0 0 1
10 0 1 1 1

Figure 46: Guided Exercise: Karnaugh Map (4/4)

Extract the result: f = (A ∧ C̄) ∨ (A ∧ B̄) ∨ (B ∧ C ∧ D̄)

4.11 Object Oriented Programming

4.11.1 Introduction

One of the biggest programming paradigms in use is surely the “Object Oriented Programming” (from now on:

“O.O.P.”) paradigm. The fundamental unit of a program, in this paradigm is the Object. This paradigm allows to

structure your code in a more modular and re-usable way, as well as implementing abstractions, allowing for more

solid code and making it possible for other code to make use of your own code without needing to know any details

besides its Interface.

4.11.2 Objects

Objects are the fundamental unit in O.O.P., objects are essentially a collection of data and functions. Objects are

actually the physical instantiation of what is called a “Class”.

To simplify the concept: a “Class” is a house blueprint, an “Object” is the house itself.

Objects contain data and functions, for the sake of precision, we will use their technical names:

• Functions that are part of an object are called methods and they can be classified as:

– Instance Methods when they act on a single object instance;

– Static Methods when they don’t (usually they’re utility functions), that also means that these methods

belong to the Class itself and not to its instance.

• Each piece of data contained in the class is called a Field and they can be classified as:

– Instance Fields when they’re part of the instance and can change from instance to instance;

– Static Fields when they’re part of the class but don’t change between instances (Caution: it does not

mean they cannot change, in that case the change will snowball into all the instances).

4 SOME COMPUTER SCIENCE FUNDAMENTALS 86


2D Game Development: From Zero To Hero

4.11.3 Abstraction and Interfaces

Abstraction is a fundamental point in O.O.P., and it is usually taken care of via so-called Interfaces.

Interfaces are the front-end that an object offers to other objects so they can interact.

As an example: the interface to your PC is given by Keyboard, Mouse and Screen - you don’t need to know how

the single electron travels through the circuits to be able to use a computer; same goes for a class that offers a

well-abstracted interface.

Being able to abstract a concept, removing the necessity to know the internal workings of the code that is used,

is fundamental to be able to write solid and maintainable code, because implementations change, but interfaces

rarely do.

Making classes work together with interfaces allows you to modify and optimize your code without having each edit

snowball into a flurry of compiler (or interpreter) errors. For instance: a rectangle class exposes in its interface a

method getArea() - you don’t need to know how to calculate the area, you just call that method and know it will return

the area of the rectangle.

The concept of keeping the internal workings of a class is called Information Hiding.

4.11.4 Inheritance and Polymorphism

One of the biggest aspects of O.O.P. is inheritance: you can create other classes based on a so-called “base class”,

allowing for extensibility of your software.

You can create a “Person” class, with a name, surname and age as fields, and by inheriting from the “Person” class

you can create a “Student” class, which has all the fields from Person, plus the “clubs” and “grade” fields.

This allows to create a “tree of classes” that represents part of your software.

From inheritance, O.O.P. presents a concept called Polymorphism (From “Poly” - Many, “Morph” - Shape), where

you can use the base class to represent the entire class tree, allowing for substitution.

In our “Person-Student” example, you could use a pointer to either a Person or a Student for the sake of getting their

first name.

In some languages it is possible for an object to inherit from multiple other objects, this is called “Multiple Inheritance”

4.11.5 Mixins

Mixins are classes that contain certain methods that are made to be used by other classes. We can see mixins as

some kind of interface with methods already implemented.

Mixins encourage the reuse of code (since the common functionalities get separated into their own classes), allowing

for some interesting mechanisms and enforcing the Dependency Inversion principle.

Many times, Mixins are described as “included” rather than “inherited”, due to their nature.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 87


2D Game Development: From Zero To Hero

Random Trivia!

The python web framework Django makes heavy use of mixins in its class-based views:

you can create a standard “View” (representing a web page, for instance), and then add

login protection (via LoginRequiredMixin) or permissions (via PermissionRequiredMixin).

This is all done using Python’s multiple inheritance.

A code example of mixins is beyond the scope of this book, since each language has its own way of implementing

mixins, some easy (like Python), other a bit more complex (like C++, see “Curiously Recurring Template Patterns”,

or C.R.T.P.).

4.11.6 The Diamond Problem

Usually when you call a method that is not present in the object itself, the program will look through the object’s

parents for the method to execute. This usually works well when there is no ambiguity. What if there is ambiguity

instead?

When multiple inheritance is involved, there is a serious possibility of a situation similar to the following

doStuff()

C B

doStuff() doStuff()

Figure 47: Example of a diamond problem

In this example, class A implements a method dostuff() that is overrode by both classes B and C (which inherit from

A): now class D inherits from both B and C but does not override dostuff(), which one will be chosen?

This is the reason many languages do not implement multiple inheritance between classes (like Java, which allows

multiple inheritance only between interfaces), other implement the so-called “virtual inheritance” (C++) and others

again use an ordered list to solve the problem (Python).

This is not something you usually need to worry about, but you may want to be careful when you structure your

classes to avoid “diamond problems”, so to avoid headaches.

4.11.7 Composition

As opposed to inheritance’s “IS-A” relationship, composition makes use of a “HAS-A” type of relationship.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 88


2D Game Development: From Zero To Hero

Composition allows to define objects by declaring which properties they have: a player character can be a sprite

with a “Movable” component, or a box could have a “RigidBody” component.

This way we can create new objects by reusing basic components, making maintenance easier as well as saving

lines of code, avoiding “the diamond problem” and reducing coupling.

4.11.8 Composition vs. Inheritance

Let’s be clear right from the get go: there is no “silver bullet” here. Composition and inheritance target different

problems (IS-A vs. HAS-A relationships). Inheritance binds classes closely, while composition tends to induce less

coupling (we’ll talk about coupling in a second).

Let’s make an example of inheritance: we have a “Shape” base class, from where we create two new classes:

Rectangle and Circle. For the purposes of our usage (which will be getting perimeter and area), Rectangle IS-A

Shape, as well as Circle IS-A Shape.

Listing 20: An example of inheritance: Shapes

1 c l a s s Shape {

2 // An abstract shape class


3 // An abstract function that will be overridden by subclasses
4 virtual f l o a t area () = 0;

5 // An abstract function that will be overridden by subclasses


6 virtual f l o a t perimeter () = 0;

7 };
8

9 c l a s s Rectangle : p u b l i c Shape {

10 // A simple rectangle class


11 f l o a t width ;

12 f l o a t height ;

13

14 Rectangle ( f l o a t w , f l o a t h){
15 width = w;
16 height = h;
17 }
18

19 f l o a t area () {

20 // Returns the Area of the rectangle


21 r e t u r n width * height ;

22 }
23

24 f l o a t perimeter () {

25 // Returns the Perimeter of the rectangle


26 r e t u r n 2 * ( width + height );

27 }
28 };
29

30 c l a s s Circle : p u b l i c Shape {

31 // A simple circle class


32 f l o a t radius ;

4 SOME COMPUTER SCIENCE FUNDAMENTALS 89


2D Game Development: From Zero To Hero

33

34 Circle ( f l o a t r) {
35 radius = r;
36 }
37

38 f l o a t area () {

39 // Returns the Area of the circle


40 r e t u r n 3.1415 * 3.1415 * radius ;

41 }
42

43 f l o a t perimeter () {

44 // Returns the circumference of the circle


45 r e t u r n 2 * 3.1415 * radius ;

46 }
47 };

Let’s continue with another example: we have a Coffee machine, such coffee machine HAS-A grinder, as well as

brewing unit. We can express such relationships with composition and build our coffee machine from our compo-

nents.

Listing 21: An example of inheritance: A coffee machine

1 #i n c l u d e < iostream >

3 c l a s s Grinder {

4 // A simple coffee grinder component


5 void grind () {

6 // Pretend to grind some coffee


7 std :: cout << " Grinding coffee " << std :: endl ;
8 }
9 };
10

11 c l a s s BrewingUnit {

12 // A simple brewing unit component


13 void brew () {

14 // Pretend to brew a good coffee


15 std :: cout << " Brewing your coffee " << std :: endl ;
16 }
17 };
18

19 c l a s s CoffeeMachine {

20 // A simple coffee machine , has a grinder and a brewing unit


21 Grinder grinder = Grinder () ;
22 BrewingUnit brewer = BrewingUnit () ;
23

24 void make_coffee () {

25 // Uses the brewing component and the grinder to make some fresh coffee
26 grinder . grind () ;
27 brewer . brew () ;
28 std :: cout << " Here 's your fresh coffee !" << std :: endl ;

4 SOME COMPUTER SCIENCE FUNDAMENTALS 90


2D Game Development: From Zero To Hero

29 }
30 };

4.11.9 “Composition over Inheritance” design

Often cited in programming, the “composition over inheritance” design states that code reuse and polymorphism

should be achieved using composition as the preferred method, while leaving subclassing (inheritance) alone as

much as possible.

This allows for easier code reuse, as well as more flexibility and less coupling. Let’s make a simple example.

Note!

If you’re having trouble understanding the diagrams that follow, head to the Reading

UML Diagrams section for a full explanation on UML.

Let’s imagine a physical object that can be Visible/Invisible, Solid/NonSolid and Movable/Immovable. In UML, an

inheritance hierarchy would look something like this:

Object

input();
update(dt);
draw();
collide();

VisibleObject InvisibleObject CollidableObject NonCollidableObject MovableObject ImmovableObject

draw(); draw(); collide(); collide(); update(); update();

Figure 48: How an object may look using inheritance

If we think of some objects, like a playable character, or a building, things get a lot more complicated: a playable

character is movable, solid and visible, while the building is not movable. Things can get ugly really fast.

Object

input();
update(dt);
draw();
collide();

ImmovableObject VisibleObject CollidableObject MovableObject InvisibleObject NonCollidableObject

update(); draw(); collide(); update(); draw(); collide();

Building PlayableCharacter

Figure 49: How inheritance can get complicated quickly

This can lead to confusion, as well as the diamond problem.

Using composition, we can separate the behaviours into the “Visible”, “Updatable” and “Movable” components and

then use those as “reusable puzzle pieces” for our objects.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 91


2D Game Development: From Zero To Hero

Implementations

ImmovableObject MovableObject InvisibleObject VisibleObject NonCollidableObject CollidableObject

update(); update(); draw(); draw(); collide(); collide();

Interfaces

Updatable Visible Collidable

update(); draw(); collide();

Objects

PlayableCharacter Building

visiblecomponent: Visible; visiblecomponent: Visible;


The fields will contain the following instances: The fields will contain the following instances:
collidablecomponent: Collidable; collidablecomponent: Collidable;
- visiblecomponent: VisibleObject - visiblecomponent: VisibleObject
- collidablecomponent: CollidableObject movablecomponent: Updatable; movablecomponent: Updatable; - collidablecomponent: CollidableObject
- movablecomponent: MovableObject update(); update(); - movablecomponent: ImmovableObject
draw(); draw();
collide(); collide();

Figure 50: How components make things a bit simpler

4.11.10 Coupling

Coupling is a term used to define the phenomenon where an edit to some part of a software snowballs into a bunch

of edits in parts of the software that depend on the modified part, and the part that depend on the previously edited

dependency, etc…

The parts involved are defined as “coupled” because, even though they are separated, their maintenance very much

behaves like they were a single entity. This also means that the elements that are coupled are harder to reuse, since

they are so tightly related that they end up serving each other and nothing else.

Introducing unnecessary coupling in our software will come back to bite us in the future, affecting maintainability in

a very negative way, since any edit we make (for instance, to fix a bug) can potentially lead to the need to edit the

rest of the software (or game) we are writing.

Reducing coupling is done by reducing interdependence, coordination and information flow between elements of a

program.

Examples of coupling include:

• A module uses code of another module (this breaks the principle of information hiding[g] );

• Many modules access the same global data;

• A module controls the flow of another module (like passing a parameter that decides “what to do”);

• Subclassing.

This means that it’s in our best interest to reduce code coupling as much as possible, following the good principles

of “nutshell programming” and following the SOLID principles, shown next.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 92


2D Game Development: From Zero To Hero

Note!

We may be tempted to try and “remove coupling completely”, but that’s usually a

wasted effort. We want to reduce coupling as much as possible and instead improve

“cohesion”. Sometimes coupling is unavoidable (as in case of subclassing). Balance is

the key.

4.11.11 The DRY Principle

DRY is a mnemonic acronym that stands for “Don’t Repeat Yourself” and condenses in itself the principle of reducing

repetition inside a software, replacing it with abstractions and by normalizing data.

This allows for each piece of code (and knowledge, since the DRY principle applies to documentation too) to be

unambiguous, centralizing its responsibilities and avoiding repetition.

Violations of the DRY principle are called “WET” (Write Everything Twice) solutions, which base themselves on

repetition and give higher chances of mistakes and inconsistency.

4.11.12 SOLID Principles

SOLID is a mnemonic acronym that condenses five principles of good design, to make code and software that is

understandable, flexible and maintainable.

• Single Responsibility: Each class should have a single responsibility, it should take care of one part of

the software specification and each change to said specification should affect only said class. This means

you should avoid the so-called “God Classes”, classes that take care of too much, know too much about the

system and in a nutshell: have too much responsibility in your software.

• Open-closed Principle: Each software entity should be open to extension, but closed for modification. This

means that each class (for instance) should be extensible, either via inheritance or composition, but it should

not be possible to modify the class’s code. This is practically enforcing Information Hiding.

• Liskov Substitution Principle: Objects in a program should be replaceable with instances of their subtypes

and the correctness of the program should not be affected. This is the base of inheritance and polimorphism,

if by substituting a base class with one of its children (which should have a Child-is-a-Base relationship, for

instance “Circle is a shape”) the program is not correct anymore, either something is wrong with the program,

or the classes should not be in a “IS-A” relationship.

• Interface Segregation: Classes should provide many specific interfaces instead of one general-purpose

interface, this means that no client should depend on methods that it doesn’t use. This makes the software

easier to refactor and maintain, and reduces coupling.

• Dependency Inversion: Software components should depend on abstractions and not concretions. This is

another staple of nutshell programming and O.O.P. - Each class should make use of some other class’s interface,

not its inner workings. This allows for maintainability and easier update and change of code, without having

the changes snowball into an Armageddon of errors.

[This section is a work in progress and it will be completed as soon as possible]

4 SOME COMPUTER SCIENCE FUNDAMENTALS 93


2D Game Development: From Zero To Hero

4.12 Designing entities as data

Sometimes it can be useful to design your entities as data, instead of making them into static objects that possibly

require a new release of your product.

Designing your objects as data allows you to use configuration files to create, configure, tinker and extend your

product, as well as allow for modifications by people who are fans of your game.

For instance, in a fantasy RPG you could have 3 types of enemies all defined as classes:

• Skeleton

• Zombie

• Ghost Swordsman

Which all have the same behavior but different animations and sprites.

These classes can inherit from an “entity” abstract class which defines the base behavior and then can be extended

to create each unique enemy.

Another idea could be designing an “entity” class that can be instantiated, and have a configuration file that defines

what each entity is and what its properties are.

An idea could be the following, using YAML:

Listing 22: Example of an entity declared as YAML data

1 entity :
2 name : skeleton
3 health : 10
4 damage_on_hit : 2.5
5 spritesheet : "./ skelly . png "
6 animations :
7 walking :
8 start_sprite : 4
9 frame_no : 4
10 duration : 0.2
11 attacking :
12 start_sprite : 9
13 frame_no : 2
14 duration : 0.1

Another often used alternative is JSON, which would look like this:

Listing 23: Example of an entity declared as JSON data

1 {
2 " entity ": {
3 " name ": " skeleton ",
4 " health ": 10 ,
5 " damage_on_hit ": 2.5 ,

4 SOME COMPUTER SCIENCE FUNDAMENTALS 94


2D Game Development: From Zero To Hero

6 " spritesheet ": "./ skelly . png ",


7 " animations ":{
8 " walking ":{
9 " start_sprite ": 4,
10 " frame_no ": 4,
11 " duration ": 0.2
12 },
13 " attacking ":{
14 " start_sprite ": 9,
15 " frame_no ": 2,
16 " duration ": 0.1
17 }
18 }
19 }
20 }

With more complex building algorithms, it is possible to change behaviors and much more with just a configuration

file, and this gives itself well to rogue-like games, which random selection of enemies can benefit from an extension

of the enemy pool. In fact, it’s really easy to configure a new type of enemy and have it work inside the game without

recompiling anything.

This allows for more readable code and a higher extensibility.

4.13 Reading UML diagrams

UML (Universal Modeling Language) is a set of graphical tools that allow a team to better organize and plan a software

product. Diagrams are drawn in such a way to give the reader an overall assessment of the situation described while

being easy to read and understand.

In this chapter we will take a look at 4 diagrams used in UML:

• Use Case Diagrams

• Class Diagrams

• Activity Diagrams

• Sequence Diagrams

4.13.1 Use Case Diagrams

Use Case Diagrams are usually used in software engineering to gather requirements for the software that will come

to exist. In the world of game development, use case diagrams can prove useful to have an “outside view” of our

game, and understand how an user can interact with our game.

Here is an example of a use case diagram for a game:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 95


2D Game Development: From Zero To Hero

GameMenu

Start The Game Remember to clear the menu stack!

Open the Options Menu

Player
Open the Credits Screen

Exit to Desktop

Figure 51: Example of a use case diagram

4.13.1.1 Actors

Actors are any entity that can interface with our system (in this case, our game) without being part of it. Actors can

both be human, machines or even other systems.

Actors are represented with a stick figure and can inherit from each other: this will create an “IS-A” relationship

between actors.

Ultimate User

Free User Power User

Authenticated User

Figure 52: Example of an actor hierarchy

In the previous example, we can see that a “Free User” is an “Authenticated User”, as well as a “Power User” (which

could be a paying user) is itself an “Authenticated User” while an “Ultimate User” (which could be a higher tier

of paying user) is a “Power User” (thus has all the “Power User” capabilities, plus some unique) and by transitive

property an “Authenticated User”.

As seen, inheritance between actors is represented with a solid line with a hollow closed arrow. Such arrow points

towards the “super-type” or “parent” from which the subject (or “sub-type”, or “child”) inherits.

This representation will come back in the UML language for other diagrams too.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 96


2D Game Development: From Zero To Hero

4.13.1.2 Use Cases

Use cases represent the functionalities that our system offers, and the relationships between them.

Use cases are represented with an ellipse with the name of the use case inside. Choosing the right name for a use

case is extremely important, since they will represent the functionality that will be developed in our game.

Start The Game

Figure 53: Example of a use case

4.13.1.2.1 Inheritance

As with many other elements used in UML, use cases can inherit from each other. Inheritance (also called “General-

ization”) is represented with a closed hollow arrow that points towards the parent use case.

Player

Website

Search By Name

Search

Search By Category

Search By Tag

Figure 54: Example of a use case hierarchy

4.13.1.2.2 Extensions

Use case extensions specify how and when optional behavior takes place. Extended use cases are meaningful

on their own and are independent from the extending use case, while the extending use case define the optional

behavior that may not have much sense by itself.

Extensions are represented via a dashed line with an open arrow on the end, labeled with the <<extend>> keyword,

pointing towards the extending use case.

System

«extend»
Login Help on Login

User

Figure 55: Example of a use case extension

4 SOME COMPUTER SCIENCE FUNDAMENTALS 97


2D Game Development: From Zero To Hero

4.13.1.2.3 Inclusions

Inclusions specify how the behavior of the included use case is inserted in the behavior of the including use case.

Inclusions are usually used to simplify large use cases by splitting them or extract common behaviors of two or more

use cases.

In this situation, the including use case is not complete by itself.

Inclusions are represented via a dashed line with an open arrow on the end, labeled with the <<include>> pointing

towards the included use case.

User

System

«include» Deposit

Customer Authentication
«include»
Withdraw

Figure 56: Example of a use case inclusion

4.13.1.3 Notes

In use case diagrams, as well as in many other UML diagrams, notes are used to jot down conditions, comments and

everything useful to better understanding the diagram that cannot be conveyed through a well definite structure

inside of UML.

Notes are shaped like a sheet of paper with a folded corner and are usually connected to the diagram with a dashed

line. Each note can be connected to more than one piece of the diagram.

You can see a note at the beginning of this chapter, in the use case diagram explanation.

4.13.1.4 Sub-Use Cases

Use cases can be further detailed by creating sub-use cases, like the following example.

Checkout

Customer «extends» Help

Checkout
«include»

Payment

Clerk

Figure 57: Example of a sub-use case

4.13.2 Class Diagrams

4.13.2.1 Classes

4 SOME COMPUTER SCIENCE FUNDAMENTALS 98


2D Game Development: From Zero To Hero

Class diagrams are used a step after analyzing your game, since they are used for planning classes. The central

element of a class diagram is the “class”, which is represented as follows:

ClassName

privateVariableType privateVariable
AbstractClassName
publicMethodName()
protectedMethodName() publicAbstractMethodName()
privateMethodName()
publicStaticMethod()

Figure 58: Example of classes in UML

Classes are made up by a class name, which is shown on top of the class; abstract classes are shown with a name

in italics.

Public members are highlighted by a “+” symbol (or in our case, a green symbol) before their name, protected

members use a “#” symbol (or a yellow symbol) and private members use a “-” symbol.

Static members are shown with an underlined name, while abstract members are shown in italics.

4.13.2.2 Interfaces

Sometimes there is a need to convey the concept of “interface” inside a UML class diagram, that can easily be done

in 2 ways:

• By using the class construct, with the keyword (called “stereotype”) <<interface>> written on top of it;

• By using the “lollipop notation” (also called “interface realization”).

«interface»
SearchInterface

SearchProvider

Figure 59: Defining an interface in UML

SearchInterface

SearchProvider

Figure 60: Interface Realization in UML

4.13.2.3 Relationships between entities of the class diagram

Expressing only single classes on their own doesn’t give UML a lot of expressive power when it comes to planning

your games. Here we’ll take a quick look at the most used relationships between classes.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 99


2D Game Development: From Zero To Hero

Generalization/ Interface Aggregation Composition


Association Dependency
Inheritance Realization

Figure 61: Relationships between classes in an UML Diagram

4.13.2.3.1 Inheritance

Inheritance is represented via a hollow closed arrow head that points towards the base class (exactly like in Actor

inheritance), this means that the classes are in a “super-type and sub-type” relationship.

Person

name: string
age: int

Student

grades: list
getGPA()

Figure 62: Example of inheritance in UML class diagrams

In this example we say that “Student IS-A Person” and inherits all Person’s methods and fields.

4.13.2.3.2 Interface realization

Interface realization can be complex to understand at first, given its formal definition:

The interface realization relationship specifies that the realizing class must conform to the contract that the

provided interface specifies.

In short, it means that the class is implementing all the methods specified by the interface (thus “realizing” it, as in

making it real).

Interface The "doStuff()" method is obligatorily


implemented, since the interface is
doStuff() "a contract" over what the class shall do.

ConcreteClass

doStuff()

Figure 63: Example of interface realization in UML class diagram

4.13.2.3.3 Association

4 SOME COMPUTER SCIENCE FUNDAMENTALS 100


2D Game Development: From Zero To Hero

Association represents a static relationship between two classes. This is usually represented with a solid line with

an arrow. The arrow usually shows the reading order of the association, so if you see an “Author” class and a “Book”

class, the “wrote” association will be pointing from the “Author” to the “Book” class.

In case the relationship is bi-directional, the arrow points are omitted, leaving only a solid line between the two

classes.

Person

name: string
age: int

0..*
subscriber
0..*

Magazine

title: string

Figure 64: Example of association in UML class diagrams

An example of an association is the relationship between a “Person” and a “Magazine”, such relationship is the

“Subscription”. In this case the relationship is bi-directional, since a “Magazine” can be subscribed by many people,

but a single “Person” can subscribe to many “Magazine”s.

4.13.2.3.4 Aggregation and Composition

Aggregation is a special case of the association relationship, and represents a more specific case of it. Aggregation

is a variant of a “has-a” relationship and represents a part-whole relationship.

Aggregation is represented with a hollow diamond and a line that points to the contained class, classes involved in

an aggregation relationships do not have their life cycles dependent one another, that means that if the container

is destroyed, the contained objects will keep on living. An example could be a teacher and their students, if the

teacher dies the students will keep on living.

Teacher
University
name: string
name: string
age: int

Student
UniversityDepartment
name: string
name: string
age: int

Figure 65: Example of aggregation and composition in UML class diagrams

Composition is represented with a filled diamond instead than a hollow one, in this case there is a life cycle de-

pendency, so when the container is destroyed the contents are destroyed too. Like when a university is dissolved,

4 SOME COMPUTER SCIENCE FUNDAMENTALS 101


2D Game Development: From Zero To Hero

its departments will cease to exist. Conversely, a teacher may have some students under their wing, but when a

teacher remains without students they won’t magically disappear: the teacher’s life cycle is independent from their

students’.

4.13.2.3.5 Dependency

The dependency relationship is the one that gives us the least amount of coupling, it represents a “supplier-client”

relationships, where the supplier supplies its functions (methods) to the client. The association is represented in a

dashed line with an open arrow that points towards the supplier.

This means that the client class requires, needs or depends on the supplier.

There are many categories of dependency, like <<create> or <<call>> that explain further the type of dependency

exists between the supplier and the client.

An example could be between a “Car Factory” and a class “Car”: the “CarFactory” class depends on the “Car” class,

and such dependency is an instantiation dependency.

CarFactory

Car

Figure 66: Example of dependency in UML class diagrams

4.13.2.4 Notes

As with Use Case diagrams, class diagrams can make use of notes too, and the graphical language used to represent

them is exactly the same one used in the Use Case Diagrams.

4.13.3 Activity Diagrams

Activity diagrams are the more powerful version of flow charts: they represent the flux of an activity in detail, allowing

to have a better understanding of a process or algorithm.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 102


2D Game Development: From Zero To Hero

Take Shopping cart

Take Item

Put Item in Shopping Cart

Delete Item name from Shopping list

yes
More Items in Shopping List?

no

Go to checkout

Pay

Figure 67: Example of an activity diagram

4.13.3.1 Start and End Nodes

Each diagram begins what a “start node”, represented with a filled black circle, and they end with an “end node”

which is represented with a filled black circle inside of a hollow circle.

Figure 68: Example of activity diagrams start and end nodes

4.13.3.2 Actions

Each action taken by the software is represented in the diagram via a rounded rectangle, a very short description of

the action is written inside the rounded rectangle space.

Delete Item name from Shopping list

Figure 69: Example of Action in activity diagrams

4.13.3.3 Decisions (Conditionals) and loops

4 SOME COMPUTER SCIENCE FUNDAMENTALS 103


2D Game Development: From Zero To Hero

Decisions and loops are enclosed in diamonds. If a condition needs to be written, the diamond can become an

hexagon, to make space for the condition to be written or guards can be used to express the condition.

Get Input number

yes no
number bigger than 0

Double the number Triple the number

Figure 70: Example of decision, using hexagons to represent the condition

Create random number between 0 and 10

Get input

Compare with number

[Wrong number]

[Right number]

You won

Figure 71: Example of loops, using guards to represent the condition

All the branches that depend on a condition start on the condition itself and end on a diamond, as shown below.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 104


2D Game Development: From Zero To Hero

There are more rows in table


yes

There are more cells in the row


yes

Read cell

yes
cell is even

Double the cell value Triple the cell value

Write cell value to console

Figure 72: Example of how nested loops and conditions are performed

Note!

Sometimes loops can make use of empty diamonds (called “merges”) to make the

diagram clearer.

4.13.3.4 Synchronization

Synchronization (or parallel processing) is represented in activity diagrams by using filled black bars that enclose

the concurrent processes: the bars are called “synchronization points” or “forks” and “joins”

Take Order

Send Order confirmation Process Order

Figure 73: Example of concurrent processes in activity diagrams

In the previous example, the activities “Send Order Confirmation” and “Process Order” are processed in parallel,

independently from each other, the first activity that finishes will wait until the other activity finishes before entering

the end node.

4.13.3.5 Swimlanes

Swimlanes are a way to organize and group related activities in columns. For instance a shopping activity diagram

4 SOME COMPUTER SCIENCE FUNDAMENTALS 105


2D Game Development: From Zero To Hero

can have the “Customer”, “Order”, “Accounting” and “Shipping” swimlanes, each of which contains activities related

to their own categories.

Customer Order Accounting Shipping

Place Order

Take Order

Process Order

Receive Confirmation Packaging

Record Shipping

Ship Order

Receive Order

Pay Bill

Close Order

Figure 74: Example of swimlanes in activity diagrams

4.13.3.6 Signals

Signals are used to represent how activities can be influenced or modified from outside the system. There are two

symbols used to represent signals.

The “Sent Signal” symbol is represented with a convex pentagon (which reminds an arrow going away from our

system), while the “Received Signal” is represented by a concave pentagon (which reminds a “slot” where the “sent

signal” symbol can connect to).

4 SOME COMPUTER SCIENCE FUNDAMENTALS 106


2D Game Development: From Zero To Hero

Customer Store

Search product

Put product in basket

Place Order

Accept Order

Take products from store

Deliver Products

Deliverer rings

Confirm Receipt

Figure 75: Example of signals in activity diagrams

4.13.3.7 Notes

As with Use Case and Class diagrams, Activity Diagrams can make use of notes, in the same way as the other two

diagrams we presented in this book do.

Take Shopping cart Make sure the shopping cart works well!

Take Item

Put Item in Shopping Cart

Delete Item name from Shopping list

yes
More Items in Shopping List?

no

Go to checkout

Pay

Figure 76: Example of a note inside of an activity diagram

4.13.3.8 A note on activity diagrams

4 SOME COMPUTER SCIENCE FUNDAMENTALS 107


2D Game Development: From Zero To Hero

The components of activity diagrams shown here are just a small part of the used components, but they should be

enough to get you started designing and reading most of the activity diagrams that exist.

4.13.4 Sequence Diagrams

Sequence diagrams are used to represents how objects (called “participants”) interact with each other and such

interactions are represented in a time sequence.

4.13.4.1 Lifelines

The central concept of sequence diagrams are lifelines: the represent the time a participant is “alive” and when it

is doing something.

WebServer

Request

Response

WebServer

Figure 77: Example of a sequence diagram lifeline

The time flows from top to bottom, a dashed line represents the participant exists (for instance an object is instan-

tiated in memory), while the rectangle that replaces the dotted line represents the participant being “active” (for

instance one of the object’s functions is called).

4.13.4.1.1 Participants

The participants don’t have to be actual classes, since sequence diagrams represent interactions at a “higher level”

than mere code-bound planning.

Some UML drawing software allows for custom shapes for each participant, like the following:

4 SOME COMPUTER SCIENCE FUNDAMENTALS 108


2D Game Development: From Zero To Hero

Generic_Participant Queue Collection


Actor Database

Actor Generic_Participant Queue Database


Collection

Figure 78: Some alternative shapes for participants

4.13.4.2 Messages

Each object (represented by a lifeline) communicates with other objects (and the “outside”) through “messages”.

Messages are represented by arrows and an example can be seen here:

Class_A Class_B Class_C

Found Message

Synchronous Message

Asynchronous Message

Self-message

Return

Lost Message

Class_A Class_B Class_C

Figure 79: Messages in a sequence diagram

Let’s analyze them one by one:

• Found Messages are messages that come from “outside”, from the perspective of the part of the system we

are analyzing, they may come from another system or even the user.

• Synchronous Messages and returns are messages that activate a class and wait for a “return message”.

These usually represent a synchronous function call (but it can represent a more abstract concept).

• Asynchronous Messages are messages that activate a class but don’t wait for a return value. These usually

represent asynchronous functions calls.

• Self-messages are messages from an object to itself, they usually represent an internal function call.

• Lost Messages are messages sent towards the “outside”, from the perspective of the part of the system we

are analyzing.

4.13.4.3 Object Instantiation and Destruction

4 SOME COMPUTER SCIENCE FUNDAMENTALS 109


2D Game Development: From Zero To Hero

Sometimes it may be useful to represent the instantiation and destruction of objects in a sequence diagram. UML

provides such facilities via the <<instantiate>>, <<create>> and <<destroy>> keywords, as well as a symbol for the de-

struction of an object.

Class_1

<<instantiate>> Class_2

doStuff()

result

<<destroy>>

Class_1 Class_2

Figure 80: Object instantiation and destruction in a sequence diagram

4.13.4.4 Grouping and loops

From time to time, we may need to represent a series of messages being sent in parallel, a loop, or just group some

messages to represent them in a clearer manner. This is where grouping comes of use: it has a representation based

on “boxes”, like the following:

Monte_Carlo_Calculator Input_Generator
User

compute()

loop [10000 times]

generate_input()

result

result

User
Monte_Carlo_Calculator Input_Generator

Figure 81: A loop grouping in a sequence diagram

4.13.4.5 Notes

4 SOME COMPUTER SCIENCE FUNDAMENTALS 110


2D Game Development: From Zero To Hero

Like all UML diagrams, it is possible to use notes to add some comments that may be useful for the interpretation

of our diagrams, like follows.

Class_1 Class_2

doStuff()

result

This is a note.

Class_1 Class_2

Figure 82: Example of notes in a sequence diagram

4.13.5 Other diagrams

UML is composed by a ton of diagrams that can be used to communicate with your teammates and organize your

work, among them we find:

• Component Diagrams;

• Communication Diagrams;

• Composite Structure Diagrams;

• Deployment Diagrams;

• Package Diagrams;

• Profile Diagrams;

• State Diagrams;

• Timing Diagrams.

In this chapter we just saw the ones that will help you the most when reading the rest of this book, as well as

effectively planning any project you have in mind.

4.14 Generic Programming

Sometimes it may be necessary (mostly in the case of containers) to have the same kind of code to work on different

data types, which means that we need to abstract types into variables and be able to code accounting for such

types.

Generic Programming is a blanket-term that defines a style of computer programming where algorithms are

written in terms of “to be specified later” data types, this usually applies to languages that make use of static

typing[g] .

4 SOME COMPUTER SCIENCE FUNDAMENTALS 111


2D Game Development: From Zero To Hero

4.15 Advanced Containers

This section is dedicated to give some basic explanation of some advanced containers that are used in computer

science, allowing us to make an informed choice when we want to implement some even more advanced containers

in the future.

We will include big-O performance counters for the basic functions of: adding/removing and item at the beginning,

adding/removing an item at the end, adding/removing an item in an arbitrary position and indexing at a certain

position.

This section is in no way exhaustive, but should be enough to make an informed decision on what containers to use

for our components, according to necessities.

Note!

This section will be purely theoretical and no code will be shown for any container, this

is because implementations vary wildly between programming languages and some of

these “advanced containers” are integrated in such languages.

4.15.1 Dynamic Arrays

In many languages, arrays are sized statically, with a size decided at compile time. This severely limits the array’s

usefulness.

Dynamic Arrays are a wrapper around arrays, allowing it to extend its size when needed. This usually entails some

additional operations when inserting or deleting an item.

Dynamic_Array

Capacity: 4
Filled: 3
Native_array

123

Figure 83: Dynamic Arrays Reference Image

4.15.1.1 Performance Analysis

Indexing an item is immediate, since arrays allow to natively index themselves.

Inserting an item at the beginning is a heavy task, since it requires either moving all the present items or rebuilding

the internal native array. Such operations require copying or moving each element, giving us a time complexity

averaging on O(n).

4 SOME COMPUTER SCIENCE FUNDAMENTALS 112


2D Game Development: From Zero To Hero

Dynamic_Array Dynamic_Array Dynamic_Array

Capacity: 4 Capacity: 4 Capacity: 4


Filled: 2 Filled: 2 Filled: 3
Native_array Native_array Native_array

0 12 0 12 012

Value to insert Value to insert

Figure 84: Adding an element at the beginning of a Dynamic Array

Inserting an item at the end, if we keep a pointer to the last item inserted, is an operation that usually happens

immediately (time complexity O(1)), but when the array is full, we need to instantiate a new native array (usually

double the size of the current one) and copy all elements inside the new array (operation that has time complexity

of O(n)). Since the number of O(1) operations outweighs by a long shot the number of O(n) operations, it’s possible to

demonstrate that in the long run appending an item at the end of a dynamic array has a time complexity averaging

around O(1).

Dynamic_Array Dynamic_Array

The array is full, doubling needed Doubling the size of the array

Capacity: 4 Capacity: 8
Filled: 4 Filled: 0
Native_array Native_array

1234
0 0

Value to Insert Value to Insert

Dynamic_Array Dynamic_Array

Inserting previously present elements Inserting new element

Capacity: 8 Capacity: 8
Filled: 4 Filled: 5
Native_array Native_array

1234 1234

0 0

Value to Insert

Figure 85: Adding an element at the end of a Dynamic Array

Inserting an item in an arbitrary position, much like inserting an item at the beginning requires moving some items

further into the array, potentially all of them (when the arbitrary position is the beginning of the array), thus giving us

a time complexity of O(n). Such operation could trigger an array resize, which has no real influence on the estimate.

Dynamic_Array Dynamic_Array Dynamic_Array


Moving the items Inserting the item

Capacity: 4 Capacity: 4 Capacity: 4


Filled: 2 Filled: 2 Filled: 3
Native_array Native_array Native_array

12 12 12 0
0 0

Value to insert Value to insert

Figure 86: Adding an element at an arbitrary position of a Dynamic Array

Some implementations of the Dynamic Arrays try to save space when the number of items goes lower than 1
4 of the
array capacity during a deletion, the internal array is rebuilt with half the size. Such operation has a time complexity

of O(n).

4 SOME COMPUTER SCIENCE FUNDAMENTALS 113


2D Game Development: From Zero To Hero

Some other implementations use a 1 3


4 / 4 rule, halving the array capacity when the item deletion brings the number
of items lower than 1 3
4 of the array and doubling it when an insertion makes the number of elements higher than 4
of the array capacity.

Note!

Not all programming languages have native support for arrays, for instance Python

normally uses lists (although it supports arrays via the array standard library).

Table 27: Performance table for Dynamic Arrays

Operation Average Cost

Indexing O(1)

Insert/Delete At Beginning O(n)

Insert/Delete At End O(1) amortized

Insert/Delete at position O(n)

Table 28: Summary Table for Dynamic Arrays

Container Name Dynamic Array

When To Use it All situations that require direct indexing of a container, but insertions and

removals are not extremely common, and usually take the form of “push back”

(insertion at the end)

Advantages Direct Indexing, Fast iteration through all the elements, given by the fact that

arrays are stored compact in memory, fast appending.

Disadvantages Slow insertions in arbitrary positions and at the head of the array.

4.15.2 Linked Lists

Linked Lists are a data structure composed by “nodes”, each node contains data and a reference to the next node in

the linked list. Differently from arrays, nodes may not be contiguous in memory, which makes indexing problematic.

Linked_List

Head

Data Next Data Next Data Next

Figure 87: Linked List Reference Image

4 SOME COMPUTER SCIENCE FUNDAMENTALS 114


2D Game Development: From Zero To Hero

Some implementations feature a pointer to the last element of the list, to make appending items at the end easier

and quicker.

Linked_List

Tail
Head

Data Next Data Next Data Next

Figure 88: Double-Ended Linked List Reference Image

4.15.2.1 Performance Analysis

Since we only have a handler on the first node, indexing requires us to scan all the elements until we reach the one

that was asked for. This operation has a potential time complexity of O(n).

Inserting an item at the beginning is immediate, we just need to create a new node, make it point at the current

head of the list and then update our “handle” to point at the newly created node. The number of operations is

independent of how many data we already have, so the time complexity is O(1).

Linked_List Linked_List Linked_List


0 0

Head Head Data Next Head Data Next

Value to insert (node)

0 Data Next Data Next Data Next Data Next Data Next Data Next Data Next Data Next Data Next

Data Next

Temporary Variable

Figure 89: Inserting a new node at the beginning of a linked list

Appending an item at the end has a time complexity that varies depending on the chosen implementation: if the

list has a reference to the final node, we just need to create a new node, update the final node’s reference (usually

called “next”) to point at the new node and then update the reference to the final node to point at the newly created

node (time complexity O(1)). If our queue doesn’t have such reference, we will need to scan the whole list to find

the final node (time complexity O(n)).

Linked_List Linked_List

Tail Tail
Head Head

Value to insert (node)


0

0 Data Next Data Next Data Next Data Next Data Next Data Next Data Next

Data Next

Figure 90: Inserting a new node at the end of a (double-ended) linked list

Inserting at an arbitrary position requires us to scan the list until we find the position that we want, after that we

just need to split and rebuild the references correctly, which is a fast operation.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 115


2D Game Development: From Zero To Hero

Linked_List Linked_List
Linked_List 0 0
Tail Tail
Tail Head
Head Data Next Head Data Next

Value to insert (node)

Data Next Data Next Data Next Data Next Data Next Data Next
0 Data Next Data Next Data Next

Data Next
Temporary Variable

Figure 91: Inserting a new node at an arbitrary position in a (double-ended) linked list

Table 29: Performance table for Linked Lists

Operation Average Cost

Indexing O(n)

Insert/Delete At Beginning O(1)

Insert/Delete At End O(1) for double-ended, o(n) otherwise

Insert/Delete at position time to search + O(1)

Table 30: Summary Table for Linked Lists

Container Name Linked List

When To Use it All situations that require quick insertions/removals, either on the head or the tail

(used as stacks or queues).

Advantages Very fast insertions/removals, quite fast iteration through all the elements.

Disadvantages Slow indexing at an arbitrary position. Sorting can be complex.

4.15.3 Doubly-Linked Lists

A doubly-linked list is a variation of a linked list where each node not only has a reference to its successor, but

also a reference to its predecessor. This allows for easy processing of the list in reverse, without having to create

algorithms that entail a huge overhead.

All the operations of insertion, indexing and deletion are performed in a similar fashion to the classic singly-linked

list we saw earlier, just with an additional pointer to account for.

Linked_List
Tail
Head

Prev Data Next Prev Data Next Prev Data Next

Figure 92: Doubly Linked List Reference Image

4 SOME COMPUTER SCIENCE FUNDAMENTALS 116


2D Game Development: From Zero To Hero

Table 31: Performance table for Doubly-Linked Lists

Operation Average Cost

Indexing O(n)

Insert/Delete At Beginning O(1)

Insert/Delete At End O(1)

Insert/Delete at position time to search + O(1)

Table 32: Summary Table for Linked Lists

Container Name Doubly-Linked List

When To Use it All situations that require quick insertions/removals, either on the head or the tail

(stacks or queues) or iterating through an entire list, forwards or backwards.

Advantages Very fast insertions/removals, quite fast iteration through all the elements.

Possibility of easily iterating the list in reverse order.

Disadvantages Slow indexing at an arbitrary position. Sorting can be complex.

4.15.4 Hash Tables

Hash Tables are a good way to store unordered data that can be referred by a “key”. These structures have

different names, like “maps”, “dictionaries” or “hash maps”.

The idea behind a hash map is having a key subject to a hash function[g] that will decide where the item will be

positioned in the internal structure.

Value

Hash Function

0 5

4 7

Figure 93: Hash Table Reference Image (Hash Table with Buckets)

4 SOME COMPUTER SCIENCE FUNDAMENTALS 117


2D Game Development: From Zero To Hero

The simplest way to implement a hash table is using an “array with buckets”: an array where each cell has a reference

to a linked list.

On average, finding an item requires passing the key through the hash function, such hash function will tell us where

the item is in our internal structure immediately. Thus giving a time complexity of O(1).

Inserting has more or less the same performance, the key gets worked through the hash function, deciding which

linked list will be used to store the item.

Deletion works in the same fashion, passing the key through the hash function and then deleting the value; giving

a time complexity of O(1)

Table 33: Performance table for Hash Tables

Operation Average Cost

Searching O(1)

Insert O(1)

Delete O(1)

Table 34: Summary Table for Hash Tables

Container Name Hash Table

When To Use it All situations that require accessing an element by a well-defined key quickly.

Building unordered data sets.

Advantages Fast insertions/removals, direct indexing (in absence of hash collisions) by key.

Disadvantages In case of a bad hashing function, it reverts to the performance of a linked list,

cannot be ordered.

4.15.5 Binary Search Trees (BST)

Binary search trees, sometimes called “ordered trees” are a container that have an “order relation” between their

own elements.

Left Data Right

15

Left Data Right Left Data Right

10 25

Left Data Right Left Data Right Left Data Right

8 11 30

Figure 94: Binary Search Tree Reference

4 SOME COMPUTER SCIENCE FUNDAMENTALS 118


2D Game Development: From Zero To Hero

The order relation allows us to have a tree that is able to distinguish between “bigger” and “smaller” values, thus

making search really fast at the price of a tiny slowdown in insertion and deletion.

Searching in a BST is easy, starting from the root, we check if the current node is the searched value; if it isn’t we

compare the current node’s value with the searched value.

If the searched value is greater, we search on the right child. If it is smaller, we continue our search on the left child.

Recursively executing this algorithm will lead us to find the node, if present. Such algorithm has a O(log(n)) time
complexity.

In a similar fashion, insertion will recursively check subtrees until the right spot of the value is found. The insertion

operation has the same time complexity as searching: O(log(n)).

Deletion is a bit more conceptually complex, since it’s necessary to maintain the ordering of the nodes. Such

operation has a time complexity of O(log(n)).

Table 35: Performance table for Binary Search Trees

Operation Average Cost

Searching O(log(n))

Insert O(log(n))

Delete O(log(n))

Table 36: Summary Table for Binary Search Trees

Container Name Binary Search Tree

When To Use it Situations that require good overall performance and requires fast search times.

Advantages Good insertion and removal times, searching on this structure is fast.

Disadvantages Given the nature of the data structure, there is no direct indexing, nor ordering.

4.15.6 Heaps

Heaps are a tree-based data structure where we struggle to keep a so-called “heap property”. The heap property

defines the type of heap that we are using:

• Max-Heap: For each node N and its parent node P, we’ll always have that the value of P is always greater or

equal than the value of N;

• Min-Heap: For each node N and its parent node P, we’ll always have that the value of P is always less or equal

than the value of N;

4 SOME COMPUTER SCIENCE FUNDAMENTALS 119


2D Game Development: From Zero To Hero

Left Data Right

33

Left Data Right


Left Data Right

34
35

Left Data Right Left Data Right Left Data Right Left Data Right

39 51 49 58

Figure 95: Heap Reference Image (Min-Heap)

Heaps are one of the maximally efficient implementation of priority queues, since the highest (or lowest) priority

item is stored in the root and can be found in constant time.

Table 37: Performance table for Heaps

Operation Average Cost

Find Minimum O(1) to O(log(n)), depending on the implementation


Remove Minimum O(log(n))
Insert Θ(1) to O(log(n)) depending on the implementation

Table 38: Summary Table for Heaps

Container Name Heap

When To Use it All situations where you require to find and/or extract the minimum or maximum

value in a container quickly; like priority queues.

Advantages Good general time complexity, maximum performance when used as priority

queues.

Disadvantages No inherent ordering, there are better solutions for general use.

4.15.7 Stacks

Stacks are a particular data structure, they have a limited way of working: you can only put or remove items on top

of the stack, plus being able to “peek” on top of the stack.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 120


2D Game Development: From Zero To Hero

Push Pop

Stack Pointer

Figure 96: How a stack works

Stacks are LIFO (Last in - First Out) data structures, and can be implemented with both a linked list or a cleverly-

indexed array.

Depending on the single implementation, the operation used to “pop” an item from the stack will also return the

element, ready to be used in an upcoming computation.

Stack Pointer

Array 1 5

Linked List 5 1

Stack Pointer

Figure 97: Array and linked list implementations of a stack

4.15.8 Queues

Queues are the exact opposite of stacks, they are FIFO (First in - First Out) data structures: you can put items on the

back of the queue, while you can remove from the head of the queue.

Enqueue
Dequeue

1 5

Figure 98: How a queue works

Depending on the single implementation, the operation used to “dequeue” an item from the queue will also return

the element just removed, ready to be used in an upcoming computation.

As with stacks, queues leverage limitations in their way of working for greater control over the structure itself.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 121


2D Game Development: From Zero To Hero

Usually queues are implemented via linked lists, but can also be implemented via arrays, using multiple indexes and

index-wrapping when iterating.

Head Tail

Array 1 5

Linked List 1 5

Head Tail

Figure 99: Array and linked list implementation of a queue

4.15.9 Circular Queues

Circular Queues are a particular kind of queues that are infinitely iterable, every time an iterator goes after the last

element in the queue, it will wrap around to the beginning.

Pointer

3
9

0 4

Figure 100: How a circular queue works

Circular Queues can be implemented via linked lists or cleverly indexed arrays, with all the advantages and disad-

vantages that such structures entail.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 122


2D Game Development: From Zero To Hero

Head Tail

Array 1 5

Linked List 1 5

Head Tail

Figure 101: Array and linked list implementation of a circular queue

4.16 The principle of locality

This is one of the most-talked about principles in computer science: it usually refers to the principle of “memory

locality”, but it may also refer to other kinds, like “temporal locality” or “branch locality”.

Let’s analyze the most common ones.

• Spatial locality: (sometimes called “memory locality”) if a certain region of storage (or memory) is refer-

enced, there is a good probability that nearby regions of storage (or memory) will be referenced in the near

future. This is true, for instance, in Arrays.

• Temporal locality: if a certain region of storage (or memory) is referenced, there is a good probability that

the same region will be referenced in the near future. CPU caches leverage this principle by copying recently-

used data into faster storage.

Temporal locality can be seen as a special case of spatial locality.

4.17 Treating multidimensional structures like one-dimensional ones

This is usually done when dealing with pointers, but we may need to use some math to deal with sprites and

animations too.

As we’ll see in the Sprite sheets section, it is more efficient to store sprites and animation frames in sprite sheets.

When dealing with frames of animation, we like our frames to be “one-dimensional”, each “cell” represents a certain

“time”.

0 1 2 3 4 5 6 7
Figure 102: The “easy way” of dealing with frames

When dealing with sprite sheets, we may find that our animation has frames saved in a “matrix” of some sort, like

4 SOME COMPUTER SCIENCE FUNDAMENTALS 123


2D Game Development: From Zero To Hero

so:

0 1 2

0 0 1 2

Height: 3
1 3 4 5
2 6 7
Width: 3

Figure 103: A sample sprite sheet with the same frames as before

The images we’ve just seen will help you understand how the following formulas work.

To convert from 2-dimensional (row, column) coordinates to a single index, the formula is:

index = width × row + column

Note!

Remember that in many programming languages arrays and similar structures are 0-

indexed. This is the system that will be used here.

If you’re using a language that indexes arrays starting from 1 (like Lua), these formulas

need to be changed a bit.

So if I want to know the index of the 3rd element of the second row, with index (2,1), the formula becomes:

index = 3 × 1 + 2 = 5

The inverse formula is the following:



row = ⌊ index ⌋
width

column = index%width

So if we wanted to know the (row,column) position of the frame with index 7 we would have:



row = ⌊ 7 ⌋ = ⌊2.33333⌋ = 2
3

column = 7%3 = 1

4 SOME COMPUTER SCIENCE FUNDAMENTALS 124


2D Game Development: From Zero To Hero

Note!

This can be done with structures with n dimensions, but the formula becomes a lot

more complex the more dimensions you add. We’ll stop at 2 for now.

4.18 Data Redundancy

When dealing with certain structures, there are operations that are inherently complex to do: let’s take for example

counting the elements in a list:

Listing 24: Counting the elements in a list

1 c l a s s List {

2 private :

3 Node * nodeList ;
4 // ...
5 public :

6 i n t getLength () {

7 i n t counter = 0;

8 Node * node = nodeList ;


9 while ( node ) {

10 counter = counter + 1;
11 node = node -> next ;
12 }
13 r e t u r n counter ;

14 }
15 };

It’s easy to see that an algorithm like this has a Θ(n) complexity, which may not be ideal for an operation as common

as finding the length of a list.

This is where data redundancy comes into play: the length of a list is an intrinsic property of the list itself, so why

not save it inside the “head” of our structure?

This will obviously require a bit more work in all the methods that will change the number of elements inside the list,

since we need to keep the “length” property in sync with the actual length of the list, but in exchange we can count

the elements in a list by doing a simple lookup.

Let’s see an example implementation:

Listing 25: Counting the elements in a list with data redundancy

1 c l a s s List {

2 private :

3 Node * nodeList ;
4 i n t length ;

5 // ...

4 SOME COMPUTER SCIENCE FUNDAMENTALS 125


2D Game Development: From Zero To Hero

6 public :

7 i n t getLength () {

8 r e t u r n length ;

9 }
10

11 void addItem ( Node * node ){

12 // ... Normal operation ...


13 // ...
14 // We update our length counter
15 length = length + 1;
16 }
17

18 void removeItem ( Node * node ){

19 // ... Normal removal operation ...


20 // ...
21 // We update our length counter
22 length = length - 1;
23 }
24

25 void clear () {

26 // ... Normal clear operation ...


27 // ...
28 // We clear the length too
29 length = 0;
30 }
31 // ...
32 };

Pitfall Warning!

It is extremely important that we keep our “redundant properties” synchronized with

the actual state of our objects, even when exceptions are raised. Not doing so will

create bugs.

Let’s consider another example: we have a standard linked list, like the one that follows:

Pointer

7 9 5

Figure 104: Singly-Linked List has no redundancy

Our “pointer” is pointing the node containing the number “5”, and now we want to know the value of the node that

precedes it. To do that we need to start from the head, saving in a temporary variable our nodes, until we find the

4 SOME COMPUTER SCIENCE FUNDAMENTALS 126


2D Game Development: From Zero To Hero

node pointed by our “pointer”.

Listing 26: Finding the previous element in a singly linked list

1 Node * get_previous_node ( List * lst , Node * current_node ){


2 Node * pointer = lst - > head ;
3 Node * previous = nullptr ;
4 while ( pointer != current_node ){

5 previous = pointer ;
6 pointer = pointer -> next ;
7 }
8 r e t u r n previous ;

9 }

This operation has O(n) complexity, which is not great. If we wanted to print a list in reverse with such technique,

the situation would be even worse.

Doubly-linked lists are another example of data redundancy. We are saving the content of the “previous” node, so

that we can do a simple lookup with complexity O(1) and easily (and efficiently) do our “reverse printing”.

7 9 5

Figure 105: A doubly linked list is an example of redundancy

4.19 Introduction to Multi-Tasking

When it comes to humans, we are used to have everything at our disposal immediately, but when it comes to

computers, each processing unit (CPU) is usually able to perform only one task at a time.

To allow for multi-tasking (doing many activities at once), the CPU switches between tasks at high speeds, giving

us the illusion that many things are happening at once. There are many methods to ensure multi-tasking without

process starvation[g] , the most used is pre-emption[g] where there are forced context switches between processes,

to avoid one hogging the CPU.

4.19.1 Multi-Threading vs Multi-Processing

Sometimes Multi-Threading and Multi-Processing are used interchangeably, but this is actually not correct. Let’s see

the differences between the two terms and how they contribute (in different ways) to allow multi-tasking.

Multi-Processing is a practice that makes use of multiple CPUs inside the same machine, this allows to process CPU-

intensive calculations in a parallel manner, thus gaining performance in our software. This style of parallelization is

usually done by spawning multiple processes, each of which will be run on a different CPU (or Core).

4 SOME COMPUTER SCIENCE FUNDAMENTALS 127


2D Game Development: From Zero To Hero

Process 1 Process 2

Figure 106: In a multi-processing environment, each CPU takes care of a task

Multi-Processing has some disadvantages: creating a process can be quite expensive and thus give us some tangible

overhead if processes are created and destroyed often.

Multi-Threading is a programming practice that allows to run different “lines of execution” (called “threads”), inside

of the same parent process, so to achieve the maximum possible CPU utilization.

Multi-Threading has the advantage of lower overhead, since threads are quite cheap to create, but also has some

more limitations when the tasks to execute are “CPU-bound” (take a lot of CPU time).

Process 1 Process 2

Figure 107: In multi-threading, the CPU uses I/O wait time to take care of another task

Multi-Threading works well when the threads are “I/O bound” (they use network or disk a lot, while the CPU usage

is low), this means essentially that while one thread is waiting for I/O (like loading an asset), another thread can

perform other calculations on the CPU instead of just “wait for the I/O to finish”.

4.19.2 Coroutines

If you search for the word “coroutine” online, you will find a lot of extremely convoluted explanations involving the

knowledge of the difference between preemptive[g] and non-preemptive multitasking, subroutines, threads and lots

more. Let’s try to make sense of this.

First of all, coroutines are computer programs can run in multitasking (so it can run separated from our main game

loop) which are used in non-preemptive multitasking. Differently from the preemptive style defined in the glossary,

in non preemptive multitasking the operating system never forces a context switch, but it’s the coroutine’s job to

yield the control over to another function.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 128


2D Game Development: From Zero To Hero

Instead of “fighting for resources”, coroutines politely free the processor and give control of it to something else

(could be the caller or another coroutine), this form of multitasking is often called cooperative multitasking.

A particularly interesting point of coroutines is the fact that their execution can be “suspended” and “resumed”

without losing its internal state. Coroutines are used in more advanced engines (using the Actor Model) and in some

particular situations. You may never need to use a single coroutine, or you may need to use them every day, so it’s

worth knowing at least what they are.

4.20 Introduction to Multi-Threading

When it comes to games and software, we usually think of it as a single line of execution, branching to (not really)

infinite possibilities; but when it comes to games, we may need to dip our toes into the world of multi-threaded

applications.

4.20.1 What is Multi-Threading

Multi-Threading means that multiple threads exist in the context of a single process, each thread has an independent

line of execution but all the threads share the process resources.

In a game, we have the “Game Process”, which can contain different threads, like:

• World Update Thread

• Rendering Thread

• Loading Thread

• …

Multi-Threading is also useful when we want to perform concurrent execution of activities.

4.20.2 Why Multi-Threading?

Many people think of Multi-Threading as “parallel execution” of tasks that leads to faster performance. That is not

always the case. Sometimes Multi-Threading is used to simplify data sharing between flows of execution, other

times threads guarantee lower latency, other times again we may need threads to get things working at all.

For instance let’s take a loading screen: in a single-threaded application, we are endlessly looping in the input-

update-draw cycle, but what if the “update” part of the cycle is used to load resources from a slow storage media

like a Hard Disk or even worse, an optical disk drive?

The update function will keep running until all the resources are loaded, the game loop is stuck and no drawing will

be executed until the loading has finished. The game is essentially hung, frozen and your operating system may

even ask you to terminate it. In this case we need the main game loop to keep going, while something else takes

care of loading the resources.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 129


2D Game Development: From Zero To Hero

4.20.3 Thread Safety

Threads and concurrent execution are powerful tools in our “programmer’s toolbox”, but as with all powers, it has

its own drawbacks.

4.20.3.1 Race conditions

Imagine a simple situation like the following: we have two threads and one shared variable.

Thread 1 Thread 2

Copy of Copy of
Variable Variable

Variable

1
Result Result

Figure 108: Two threads and a shared variable

Both threads are very simple in their execution: they read the value of our variable, add 1 and then write the result

in the same variable.

This seems simple enough for us humans, but there is a situation that can be really harmful: let’s see, in the following

example each thread will be executed only once. So the final result, given the example, should be “3”.

First of all, let’s say Thread 1 starts its execution and reads the variable value.

Read
Thread 1 Thread 2

Copy of Copy of
Variable Variable

Variable

1
Result Result

Figure 109: Thread 1 reads the variable

Now, while Thread 1 is calculating the result, Thread 2 (which is totally unrelated to Thread 1) starts its execution

and reads the variable.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 130


2D Game Development: From Zero To Hero

...
Read
Thread 1 Thread 2

Copy of Copy of
Variable Variable

1 Variable

1
Result Result

Figure 110: While Thread 1 is working, Thread 2 reads the variable

Now Thread 1 is finishing its calculation and writes the result into the variable.

...

Thread 1 Thread 2

Copy of Copy of
Variable Variable

1 Variable 1
1
Result Result

Write
Result

Figure 111: Thread 1 writes the variable

After That, Thread 2 finishes its calculation too, and writes the result into the variable too.

Thread 1 Thread 2

Copy of Copy of
Variable Variable

1 Variable 1
2
Result Result

2 2
Terminated
Write
Result

Figure 112: Thread 2 writes the variable

Something is not right, the result should be “3”, but it’s “2” instead.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 131


2D Game Development: From Zero To Hero

Thread 1 Thread 2

Copy of Copy of
Variable Variable

1 Variable 1
2
Result Result

2 2
Terminated Terminated

Figure 113: Both Threads Terminated

We just experienced what is called a “race condition”: there is no real order in accessing the shared variable, so

things get messy and the result is not deterministic. We don’t have any guarantee that the result will be right all

the time (or wrong all the time either).

4.20.3.2 Critical Regions

Critical Regions (sometimes called “Critical Sections”) are those pieces of code where a shared resource is used, and

as such it can lead to erroneous or unexpected behaviors. Such sections must be protected from concurrent access,

which means only one process or thread can access them at one given time.

4.20.4 Ensuring determinism

Let’s take a look at how to implement multi-threading in a safe way, allowing our game to perform better without

non-deterministic behaviors. There are other implementation approaches (like thread-local storage and re-entrancy)

but we will take a look at the most common here.

4.20.4.1 Immutable Objects

The easiest way to implement thread-safety is to make the shared data immutable. This way the data can only

be read (and not changed) and we completely remove the risk of having it changed by another thread. This is an

approach used in many languages (like Python and Java) when it comes to strings. In those languages strings are

immutable, and “mutable operations” only return a new string instead of modifying the existent one.

4.20.4.2 Mutex

Mutex (Short for mutual exclusion) means that the access to the shared data is serialized in a way that only one

thread can read or write to such data at any given time. Mutual exclusion can be achieved via algorithms (be careful

of out of order execution[g] ), via hardware or using “software mutex devices” like:

• Locks (known also as mutexes)

• Semaphores

• Monitors

• Readers-Writer locks

• Recursive Locks

4 SOME COMPUTER SCIENCE FUNDAMENTALS 132


2D Game Development: From Zero To Hero

• …

Usually these multi-threaded functionalities are part of the programming language used, or available via libraries.

Let’s see how Mutex solve our concurrency problem.

As seen before, we have a shared variable and two threads that want to add one to it.

Figure 114: How mutex works (1/8)

Now the first thread reads the variable and “locks” the mutex (thus stopping other threads from accessing the

variable).

Figure 115: How mutex works (2/8)

When the second thread wants to access the “critical region”, it will check on the Mutex, find it “locked” and be

forced to wait: it cannot read the variable, because we would have a “race condition” otherwise.

Figure 116: How mutex works (3/8)

As soon as the first thread finishes its job, it will write the result in the variable and “unlock” the mutex, allowing

others to access the variable.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 133


2D Game Development: From Zero To Hero

Figure 117: How mutex works (4/8)

Since the second thread was waiting, it will read the variable result (now 2) and “lock” the mutex for safety. The

second thread entered the “critical region”.

Figure 118: How mutex works (5/8)

The second thread will do its job as normal, if a third thread tried to access the variable, it would be stopped by the

locked mutex.

Figure 119: How mutex works (6/8)

When its job is done, the second thread will write to the variable and “unlock” the Mutex, thus allowing other threads

or processes to access the variable.

4 SOME COMPUTER SCIENCE FUNDAMENTALS 134


2D Game Development: From Zero To Hero

Figure 120: How mutex works (7/8)

Now both threads finished their jobs and the result inside the variable is correct.

Figure 121: How mutex works (8/8)

4.20.4.3 Atomic Operations

[This section is a work in progress and it will be completed as soon as possible]

4 SOME COMPUTER SCIENCE FUNDAMENTALS 135


2D Game Development: From Zero To Hero

5 A Game Design Dictionary

Why should you make games? Do it to give players joy from your unique

perspective and to have fun expressing yourself. You win and the players win.

Duane Alan Hahn

In this section we will talk about platforms, input systems and game genres, in a quick fashion. This chapter will

introduce you to the language and terms used in game design, this way the following chapters will be easier to

comprehend.

We will talk about the differences and challenges deriving from each decision and the basic way game genres work.

The objective of this chapter is giving you some terminology and knowledge about game design, before deep-diving

into the topic.

5.1 Platforms

There are several different platforms a game can be developed for, and each one has its own advantages and

drawbacks. Here we will discuss the most notable ones.

5.1.1 Arcade

Arcade cabinets have been around for decades, and have still a huge part in the heart of gaming aficionados with

classic series going on like “Metal Slug”. The main objective of these machines is to make you have fun, while forcing

you to put quarters in to continue your game.

These cabinets’ software is known to be very challenging (sometimes due to the fact that you’re popping quarters

into the machine for the “right to play”), having some nice graphics and sound. Arcade games are usually presented

in the form of an “arcade board”, which is the equivalent of a fully-fledged console, with its own processing chips

and read-only memory.

Figure 122: How an arcade machine usually looks like

5 A GAME DESIGN DICTIONARY 136


2D Game Development: From Zero To Hero

In the case of arcades, the hardware is usually tailored to support the software; with some exceptions added later

(like the Capcom Play System, also known as CPS), where the hardware is more stable between arcades, while the

software changes.

5.1.2 Console

Consoles are a huge (if not the biggest) part in the video game industry. Their Hardware is dedicated solely to

gaming (and some very marginal “multimedia functionalities”) and it evolves in “generations”: this means that

each “generation” has a stable hardware programmers can study and exploit.

Figure 123: A portable console

This hardware stability is a double-edged sword: the hardware can be really hard to master at the beginning, resulting

in some poor-performing games at the beginning of the generation, but when mastered the results are incredible.

This feeds into a cycle that looks like the following:

1. New Generation is introduced

2. Initial confusion, with poor performance and graphics

3. Hardware is mastered and games have great performance/graphics

4. The games become “too big” for the current generation and a new generation must be introduced.

5.1.3 Personal Computer

Personal Computers are another huge part of the video game industry. They are extremely flexible (being general-

purpose machines) but have a huge drawback: their hardware is not the same from one unit to the other. This means

that the programmer needs to use “abstraction layers” to be able to communicate with all the different hardware.

5 A GAME DESIGN DICTIONARY 137


2D Game Development: From Zero To Hero

Figure 124: A personal computer

This compounds with the fact that “abstraction layers” used by the developer (like SDL, SFML or GLFW) are running on

top of other “abstraction layers”, like sound servers, device drivers, etc… which can be littered with bugs themselves.

Just look at how many indirections we have on a modern Linux system (which is usually bundled with PulseAudio):

Game

SDL/SFML/GLFW

PulseAudio Library Layer

PulseAudio Engine

Linux Kernel Drivers

Sound Card

Figure 125: How many abstraction layers are used just for a game to be able to play sounds

This can have performance costs, as well as forcing the programmer to add options to lower graphic settings, reso-

lution and more.

5 A GAME DESIGN DICTIONARY 138


2D Game Development: From Zero To Hero

All of this just to be able to run on as many computers as possible. The upside is that when the computer is really

powerful, you can get great performance and amazing quality, but that’s a rare occasion.

5.1.4 Mobile

One of the most recent platforms game developers work on is right in your pocket: your smartphone.

Figure 126: A smartphone

Today’s smartphones have enough power to run fully-fledged video games, on the go. Sadly the touch screen can

prove to be really uncomfortable to use, unless the game is specially tailored for it.

5.1.5 Web

Another platform that has seen a massive rise in recent times is the Web: with WebGL and WebAssembly, fully-

fledged games (including 3D games) can run on our browser, allowing for massively-multiplayer experiences (like

Agar.io) without the hassle of manual installation or making sure the game is compatible with your platform.

Figure 127: Fully fledged games can run in your browser nowadays

A drawback of the “web approach” is the limited performance that web browsers, WebGL and WebAssembly can give,

as well as the need to download the game before being able to play (and sometimes you may need to re-download

the game if you cleared your browser’s cache).

5 A GAME DESIGN DICTIONARY 139


2D Game Development: From Zero To Hero

5.2 Input Devices

A game needs a way to be interacted with: this “way” is given by input devices. In this section we will take a brief

look at the input devices available in a game.

5.2.1 Mouse and Keyboard

One of the most common input devices, most of the currently available frameworks and engine have support for

input via mouse and keyboard. These input methods are great for visual novels, point and click adventures, FPS/TPS

games and anything that is considered to be “made for PCs”.

5.2.2 Gamepad

One of the classics of input devices, works well with the majority of games: FPS/TPS games may need some aim

assist mechanic in your game. Point and click adventures feel clunky with this input method.

As with Mouse and Keyboard, most of the currently available engines and frameworks support gamepads.

5 A GAME DESIGN DICTIONARY 140


2D Game Development: From Zero To Hero

5.2.3 Touch Screen

With the coming of smartphones, touch screen is a new input device that we have to account for. Touch screens

emulate computer mice well enough, although they lack precision.

The nature of being a mix between an input device and a screen brings a lot of new ways to experience a game

if well done. Many times touch screens are used to simulate game pads: the lack of the tactile feedback given by

buttons makes this simulation clunky and uncomfortable.

Some of the most recent framework and engines support touch screens, although there’s an additional layer of

complexity given by the specific operating system of the smartphone you’re building for.

5.2.4 Dedicated Hardware

Some games require dedicated hardware to work at their best, if at all. Guitars (guitar hero), wheels for racing

games, joysticks for flying simulators, arcade sticks for arcade ports…

Dedicated hardware requires precise programming, and is usually an advanced topic. On PCs many “dedicated input

devices” are recognized as “game pads” and use an “axis” and “buttons” abstraction that makes coding easier.

5.2.5 Other Input Devices

A special mention is deserved for all the input devices that are “general purpose” (as in not “dedicated”) but are

still in a group outside what we saw so far.

5 A GAME DESIGN DICTIONARY 141


2D Game Development: From Zero To Hero

In this group we see gyroscopes, accelerometers (like the Nintendo Wii/Switch JoyCons), sensors, IR, as well as other

exotic hardware that can still be exploited in a video game.

5.3 Game Genres

Let’s analyze some game genres to understand them better and introduce some technical language that may be

useful in writing a Game Design Document.

These genres are quite broad, so a video game is usually a mix of these “classes” (like a strategy+simulation game).

5.3.1 Shooters

Shooters are games that involve… shooting. They can include any kind of projectile (bullets, magic from a fairy,

arrows from a hunter) and can be crossed with any other genre (creating sub-genres in a way), like 2D platformers.

Some of the most known shooter genres are:

• FPS (first person shooters), 3D games where the game is shown from the point of view of the protagonist.

This involves only seeing a HUD and the weapon, instead of the whole character;

• TPS (third person shooters), 3D games where the game is shown from a behind-the-character perspective.

Some show the whole protagonist, while others adopt an over-the-shoulder perspective;

• Top Down Shooters, usually 2D games where you may be piloting a vehicle (space ship, plane, etc…) and

shoot down waves of enemies, in this category we fit arena shooters (like Crimsonland) and space shooters

(like Galaga);

• Side scroller shooters, usually 2D games and platformers, where you control the protagonist and shoot

enemies on a 2D plane, in this category we find games like Metal Slug.

5.3.2 Strategy

Strategy games involve long-term planning and resource control, they are slower games, but can be really intense

when played in competition with other players.

Some of the most popular strategy genres are:

• RTS (real time strategy), where units are controlled in real time;

• Turn-based strategy, where units and resources are managed in turns;

5.3.3 Platformer

Platformer games involve difficult jumps and precise movement, they can both be 2D and 3D games. A prime

example of platformer games is the Mario series: Mario 1,2,3 for 2D games and Mario 64 for 3D.

5.3.4 RPG

RPGs or “Role Playing Games” are games where you assume the role of a character in a fictional setting. In RPGs

the world is well-defined and usually have some level or class system and quite advanced item management.

5 A GAME DESIGN DICTIONARY 142


2D Game Development: From Zero To Hero

RPGs can be either action/adventure, with real-time actions, turn-based or hybrid, where the movement is done in

real time but battles happen in turns. Some prime examples of RPG games are the Legend of Zelda series, as well

as the Final Fantasy series.

5.3.5 MMO

MMO (Massively Multiplayer Online) is a term used for games that have a heavy multiplayer component via the

internet. The most known MMO genre is MMORPGs (Massively Multiplayer Online Role-Playing Games).

5.3.6 Simulation

Simulation games cover a huge variety of games that are created to “simulate reality”, in more or less precise ways.

Among simulation games we can find:

• Racing Games: sometimes more simulative others more arcade-like, racing games simulate the experience

of driving a vehicle, more or less realistic (from modern cars to futuristic nitro-fueled bikes);

• Social Simulation: simulating the interaction between characters, a pioneer on the genre is surely “The

Sims”;

• Farming simulation: simulating the quietude and work in the fields;

• Business simulation: like “game dev tycoon” or “rollercoaster tycoon”;

But there are also other kinds of simulations, like Sim City, where you manage an entire city.

5.3.7 Rhythm Games

Rhythm games are based on the concept of following a music beat as precisely as possible, this can be also used as

a “mechanic” in other types of games.

Some examples of Rhythm games are “Dance-Dance Revolution” (also known as DDR), as well as more innovative

games like “Crypt of the Necrodancer” (a mix between rhythm game and dungeon crawler).

5.3.8 Visual novels

Visual novels are graphical adventures whose primary objective is “telling a story”, they can be linear or have a

“choose your own path” component. They usually feature multiple endings and hand-crafted still images as artwork.

The more modern versions feature more interactive components and fully-fledged 3D graphics, but what ties the

genre together is usually a “point and click” style of gameplay.

5.3.9 Puzzle games

Puzzle games are centered about making the player think: they can test a lot of problem-solving skills from pattern

recognition, to word completion, to logic.

Some example of puzzle games include Lemmings, Boulder Dash, any match-3 game (started with “Shariki”, followed

by “Bejeweled” until the more modern titles for mobile phones), and Tetris.

5 A GAME DESIGN DICTIONARY 143


2D Game Development: From Zero To Hero

Puzzle games can involve math (like Sudoku), Physics (like the game “Peggle”), Hidden objects or even programming

(for instance “Shenzen I/O” for “realistic programming”, or “Opus Magnum” for a different approach).

Nothing stops other genres from including puzzle elements, but this small section is dedicated to the games that

feature puzzle elements as their core mechanic.

5.4 Miscellaneous

Here we will talk about some other terms that you may hear in the game development and design world, but that

don’t fit into a specific category.

5.4.1 Emergent Gameplay

Sometimes, when interacting with simple game mechanics, players can give life to complex situations. When that

happens usually we talk about “emergent gameplay”.

Emergent gameplay can take place in open-ended games, where there are many solutions to a situation and none

of them is “preferred by the game”. For instance, we can think of someone guarding a door, there are many ways

to get through the guard, such as:

• Attacking the guard (and winning);

• Find an alternative path;

• Sneak around the guard to knock them unconscious;

• Find a way to make the guard leave their post;

• …

Random Trivia!

A prime example of a game that leverages emergent gameplay is Minecraft. Players

can either survive, build palaces, build redstone circuits and much more.

5 A GAME DESIGN DICTIONARY 144


Part 2: Project Management
2D Game Development: From Zero To Hero

6 Project Management Basics and tips

Those who plan do better than those who do not plan even though they

rarely stick to their plan.

Winston Churchill

Project management is a very broad topic but I feel that some basics and tips should be covered in this book. Knowing

some project management can save you a lot of headaches and can make the difference between success and a

colossal failure.

6.1 The figures of game design and development

Before delving into the topic at hand, we need to familiarize ourselves with the main figures that are involved in the

process of game design and development, since you’ll probably (if you are the only developer of your game) have

to take upon all their tasks.

6.1.1 Producer/Project Manager

The producer is a figure that has experience in many fields and has an overall view of the project. They essentially

keep the project together.

Their duties are:

• Team Building (and its maintenance too);

• Distributing duties and responsibilities;

• Relations with the media.

Under the term “project manager” you can find different roles, among them:

• Product Manager;

• Assistant Producer;

• Executive producer.

A good project manager will need tools to manage tasks (Like a Kanban Board), as well as tools that promote

communication in the team (Chats, VoIP) and information repositories (having all information in the same place is

important!).

6.1.2 Game Designer

The game designer takes care of the game concept, usually (but not only!) working with really specific software,

usually provided by the programmers in the team (like specific level editors).

They design balanced game mechanics, manage the learning curve and take care of level design too.

Under the “Game Designer” term you can find different roles, among them:

• Level Designer;

6 PROJECT MANAGEMENT BASICS AND TIPS 146


2D Game Development: From Zero To Hero

• World Builder;

• Narrative Designer;

• Quest/Mission Designer.

A good game designer must know mathematics, some scripting and be able to use planning tools (again, our friendly

Kanban Board comes into play) as well as diagram drawing tools.

6.1.3 Writer

Writers are the ones who can help you give your game its own story, but also help with things that are outside the

mere game itself.

Some of their jobs include:

• Writing tutorial prompts;

• Writing narration;

• Writing dialogue;

• Writing pieces for the marketing of your game (sometimes known as “Copywriting”).

Under the term of “Writer” you can find more roles, like:

• Editor;

• Narrative Designer;

• Creative Writer.

A good writer must have good language skills, as well as creativity. They must be able to use planning programs

(like everyone, communication is important) as well as writing programs, like LibreOffice/OpenOffice Writer.

6.1.4 Developer

Logic and mathematics are the strong suit of programmers, the people who take care of making the game tick, they

can also have many specializations like:

• Problem Solver

• Game mechanics programmer;

• Controls programmer;

• AI developer;

• Visuals Programmer;

• Networking programmer;

• Physics programmer;

• …

They must be familiar with IDEs and programming environments, as well as Source Control Tools (Like Git), knowledge

of game engines like Unity is preferred, but also tied to the kind of game that is made.

6 PROJECT MANAGEMENT BASICS AND TIPS 147


2D Game Development: From Zero To Hero

6.1.5 Visual Artist

In 2D games visual art is as important as in 3D games and good graphics can really boost the game’s quality greatly,

as bad graphics can break a game easily.

Among visual artists we can find:

Both in 2D and 3D games:

• 2D Artists;

• Animators;

• Environment Artists;

• UI Artists/Designers;

• Conceptual Artists.

In 3D games:

• 3D Modelers;

• Texture Artists.

Visual Artists must be knowledgeable in the use of drawing programs, like Krita, GIMP or their commercial counter-

parts.

6.1.6 Sound Artist

As with graphics, sound and music can make or break a game. Sound artists may also be musicians, and their task

is to create audio that can be used in a video game, like sound effects, atmospheres or background music.

Under the umbrella of a sound artist, you can find:

• Audio Engineers;

• Game Composers;

• Music Mixers;

• Audio Programmers.

The knowledge of DAW (Digital Audio Workstation) software is fundamental, as well as knowing some so-called

“middlewares”, like FMOD. Another important bit of knowledge is being able to use Audio editors effectively.

6.1.7 Tester

Probably the most important job in a game development team, testing needs people with high attention to detail,

as well as the ability to handle stress well.

Testers are able to find, describe and help you reproduce bugs and misbehaviors of your game.

6 PROJECT MANAGEMENT BASICS AND TIPS 148


2D Game Development: From Zero To Hero

6.2 Some general tips

6.2.1 Be careful of feature creep

The “it would be cool to…” trap, formally called “feature creep”, is a huge problem in all projects that involve any

amount of passion in them.

Saying “it would be cool to do <insert something here>: let’s implement it!” can spiral out of control and make us

implement new features forever, keeping us from taking care of the basics that make a good game (or make a game

at all).

Try to stick to the basics first, and then eventually expand when your game is already released, if it’s worth it: first

make it work, then make it work well and only in the end make it elegant.

6.2.2 On project duration

When it comes to project management, it’s always tough to gauge the project duration, so it can prove useful to

remember the following phrase:

“If you think a project would last a month, you should add a month of time for unforeseen events. After that,

you should add another month for events that you really cannot foresee.”

This means that projects will last at least 3 times the time you foresee.

That may seem a lot like an exaggeration, but unforeseen events happen and they can have a huge impact on the

release of your game. It’s better to err on the side of caution and even delay the release if something goes wrong.

Shigeru Miyamoto said the following:

A delayed game is eventually good, a bad game is bad forever.

so maybe being “abundant” with your time estimates is not that wrong.

6.2.3 Brainstorming: the good, the bad and the ugly

Brainstorming is an activity that involves the design team writing down all the ideas they possibly can (without

caring about their quality yet).

This is a productive activity to perform at the beginning of the game development and design process, but it can be

a huge source of feature creep if done further down the line.

After the initial phase of brainstorming, the team analyzes the ideas and discards the impossible ones, followed by

the ones that are not “as good as they sounded at first”. The remaining ideas can come together to either form a

concept of a video game or some secondary component of it.

In short: brainstorming is a great activity for innovation, but since it’s essentially “throwing stuff at a wall and see

what sticks”.

6 PROJECT MANAGEMENT BASICS AND TIPS 149


2D Game Development: From Zero To Hero

This activity can sometimes be either unproductive or “excessively productive”: in both cases we end up with nothing

of use in our hands.

6.2.4 On Sequels

In case your game becomes a hit, you will probably think about making a sequel: this is not inherently a bad thing,

but you need to remember some things.

When developing a sequel, you will have to live up to your previous game, as well as the expectations of the players,

and this becomes more and more difficult as the “successful sequels” go on.

Not only a sequel must be “as good or better” than its predecessor, but also it should add something to the original

game, as well as the established lore (if there is any).

Your time and resource management must be top-notch to be able to “bring more with less”, since your need for

resources cannot skyrocket without a very good reason.

Also don’t get caught in the some kind of “sequel disease” where you end up making a sequel just to “milk the

intellectual property”: you will end up ruining the whole series: it may end up being hated by the ones who played

the first games, and new players will be discouraged by a series that either overstays its welcome, or has one or

more low-quality sequels.

6.3 Common Errors and Pitfalls

When you are making a new game, it’s easy to feel lost and “out of your comfort zone”, and that’s okay! It’s also

easy to fall into traps and pitfalls that can ruin your experience, here we take a look at the most common ones.

6.3.1 Losing motivation

Sometimes it can happen to lose motivation, usually due to having “too much ambition”: make sure you can develop

the kind of game you want to make, for instance leave multiplayer out of the question (multiplayer games are really

hard and network code can be a real pain to work on). It will just suck up development time, and it isn’t that much

of an important feature anyway (and it can still be implemented later, like it happened in Stardew Valley).

Like in music, many people prefer “mediocrity” to “something great”, so don’t force yourself to innovate: do things

well enough and if the innovative idea comes, welcome it.

If you get tired, take a break, you’re your own boss, and no one is behind you zapping you with a cattle prod: just

focus on making a good overall product and things will go well.

6.3.2 The “Side Project” pitfall

It happens: you have a ton of ideas for games of all kinds, and probably you’ll start thinking:

What’s bad about a small “side project”? I want to change things up a bit…

6 PROJECT MANAGEMENT BASICS AND TIPS 150


2D Game Development: From Zero To Hero

You will end up having lots of “started projects” and nothing finished, your energy will deplete, things will become

confusing and you won’t know what game you’re working on anymore.

Instead, make a small concept for the new mechanic and try to implement it in your current game, you may find a

new mix that hasn’t been tried before, making your game that much more unique.

6.3.3 Making a game “in isolation”

While making a game you will need to gather some public for it, as well as create some hype around it: making a

game on your own without involving the public is a mistake that deprives you of a huge source of suggestions and

(constructive) criticism (as well as satisfaction, when you manage to get some people interested in your game).

Make your game public, on platforms like itch.io or IndieDB, get feedback and encouragement. Create trailers towards

the end of development, put them on YouTube or Vimeo and if you want to go all out, get in touch with the press (locally

first) and create hype around your product.

6.3.4 (Mis)Handling Criticism

Among all the other things that are happening, we also need to handle feedback from our “potential players”, and

this requires quite the mental effort, since we can’t make it “automatic”.

Not all criticism can be classified as “trolling”, and forging our game without listening to any feedback will only mean

that such game won’t be liked by as many people as we would like, maybe for a very simple problem that could

have been solved if only we listened to them.

At the same time, not all criticism is “useful” either, not classifying criticism as “trolling” does not mean that trolling

doesn’t exist, some people will take pride in ruining other people’s mood, either by being annoying and uselessly

critic, or by finding issues that don’t actually exist.

The question you should ask yourself is simple:

Is this criticism I’m receiving constructive? Can it make my game better?

If the answer is no, then you may want to ignore such criticism, but if it is constructive, maybe you want to keep it

in consideration.

6.3.4.1 Misusing of the Digital Millennium Copyright Act

This is what could be considered the apex of mishandling criticism: the usage of DMCA takedowns to quash criticism

towards your game.

6 PROJECT MANAGEMENT BASICS AND TIPS 151


2D Game Development: From Zero To Hero

Note!

What follows is not legal advice. I am not a lawyer.

If you want to know more (as in quantity and quality of information), contact your

favorite lawyer.

Sadly, mostly in the YouTube ecosystem, DMCA takedowns are often used as a means to suppress criticism and

make video-reviews disappear from the Internet. Useless to say that this is potentially illegal as well as definitely

despicable.

Takedowns according to the DMCA are a tool at your disposal to deal with copyright infringements by people who

steal part (or the entirety of) your work, allowing (in the case of YouTube at the very least) to make the allegedly

infringing material. This should be used carefully and just after at the very least contacting the alleged infringer

privately, also because there is an exception to the copyright rule.

6.3.4.1.1 The Fair Use Doctrine

The so-called “Fair Use” is a limited exception to the copyright law that targets purposes of review, criticism, parody,

commentary, and news reporting, for instance.

The test for “Fair use” has four factors (according to 17 U.S.C. §107):

1. The Purpose and character of the use: if someone can demonstrate that their use advances knowledge

or the progress of arts through the addition of something new, it’s probably fair use. This usually is defined

by the question “is the work transformative enough?”

2. The nature of the copyrighted work: For instance, facts and ideas are not protected by copyright, but

only their particular expression or fixation is protected. Essentially you can’t really sue someone for making

a game very similar to yours (For instance making a 2D sidescrolling, run’n’gun platformer).

3. The amount and substantiality of the portion used in relation to the work as a whole: If someone

uses a small part (compared to the whole) of the work, and if that part is not really substantial, then it’s

probably fair use.

4. The effect on the potential market for the copyrighted work: this defines if the widespread presence

of the “allegedly infringing use” can hinder on the copyright owner’s ability to exploit (earn from) their original

work.

There can also be some additional factors that may be considered, but these four factors above are usually enough

to decide over the presence (or absence) of fair use.

6.3.4.1.2 The “Review Case”

Let’s take a simple example: a video-review on our brand new video game, that takes some small pieces of gameplay

(totaling about 5 minutes), on video and comments on the gameplay, sound and graphics. A very common scenario

with (I hope) an unsurprising turnout.

6 PROJECT MANAGEMENT BASICS AND TIPS 152


2D Game Development: From Zero To Hero

Let’s take a look at the first point: the purpose is criticism, the review brings something new to the table (essentially

it is transformative): someone’s impression and comments about the commercial work.

Second point: the game is an interactive medium, while the review is non-interactive by nature, the mean of trans-

mission is different.

Third point: considering the average duration of 8 to 10 hours of a video game, 5 minutes of footage amounts for

around 0.8% to 1% of the total experience, that’s a laughable amount compared to the total experience.

Fourth Point: this is the one many people may get wrong. A review can have a huge effect on the market of a

copyrighted work (a bad score from a big reviewer can result in huge losses), but that’s not really how the test

works. The fourth test can usually be answered by the following questions:

What’s the probability that someone would buy (or enjoy for free) the work from the alleged infringer, instead

than from me (the copyright owner)?

This is called “being a direct market substitute” for the original work. The other question is:

Is there a potential harm (other than market substitution) that can exist?

This usually is related to licensing markets. And here lies the final nail on the coffin: there is no direct market

substitution and courts recognize that certain kinds of market don’t negate fair use, and reviews are among those

kinds of market. In essence Copyright is not a shield against adverse criticism.

6.3.5 Not letting others test your game

This is a common mistake when you are focused on making the game: using your own skill as a “universal measure”

for the world’s skill level. You may be an unknown master at 2D platformers, and as such what is “mildly difficult”

for you may be “utterly impossible” for the average player. Or the opposite.

Try to keep the challenge constant through the levels, applying the usual slight upwards curve in difficulty that most

games have (or check the section about difficulty curves for some ideas), and let others test your game.

A beta version with feedback capabilities (or just a beta version and a form or email address can do the trick too) is

pure gold when it comes to understanding what your players think about the game’s challenge level.

Remember: when a level is (perceived as unfairly) too hard, players will stop playing the game.

6.3.6 Being perfectionist

If you are called “perfectionist” by your friends, that should be a red flag in your game development process from

the very beginning.

Finding yourself honing the game over and over, allocating countless hours (that always feel as “not enough”) into

making the game “better”, will end up just sabotaging the development process itself.

6 PROJECT MANAGEMENT BASICS AND TIPS 153


2D Game Development: From Zero To Hero

Instead try to prefer a more “scientific approach”, where you study your game’s shortcomings (with the help of some

testers, or “friend-made-tester”), order them by their “effort vs improvement” ratio and start with those who require

the lowest effort compared to the improvements they bring.

Quality
I
3. After a certain point, we have
diminishing returns with increasing effort.

2. After studying the situation,


working on small things can give
great quality improvements
without much effort.

1. Understanding what needs to be improved


requires effort without giving much result

Effort

Figure 128: How to approach improvements on your game

You can see that you can get really good returns for relatively little effort, but if you’re a perfectionist, you may want

to push forward and put more and more hours, with diminishing returns.

This means that when you have:

• Good Visuals and Good Audio

• Working Gameplay

• A challenge that lasts the test of time

• The testing phase completed

You have a complete product. Release it. Updating it is very easy these days, and maybe that will give you the

mental energy to undertake a new game. Maybe a sequel even?

6.3.7 Using the wrong engine

The game engine is one of the most important decisions you can take at the beginning of your game development

journey. Realizing that you used the wrong engine after months of development can be a huge setback, as well as

a “black hole” for your motivation.

Don’t trust market hype over an engine, and don’t trust the vendor’s promises either.

Does the game engine have the features you will need already? No? Then your money should stay where it is, and

you should look somewhere else.

6 PROJECT MANAGEMENT BASICS AND TIPS 154


2D Game Development: From Zero To Hero

If such engine’s producer is promising the feature you want in future, don’t trust it, that version may come, or it may

never come at all. If you bought the engine and such feature won’t ever be there, your money won’t come back.

6.4 Software Life Cycle Models

When talking about project management (in itself or in the broader field of Software Engineering) it is really useful

to talk about some guideline models that can be used to manage your project.

6.4.1 Iteration versus Increment

Before getting to the models, we need to discuss the difference between two terms that are often used interchange-

ably: “iteration” and “increment”.

Iteration is a non-deterministic process, during an iteration you are revisiting what you have already done, and

such revisiting can include an advancement or a regression. While iterating, you have no idea when you will finish

your job.

Increment is deterministic instead, with increments you are proceeding by additions over a base. Every increment

creates a “new base” for the next increments, and increments are numbered and limited, giving you an idea of when

you have to finish your job.

6.4.2 Waterfall Model

The Waterfall model, also known as “sequential model” is the simplest one to understand, easily repeatable (in

different projects) and is composed by phases that are strictly sequential, which means:

• There is no parallelism;

• There is no overlap between phases;

• When a phase is completed, you cannot go back to it.

Analysis Planning Production Maintenance

Figure 129: Diagram of the waterfall life cycle model

This makes the Waterfall life cycle model extremely rigid, everything needs to be carefully analyzed and documented

(sometimes people define this model “document-driven”) and the coding is done only in its final phases.

In order to have a good result, this model requires quantifying some metrics (time spent, costs, …) and such quan-

tification heavily relies on the experience of the project manager and the administrators.

6.4.3 Incremental Model

When a project of a certain size is involved, it’s a bad idea to perform the so-called “big-bang integration” (inte-

grating all the components together). Such approach would make troubleshooting a nightmare, so it’s advisable to

incrementally integrate the components.

6 PROJECT MANAGEMENT BASICS AND TIPS 155


2D Game Development: From Zero To Hero

The Incremental Model allows to have a “high-level analysis and planning”, after that the team decides which features

should be implemented first. This way the most important features are ready as soon as possible and have more

time to become stable and integrate with the rest of the software.

Analysis

High-level Planning
The number of iterations
is fixed

Detail Planning

Release 1
Release 2
Production ..........
Release n

Figure 130: Diagram of the incremental life cycle model

This model can make use of strictly sequential phases (detail planning -> release -> detail planning -> release …)

or introduce some parallelism (for instance planning and developing frontend and backend at the same time).

As seen from the diagram, the high-level analysis and planning are not repeated, instead the detail planning and

release cycle for a well-defined number of iterations, and on each iteration we will have a working release or proto-

type.

6.4.4 Evolutionary Model

It’s not always possible to perfectly know the outline of a problem in advance, that’s why the evolutionary model

was invented. Since needs tend to change with time, it’s a good idea to maintain life cycles on different versions of

your software at the same time.

Initial
Specification Version

High Level Intermediate


Development
Description Versions

Validation Final
Version

Figure 131: High-level diagram of the evolutionary life cycle model

Adding a way to implement the feedback you get from your customers and stakeholders completes the micro-

managed part of the life cycle model, each time feedback and updates are implemented, a new version is released.

6 PROJECT MANAGEMENT BASICS AND TIPS 156


2D Game Development: From Zero To Hero

Analysis

Planning

Detail Planning

Production and Release

Incorporation
Delivery
of Feedback

Customer Feedback

Figure 132: Diagram of the evolutionary life cycle model

6.4.5 Agile Software Development

Agile Software Development was born as a reaction to the excessive rigidity of the models we’ve seen so far. The

basic principles of Agile Software Development are presented at the http://agilemanifesto.org website, but we will

shortly discuss them below.

• Rigid rules are not good;

• A working software is more important than a comprehensive documentation;

• Seek collaboration with the stakeholder instead of trying to negotiate with them;

• Responding to change is better than following a plan

• Interactions and individuals are more important than processes and tools.

Obviously not everything that shines is actually gold, there are many detractors of the Agile model, bringing on the

table some criticism that should be noted:

• The agile way of working entails a really high degree of discipline from the team: the line between “flexibility”

and “complete lack of rules” is a thin one;

• Software without documentation is a liability more than an asset: commenting code is not enough - you need

to know (and let others know) the reason behind a certain choice;

• Without a plan, you can’t estimate risks and measure how the project is coming along;

• Responding to change can be good, but you need to be aware of costs and benefits such change and your

response entail.

6.4.5.1 User Stories

Agile models are based on “User Stories”, which are documents that describe the problem at hand.

Such documents are written by talking with the stakeholder/customer, listening to them, actively participating in

the discussion with them, proposing solutions and improvements actively.

6 PROJECT MANAGEMENT BASICS AND TIPS 157


2D Game Development: From Zero To Hero

A User Story also defines how we want to check that the software we are producing actually satisfies our customer.

6.4.5.2 Scrum

The term “scrum” is taken from the sport of American Football, where you have an action that is seemingly product

of chaos but that instead hides a strategy, rules and organization.

Let’s see some Scrum terminology:

• Product Backlog: This is essentially a “todo list” that keeps requirements and features our product must

have;

• Sprint: Iteration, where we choose what to do to create a so-called “useful increment” to our product. Each

Sprint lasts around 2 to 4 weeks and at the end of each sprint you obtain a version of your software that can

be potentially sold to the consumer;

• Sprint Backlog: Essentially another “todo list” that keeps the set of user stories that will be used for the

next sprint.

As seen from the terminology, the Scrum method is based on well-defined iterations (Sprints) and each sprint is

composed by the following phases:

• Sprint Planning: You gather the product backlog and eventually the previous sprint backlogs and decide

what to implement in the upcoming sprint;

• Daily Scrum: A daily stand-up meeting that lasts around 15 minutes where a check on the daily progress is

done;

• Sprint Review: After the sprint is completed, we have the verification and validation of the products of the

sprint (both software and documents);

• Sprint Retrospective: A quality control on the sprint itself is done, allowing for continuous improvement

over the way of working.

6.4.5.2.1 Criticisms to the Scrum approach

The Scrum approach can quickly become chaotic if User Stories and Backlogs are not well kept and clear. Also, no

matter how short it can be, the Daily Scrum is still an invasive practice that interrupts the workflow and requires

everyone to be present and ready.

6.4.5.3 Kanban

Kanban is an Agile Development approach taken by the scheduling system used for lean and just-in-time manufac-

turing implemented at Toyota.

The base of Kanban is the “Kanban Board” (sometimes shortened as “Kanboard”), where plates (also called “cards”

or “tickets”) are moved through swimlanes that can represent:

• The status of the card (To Do, Doing, Testing, Done)

• The Kind of Work (Frontend, Backend, Database, …)

6 PROJECT MANAGEMENT BASICS AND TIPS 158


2D Game Development: From Zero To Hero

• The team that is taking care of the work

The board helps with organization and gives a high-level view of the work status.

Backlog In Progress Testing Done Blocked

Fix Bug #1234 Fix Bug #159 Antigravity Engines World Domination

Implement New Bugs

Figure 133: Example of a Kanban Board

6.4.5.4 ScrumBan

ScrumBan is a hybrid approach between Scrum and Kanban, mixing the Daily Scrum and Sprint Approach with the

Kanban Board.

This approach is usually used during migration from a Scrum-Based approach to a purely Kanban-based approach.

6.4.6 Lean Development

Lean development tries to bring the principles of lean manufacturing into software development. The basis of lean

development is divided in 7 principles:

• Remove Waste: “waste” can be partial work, useless features, waiting, defects, work changing hands…

• Amplify Learning: coding is seen as a learning process and different ideas should be tested on the field,

giving great importance to the learning process;

• Decide late: the later you take decisions, the more assumptions and predictions are replaced with facts, Also

strong commitments should happen as late as possible, as they will make the system less flexible;

• Deliver early: technology evolves rapidly, and the one that survives is the fastest. If you can deliver your

product free from defects as soon as possible you will get feedback quickly, and get to the next iteration

sooner;

• Empower the team: managers are taught to listen to the developers, as well as provide suggestions;

• Build integrity in: the components of the system should work well together and give a cohesive experience,

giving the customer and impression of integrity;

• Optimize the whole: optimization is done by splitting big tasks into smaller ones which helps finding and

eliminating the cause of defects.

6 PROJECT MANAGEMENT BASICS AND TIPS 159


2D Game Development: From Zero To Hero

6.4.7 Where to go from here

Obviously the models presented are not set in stone, but are “best practices” that have been proven to help with

project management, and not even all of them.

Nothing stops you from taking elements of a model and implement them into another model. For example you could

use an Evolutionary Model with a Kanban board used to manage the single increment.

6.5 Version Control

When it comes to managing any resource that is important to the development process of a software, it is vitally

important that a version control system is put in place to manage such resources.

Code is not the only thing that we may want to keep under versioning, but also documentation can be subject to it.

Version Control Systems (VCS) allow you to keep track of edits in your code and documents, know (and blame) users

for certain changes and eventually revert such changes when necessary. They also help saving on bandwidth by

uploading only the differences between commits and make your development environment more robust (for instance,

by decentralizing the code repositories).

The most used Version Control system used in coding is Git, it’s decentralized and works extremely well for tracking

text-based files, like code or documentation, but thanks to the LFS extension it is possible for it to handle large files

efficiently.

Figure 134: An example screen from Git, a version control system

Other used version control systems are Mercurial and SVN (subversion).

Another useful feature of many version control systems are remote sources, which allow you to upload and synchro-

nize your repositories with a remote location (like GitHub, GitLab or BitBucket for instance) and have it safe on the

cloud, where safety by redundancy is most surely ensured.

6.6 Metrics and dashboards

During development you need to keep an eye on the quality of your project, that’s when you need a project dash-

board: but before that, you need to decide what your quality metrics are, that means the measurements that

define if your project is “up to par” with what you expect or not.

6 PROJECT MANAGEMENT BASICS AND TIPS 160


2D Game Development: From Zero To Hero

6.6.1 SLOC

This is probably the simplest metric out there: The “Source Line of Code” (SLOC). It is used to measure the size of a

program by counting its lines of code. Once Bill Gates said the following:

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

An aircraft must be lightweight and robust, and being heavier than necessary will stop it from flying. The same

reasoning should be applied here: a longer source code doesn’t mean a better product.

It is important to strike a balance between “readability” and “brevity”: your code should be short, but being source

code, it is still meant for humans to read, so readability matters more than brevity.

Usually the SLOC metric is used to give a “order of magnitude” impression of the program: considering 2 programs

that do exactly the same thing, one is 10.000 lines of code, the other one is 100.000, you may start to suspect that

the bigger program is more (probably uselessly) complex and less maintainable.

6.6.2 Cyclomatic Complexity

More precisely called “McCabe’s Cyclomatic Complexity”, this metric defines the number of linearly independent

paths through a program’s source code: the higher the metric, the higher is the number of paths a piece of code

can take in its elaboration.

This means that a higher number of paths takes into account a higher number of conditions and decisions and when

such number becomes too high, the code becomes hard to maintain.

The maximum complexity suggested is 10, although sometimes it’s good to relax such metric to a maximum of 15.

When the cyclomatic complexity becomes higher than the maximum value, it is suggested to split the module into

smaller, more maintainable modules.

Your IDE, if advanced enough, should already be able to warn you of a high cyclomatic complexity.

Pitfall Warning!

Be mindful that cyclomatic complexity may have issues of “over-estimation” or “under-

estimation”, depending on a case-by-case basis. McCabe’s cyclomatic complexity is

far from a “silver bullet” that will suit all your needs, but as all other metrics, it can

give a pointer over where refactoring may be necessary.

6.6.2.1 How cyclomatic complexity is calculated

Advanced Wizardry!

This section contains the technical explanation on how to calculate cyclomatic com-

plexity. If you’re not interested in this, feel free to gloss over this section.

6 PROJECT MANAGEMENT BASICS AND TIPS 161


2D Game Development: From Zero To Hero

As people say, an example is worth a thousand words, so let’s take the following UML activity diagram, that represents

a simple program (I made it a bit more complex for the sake of demonstration).

a=input()

yes no
a == 0

yes no
a % 2 == 0
b = "zero"

b = "even" b = "odd"

return b

Figure 135: UML of the program which we’ll calculate the cyclomatic complexity of

First of all, we need to convert it into the corresponding flow diagram, which usually means eliminating the start

nodes and merge nodes used by UML. The result should look something like the following:

6 PROJECT MANAGEMENT BASICS AND TIPS 162


2D Game Development: From Zero To Hero

a=input()

a == 0

b='zero' a % 2 == 0

b='even' b='odd'

return b

Figure 136: Flow diagram of the program we’ll calculate the cyclomatic complexity of

Now we need to count 3 things:

• The number of “nodes”: that is the number of boxes and diamonds in our flow diagram. In our case it is 7.

• The number of “edges”: that is the number of arrows that connect the nodes in our flow diagram. In our case

it is 8.

• The number of “exit points”: usually that is the number of stop nodes in our UML diagram, in our flow diagram

it’s the number of return statements. In our case it is 1.

Now we need to apply the following formula: C = E − N + 2 · P.

This formula can be explained as follows:

Cyclomatic Complexity = Edges − N odes + 2 · Exit P oints

In our case we have: C =8−7+2·1=3

Usually a complexity lower than 15 is considered OK, but also the lower the better.

6.6.3 Code Coverage

When you have a test suite, you may already be thinking about a metric that tells you how much of your code is

tested. Well, here it is: the code coverage metric tells you what percentage of your code base has been run when

executing a test suite.

6 PROJECT MANAGEMENT BASICS AND TIPS 163


2D Game Development: From Zero To Hero

That is both the useful and damaging part of this metric: code coverage doesn’t tell you how well your code is

tested, just how much code was executed, so it’s easy to incur into what I like to call “incidental coverage”: the

code coverage presents a higher value, when the code is merely “executed” and not thoroughly “tested”.

Code coverage is split in many “sub-sets”, like:

• Statement Coverage: how many statements of the program are executed;

• Branch Coverage: defines which branches (as in portions of the if/else and “switch” statements) are exe-

cuted;

• Function Coverage: how many functions or subroutines are called.

This is also why it’s better to prepare unit tests first, and delay the integration tests for a while.

To know more about those terms, head to the testing section.

6.6.4 Code Smells

Code Smells is a blanket term representing all the common (and thus known) mistakes done in a certain programming

language, as well as bad practices that can be fixed more or less easily.

Some of these smells can be automatically detected by static analysis programs (sometimes called Linters), others

may require dynamic execution, but all code smells should be solved at their root, since they usually entail a deeper

problem.

Among code smells we find:

• Duplicated Code;

• Uncontrolled Side Effects;

• Mutating Variables;

• God Objects;

• Long Methods;

• Excessively long (and thus complex) lines of code.

6.6.5 Coding Style infractions

When you are collaborating with someone, it is absolutely vital to enforce a coding style, so that everyone in the

team is able to look at everyone else’s code without having to put too much effort into it.

Coding style can be enforced via static analysis tools, when properly configured.

Counting (automatically) the number of coding style infractions can help you estimate how much effort working on

the code is necessary, thus you would be able to foresee slowdowns in the development process.

6.6.6 Depth of Inheritance

Some people say that inheritance is evil and should be avoided, some other say it’s good. As with all things, in

medio stat virtus (virtue stands in the middle), sometimes inheritance is better left where it is, other times its usage

6 PROJECT MANAGEMENT BASICS AND TIPS 164


2D Game Development: From Zero To Hero

is necessary for things to make sense.

The depth of inheritance metric tells us how deep the inheritance hierarchy is, thus this metric will tell the us the

strength of one of the possible dependency types. The deeper the inheritance, the more dependencies we have,

which means that we have more classes that, if edited, will change the behavior of the “children classes”.

It’s better having a short inheritance depth, (although it’s not necessarily wrong) having a longer chain of dependen-

cies might mean we have a structural problem, where some classes are “too generic” and at the top of the hierarchy

we have some kind of “universal object”.

6.6.7 Number of methods / fields / variables

Let’s talk numbers: having too many methods or fields in a class can be an indicator of a so-called “god object”:

an object that has too many responsibilities under its wing (does too many things), this is a breach of the single

responsibility principle and should be avoided.

We can fix this by splitting the class into smaller classes, each with its own single responsibility.

A high number of local variables instead may point to a complexity issue: your algorithm may be more complex than

needed, or needs to be split into different functions.

6.6.8 Number of parameters

This metric is specific for functions, when a function has a lot of parameters, it’s harder to call and harder to under-

stand. Functions should have no more than 5 parameters in most cases, more and it will be complex.

Some automated tools in your IDE may be able to warn you in case methods and functions have too many parame-

ters.

To solve this issue, you may need to review the function (maybe it has too many responsibilities?) or pass a so-called

“complex structure” to it (thus merging all the parameters into one).

6.6.9 Other metrics

The metrics listed above are not the only ones available to you, some IDEs have aggregated metrics (like the “main-

tainability index” in Visual Studio), while there may be other metrics you want to measure, some follow:

• Lead Time: Time elapsed between the start and end of a process (may be a ticket, or a task);

• MTBF: (Mean Time Before Failure) represents the mean time before the software crashes;

• Crash Rate: The number of times a software crashes, over the number of times it’s used.

6 PROJECT MANAGEMENT BASICS AND TIPS 165


2D Game Development: From Zero To Hero

7 Writing a Game Design Document

If you don’t know where you are going. How can you expect to get there?

Basil S. Walsh

One of the most discussed things in the world of Game Development is the so-called “GDD” or “Game Design

Document”. Some say it’s a thing of the past, others swear by it, others are not really swayed by its existence.

Being an important piece of any software development process, in this book we will talk about the GDD in a more

flexible way.

7.1 What is a Game Design Document

The Game Design Document is a Body Of Knowledge that contains everything that is your game, and it can take

many forms, such as:

• A formal design document;

• A Wiki[g] ;

• A Kanboard[g] ;

• A collection of various files, including spreadsheets.

The most important thing about the GDD is that it contains all the details about your game in a centralized and

possibly easy-to-access place.

It is not a technical document, but mostly a design document, technical matters should be moved to a dedicated

“Technical Design Document”.

7.2 Possible sections of a Game Design Document

Each game can have its own attributes, so each Game Design Document can be different, here we will present some

of the most common sections you can include in your own Game Design Document.

7.2.1 Project Description

This section is used to give the reader a quick description of the game, its genre (RPG, FPS, Puzzle,…), the type of

demographic it covers (casual, hardcore, …). Additional information that is believed to be important to have a basic

understanding of the game can be put here.

This section should not be longer than a couple paragraphs.

A possible excerpt of a description could be the following:

This game design document describes the details for a 2D side scrolling platformer game where the player

makes use of mechanics based on using arrows as platforms to get to the end of the level.

The game will feature a story based on the central America ancient culture (Mayan, Aztec, …).

The name is not defined yet but the candidate names are:

7 WRITING A GAME DESIGN DOCUMENT 166


2D Game Development: From Zero To Hero

7.2.2 Characters

If your game involves a story, you need to introduce your characters first, so that everything that follows will be

clear.

A possible excerpt of a characters list can be the following:

Ohm is the main character, part of the group called “The Resistance” and fights for restoring the electrical

order in the circuit world.

Fad is the main side character, last survivor and heir of the whole knowledge of “The Capacitance” group.

Its main job is giving technical assistance to Ohm.

Gen. E. Rator is the main antagonist, general of “The Reactance” movement, which wants to conquer the

circuit world.

This can be a nice place where to put some character artwork.

If your game does not include a story, you can just avoid inserting this section altogether.

7.2.3 Storyline

After introducing the characters, it’s time to talk about the events that will happen in the game.

An example of story excerpt can be the one below:

It has been 500 mega-ticks that the evil Rator and the reactance has come to power, bringing a new era of

darkness into the circuit world.

After countless antics by the evil reactance members, part of the circuit world’s population united into what

is called “The Resistance”.

Strong of thousands of members and the collaboration of the Capacitance, the resistance launched an attack

against the evil reactance empire, but the empire stroke back with a carpet surcharge attack, decimating

the resistance and leaving only few survivors that will be tasked to rebuild the resistance and free the world

from the reactance’s evil influence.

This is when a small child, and their parents were found. The child’s name, Ohm, sounded prophetic of a

better future of the resistance.

And this is where our story begins.

As with the Characters section, if your game does not include a story, you can just skip this section.

7.2.3.1 The theme

When people read the design document, it is fundamental that the game’s theme is quickly understood: it can be

a comedy-based story, or a game about hardships and fighting for a better future, or maybe it is a purely fantastic

game based on ancient history…

Here is a quick example:

7 WRITING A GAME DESIGN DOCUMENT 167


2D Game Development: From Zero To Hero

This is a game about fighting for a better future, dealing with hardships and the deep sadness you face when

you are living in a world on the brink of ruin.

This game should still underline the happiness of small victories, and give a sense of “coziness” in such small

things, even though the world can feel cold.

If you feel that this section is not relevant for your game, you can skip it.

7.2.3.2 Progression

After defining the story, you should take care of describing how the story progresses as the player furthers their

experience in a high-level fashion.

An example:

The game starts with an intro where the ruined city is shown to the player and the protagonist receives their

magic staff that will accompany them through the game.

The first levels are a basic tutorial on movement, where the shaman teaches the player the basic movement

patterns as well as the first mechanic: staff boosting. Combat mechanics are taught as well.

After the tutorial has been completed, the player advances to the first real game area: The stone jungle.

7.2.4 Levels and Environments

In this section we will define how levels are constructed and what mechanics they will entail, in detail.

We can see a possible example here:

The First Level (Tutorial) is based in a medieval-like (but adapted to the center-America theme) training camp,

outside, where the player needs to learn jumping, movement and fight straw puppets. At the end of the basic

fighting and movement training, the player is introduced to staff boosting which is used to first jump to a

ledge that is too high for a normal jump, and then the mechanic is used to boost towards an area too far

forward to reach without boosting.

Some level artwork can be included in this section, to further define how the levels will look and feel.

7.2.5 Gameplay

This section will be used to describe your gameplay. This section can become really long, but do not fear, as you

can split it in meaningful sections to help with organization and searching.

7.2.5.1 Goals

Why is the player playing your game?

7 WRITING A GAME DESIGN DOCUMENT 168


2D Game Development: From Zero To Hero

This question should be answered in this section. Here you insert the goals of your game, both long and short term.

An example could be the following:

Long Term Goal: Stop the great circuit world war

Optional Long Term Goal: Restore the circuit world to its former glory.

Short Term Goals:

• Find the key to the exit

• Neutralize Enemies

• Get to the next level

7.2.5.2 Game Mechanics

In this section, you describe the core game mechanics that characterize the game, extensively. There are countless

resource on how to describe game mechanics, but we’ll try to add an example here below.

The game will play in the style of the well-known match-3 games. Each match of 3 items will add some points

to the score, and new items will “fall” from a randomly chosen direction every time.

Every time an “L” or a “T” match is performed, a special item of a random color will be generated, when a

match including this item is made, all the items in the same row and column will be deleted and bonuses will

be awarded.

Every time a match with 4 items in a row is performed, a special item of a random color will be generated,

when a match including such item is made, all items in a 3x3 grid centered on the item will be deleted and

bonuses will be awarded.

Every time a match with 5 items in a row is performed, a special uncolored item will be generated, this can

be used as a “wildcard” for any kind of match.

In case the 5-item special is matched with any other special item, the whole game board will be wiped and

a bonus will be awarded.

7.2.5.3 Skills

Here you will describe the skills that are needed by the users in order to be able to play (and master) your game.

This will be useful to assess your game design and eventually find if there are some requirements that are too high

for your target audience; for instance asking a small child to do advanced resource management could be a problem.

This will also help deciding what the best hardware to use your game on could be, for instance if your game requires

precise inputs for platforming then touch screens may not be the best option.

Here’s an example of such section:

7 WRITING A GAME DESIGN DOCUMENT 169


2D Game Development: From Zero To Hero

The user will need the following skills to be able to play the game effectively:

• Pressing Keyboard Buttons or Joypad Buttons

• Puzzle Solving (for the “good ending” overarching puzzle)

• Timing inputs well (for the sections with many obstacles)

7.2.5.4 Items/Powerups

After describing the basic game mechanics and the skills the user needs to master to be able to play the game

effectively, you can use this section to describe the items and powerups that can be used to alter the core gameplay.

For example:

The player can touch a globular light powerup to gain invincibility, every enemy that will touch the player

will get automatically killed. The powerup duration is 15 seconds.

Red (incendiary) arrows can be collected through the levels, they can get shot and as soon as they touch the

ground or an enemy, the burst into flames, similarly to a match.

In this section you describe all items that can be either found or bought from an in-game store or also items derived

from micro-transactions. In-game currency acquisition should be mentioned here too, but further detailed in the

monetization section.

7.2.5.5 Difficulty Management and Progression

This section can be used to manage how the game gets harder and how the player can react to it. This will expand

on game mechanics like leveling and gear.

This section is by its own nature quite subjective, but describing how the game progresses helps a lot during the

tighter parts of development.

Below a possible example of this section:

The game will become harder by presenting tougher enemies, with more armor, Health Points and attack. To

overcome this difficulty shift, the player will have to create defense strategy and improve their dodging, as

well as leveling up their statistics and buy better gear from the towns’ shops.

In the later levels, enemies will start dodging too, and will also be faster. The player will need to improve

their own speed statistic to avoid being left behind or “kited” by fast enemies.

As the game progresses, the player will need to acquire heavy weapons to deal with bigger bosses, as well

as some more efficient ranged weapons to counteract ranged enemies.

This section is good if you want to talk about unlocking new missions/maps/levels too.

7 WRITING A GAME DESIGN DOCUMENT 170


2D Game Development: From Zero To Hero

7.2.5.6 Losing Conditions

Many times we focus so much on how the player will get to the end of the game that we absolutely forget how the

player can not get to the end of the game.

Losing conditions must be listed and have the same importance of the winning conditions, since they add to the

challenge of the game itself.

A possible example of how a “losing conditions” section could be written is the following:

The game can be lost in the following ways:

• Losing all the lives and not “continuing” (Game Over)

• Not finding all the Crystal Oscillators (Bad Ending)

An interesting idea could be having an “endings” section inside your game, where all endings (both good, bad and

neutral) are listed, encouraging the player to pull themselves out from the “losing condition” that is a bad ending.

7.2.6 Graphic Style and Art

Here we describe the ideas on how the game will look like. Describing the graphic style and medium.

Here is a possible example of the game:

This is a 2D side scroller with a dark theme, the graphics should look gloomy and very reminiscing of a circuit

board.

The graphical medium should be medium-resolution pixel art, allowing the player’s imagination to “fill in” the

graphics and allowing to maintain a “classic” and “arcade” feeling.

7.2.7 Sound and Music

Sadly, in way too many games, music and sound is an afterthought. A good soundtrack and sound effect can really

improve the immersion, even in the simplest of games.

In this section we can describe in detail everything about Music and Sound Effects, and if the section becomes hard

to manage, splitting it in different sub-sections could help organization.

Music should be based on the glitch-hop style, to complement the electronic theme. 8 or 16-bit style sounds

inside the score are preferable to modern high-quality samples.

Sound effects should appeal to the 8 or 16-bit era.

Lots of sound effects should be used to give the user positive feedback when using a lever to open a new

part of the level, and Extra Lives/1UP should have a jingle that overrides the main music.

7 WRITING A GAME DESIGN DOCUMENT 171


2D Game Development: From Zero To Hero

7.2.8 User Interface

In this section we will describe everything that concerns the User Interface: menus, HUD, inventories and everything

that will contribute to build the user experience that is not strictly tied to the gameplay.

This is especially important in games that make heavy use of menus, like turn-based strategy games or survival

games where inventory management can be fundamental.

Let’s see an example of how this section can be written:

The game will feature a cyberpunk-style main menu, looking a lot like an old green-phosphor terminal but

with a touch of futurism involved. The game logo should be visible on the left side, after a careful conversion

into pixel-art. On the right, we see a list of buttons that remind old terminal-based GUIs. On the bottom of

the screen, there should be an animated terminal input, for added effect.

Every time a menu item is highlighted or hovered by the mouse, the terminal input will animate and write a

command that will tie to the selected menu voice, such as:

• Continue Game: ./initiate_mission.bin -r

• Start Game: ./initiate_mission.bin --new

• Options: rlkernel_comm.bin --show_settings

• Exit: systemcontrol.bin --shutdown

The HUD display should remind a terminal, but in a more portable fashion, to better go with the “portability”

of a wrist-based device.

It’s a good idea to add some mock designs of the menu in this section too.

7.2.9 Game Controls

In this section you insert everything that concerns the way the game controls, eventually including special periph-

erals that may be used.

This will help you focusing on better implementing the input system and limit your choices to what is feasible and

useful for your project, instead of just going by instinct.

Below, a possible way to write such section

The game will control mainly via mouse and keyboard, using the mouse to aim the weapon and shoot and

keyboard for moving the character.

Alternatively, it’s possible to connect a twin-stick gamepad, where the right stick moves the weapon crosshair,

while the left stick is used to move the character, one of the back triggers of the gamepad can be configured

to shoot.

If the gamepad is used, there will be a form of aim assistance can be enabled to make the game more

accessible to gamepad users.

7 WRITING A GAME DESIGN DOCUMENT 172


2D Game Development: From Zero To Hero

7.2.10 Accessibility Options

Here you can add all the options that are used to allow more people to access your game, in more ways than you

think.

Below, we can see an example of many accessibility options in a possible game.

The game will include a “colorblind mode”, allowing the colors to be colorblind-friendly: such mode will

include 3 options: Deuteranopia, Tritanopia and Monochromacy.

Additionally, the game will include an option to disable flashing lights, making the game a bit more friendly

for people with photosensitivity.

The game will support “aim assistance”, making the crosshair snap onto the enemy found within a certain

distance from the crosshair.

In order to assist people who have issues with the tough platforming and reaction times involved, we will

include the possibility to play the game at 75%, 50% and 25% speed.

7.2.11 Tools

This section is very useful for team coordination, as having the same toolkit prevents most of the “works for me”

situations, where the game works well for a tester/developer while it either crashes or doesn’t work correctly for

others.

This section is very useful in case we want to include new people in our team and quickly integrate them into the

project.

In this section we should describe our toolkit, possibly with version numbers included (which help reducing incom-

patibilities), as well as libraries and frameworks. The section should follow the trace below:

The tools and frameworks used to develop the game are the following:

Pixel Art Drawing: Aseprite 1.2.13

IDE: Eclipse 2019-09

Music Composition: Linux Multimedia Studio (LMMS) 1.2.1

Map and level design: Tiled 1.3.1

Framework: SFML 2.5.1

Version Control: Git 2.24.0 and GitLab

7.2.12 Marketing

This section allows you to decide how to market the game and have a better long-term plan on how to market your

game to your players.

Carefully selecting and writing down your target platforms and audience allows you to avoid going off topic when it

comes to your game.

7 WRITING A GAME DESIGN DOCUMENT 173


2D Game Development: From Zero To Hero

7.2.12.1 Target Audience

Knowing who is your target audience helps you better suit the game towards the audience that you are actually

targeting.

Here is an example of this section:

The target audience is the following:

Age: 15 years and older

Gender: Everyone

Target players: Hardcore 2D platformer fans

7.2.12.2 Available Platforms

Here you describe the launch platforms, as well as the platforms that will come into the picture after the game

launched. This will help long term organization.

Here is an example of how this section could look:

Initially the game will be released on the following platforms:

• PC

• Playstation 4

After launch, we will work on the following ports:

• Nintendo Switch

• XBox 360

After working on all the ports, we may consider porting the game to mobile platforms like:

• Android 9.0 +

• iOS 11.0 +

7.2.12.3 Monetization

In this optional section you can define your plans for the ways you will approach releasing the game as well as

additional monetization strategies for your game.

For example:

The game will not feature in-game purchases.

Monetization efforts will be focused on selling the game itself at a full “indie price” and further monetization

will take place via substantial Downloadable Content Expansions (DLC)

The eventual mobile versions will be given away for free, with advertisements integrated between levels. It

is possible for the user to buy a low-price paid version to avoid seeing the advertisements.

7 WRITING A GAME DESIGN DOCUMENT 174


2D Game Development: From Zero To Hero

7.2.12.4 Internationalization and Localization

Internationalization and Localization are a matter that can make or break your game, when it comes to marketing

your game in foreign countries.

Due to political and cultural reasons, for instance you shouldn’t use flags to identify languages. People from territories

inside a certain country may not be well accepting of seeing their language represented by the flag of their political

adversaries.

Another example could be the following: if your main character is represented by a cup of coffee, your game could

be banned somewhere as a “drug advertisement”.

This brings home the difference between “Internationalization” and “Localization”:

Internationalization Making something accessible across different countries without major changes to its content

Localization Making something accessible across different countries, considering the target country’s culture.

We can see a possible example of this section below:

The game will initially be distributed in the following languages:

• English

• Italian

After the first release, there will be an update to include:

• Spanish

• German

• French

7.2.13 Other/Random Ideas

This is another optional section where you can use as a “idea bin”, where you can put everything that you’re not

sure will ever make its way in the game. This will help keeping your ideas on paper, so you won’t ever forget them.

We can see a small example here:

Some random ideas:

• User-made levels

• Achievements

• Multiplayer Cooperative Mode

• Multiplayer Competitive Mode

7.3 Where to go from here

This chapter represents only a guideline on what a Game Design Document can be, feel free to remove any sections

that don’t apply to your current project as well as adding new ones that are pertinent to it.

7 WRITING A GAME DESIGN DOCUMENT 175


2D Game Development: From Zero To Hero

A Game Design Document is a Body of Knowledge that will accompany you throughout the whole game development

process and it will be the most helpful if you are comfortable with it and it is shaped to serve you.

7 WRITING A GAME DESIGN DOCUMENT 176


Part 3: Game Development Basics
2D Game Development: From Zero To Hero

8 The Game Loop

All loops are infinite ones for faulty RAM modules.

Anonymous

8.1 The Input-Update-Draw Abstraction

Animations and movies are an illusion, and so are games. Games and movies show still images tens of times per

second, giving us the illusion of movement.

Any game and its menus can be abstracted into 3 main operations that are performed one after the other, in a loop:

1) Process the user input

2) Update the world (or menu) status

3) Display (Draw) the updated world (or again, menu) to the screen

We call such abstraction the “game loop”.

Preparation work

Game Loop

Process Input

Update Internal Game State

Draw Screen

yes
game is still running?

no

Clean up

Figure 137: UML Diagram of the input-update-draw abstraction

8 THE GAME LOOP 178


2D Game Development: From Zero To Hero

So a pseudocode implementation of such loop would be something like the following:

Listing 27: Game Loop example

1 void game () {

2 bool game_is_running = t r u e ;

3 while ( game_is_running ){

4 process_user_input () ;
5 update_world () ;
6 draw () ;
7 }
8 }

This abstraction will become really useful when dealing with many rows of code and keeping it neatly organized.

8.2 Input

8.2.1 Events vs Real Time Input

Some frameworks may be able to further abstract how they process input by giving an API[g] that allows to make

use of events.

Most of the time, events will be put in a queue that will be processed separately. This way it’s easier to program how

to react to each event and keep our code neatly organized. The downside is that the performance of an event-driven

input processing is directly tied to how many events are triggered: the more events are triggered, the longer the

wait may be before we get to our processed input.

This usually depends on the implementation of the event queue: an event queue is less wasteful in terms of resources

and allows for less coupled code, but the queue could be cluttered with events we’re not interested in (for instance

mouse movement events in a game that uses only keyboard for controls) so we need to take the time to configure

our event handler to ignore certain events when not necessary.

Note!

A well-configured event-based input system is the most efficient way of doing

things, allowing code to be executed only when necessary.

On the opposite side, we have so-called “real-time input”, where at a certain point of our update routine, we check for

the instantaneous status of the input peripherals and process it immediately. This allows for a faster, more reactive

code and to apply some different logic (for instance pressing left and right on the keyboard can be coded to make

the character stop). Besides being more immediate, this system shares a lot of traits with “polling” which can be

performance-heavy, as well as inducing some undesired code coupling.

Again, a well-implemented and well-configured event-based system should feel no different from real-time input,

with the advantage of having better performance and having less code coupling.

8 THE GAME LOOP 179


2D Game Development: From Zero To Hero

8.3 Timing your loop

When it comes to anything that remotely relates to physics (that includes video games), we need to set the relation

to time in our loop. There are many ways to set our delta time (or time steps), we’ll see some of the most common.

8.3.1 What is a time step

A time step (or delta time) is a number that will define “how much time passed” between two “snapshots” of our

world (remember, the world is updating and showing in discrete intervals, giving the illusion of movement). This

number will allow us to make our loop more flexible and react better to the changes of load and machines.

8.3.2 Fixed Time Steps

The first and simplest way is to use a fixed time step, our delta time is fixed to a certain number, which makes the

simulation easier to calculate but also makes some heavy assumptions:

• Vertical Synchronization is active in the game

• The PC is powerful enough to make our game work well, 100% of the time

1
An example of fixed time step loop can be the following (assuming 60 frames per second or dt = 60 ):

Listing 28: Game loop with fixed timesteps

1 // ...
2 f l o a t dt = 1.0/60.0;

3 bool game_is_running = t r u e ;

5 while ( game_is_running ) {

6 process_user_input () ;
7 update_world ( dt );
8 draw () ;
9 }
10 // ...

Everything is great, until our computer starts slowing down (high load or just not enough horsepower), in that case

the game will slow down.

This means that every time the computer slows down, even for a microsecond, the game will slow down too, which

can be annoying.

Note!

A similar problem can apply between different computers: if computer A can run the

game at 30fps maximum, while computer B will run at 120fps (and we don’t account for

that), using fixed timesteps the game will run 4 times as fast on computer B.

8 THE GAME LOOP 180


2D Game Development: From Zero To Hero

8.3.3 Variable Time Steps

A way to limit the issues given by a fixed time step approach is to make use of variable time steps, which are simple

in theory, but can prove hard to manage.

The secret is measuring how much time passed between the last frame and the current frame, and use that value

to update our world.

An example in pseudocode could be the following:

Listing 29: Game loop with variable time steps

1 bool game_is_running = t r u e ;

3 // We initialize our dt at 1/60 th of a second for the first loop


4 f l o a t dt = 1.0/60.0;

6 while ( game_is_running ) {

7 // We get the system time in milliseconds


8 // since implementation varies here i 'll use a generic function name
9 f l o a t begin = get_system_time_millis () ;

10 process_user_input () ;
11 update_world ( dt );
12 draw () ;
13 f l o a t end = get_system_time_millis () ;

14 // We update our dt
15 dt = end - begin ;
16 }

This allows to smooth the possible lag spikes, even allowing us to disable Vertical Sync and have a bit less input lag,

but this approach has some drawbacks too.

Since the delta time now depends on the speed of the game, the game can “catch up” in case of slowdowns; that

can result in a slightly different feeling, depending on the framerate, but if there is a really bad slowdown dt can

become really big and break our simulation, and collision detection will probably be the first victim.

Also this method can be a bit harder to manage, since every movement will have to be scaled with dt.

8.3.4 Semi-fixed Time Steps

This is a special case, where we set an upper limit for our time steps and let the update loop execute as fast as

possible. This way we can still simulate the world in a somewhat reliable way, avoiding the dangers of higher spikes.

1
A semi-fixed time step approach is the following (assuming 60 fps or dt = 60 ):

Listing 30: Game loop with Semi-Fixed time steps

1 f l o a t dt = 1.0/60.0;

2 bool game_is_running = t r u e ;

8 THE GAME LOOP 181


2D Game Development: From Zero To Hero

4 // We bootstrap frametime for 1/60 th of a second for the first frame


5 f l o a t frametime = 1.0/60.0;

7 while ( game_is_running ) {

8 // We get the system time in milliseconds


9 // since implementation varies here i 'll use a generic function name
10 f l o a t begin = get_system_time_millis () ;

11

12 while ( frametime > 0.0) {

13 f l o a t deltaTime = min (dt , frametime );

14 process_user_input () ;
15 update_world ( dt );
16 frametime = frametime - deltaTime ;
17 draw () ;
18 }
19 f l o a t end = get_system_time_millis () ;

20 // We memorize how long this frame lasted


21 frametime = end - begin ;
22 }

This way, if the loop is running too slow, the game will slow down and the simulation won’t blow up. The main

disadvantage of this approach is that we’re taking more update steps for each draw step, which is fine if drawing

takes more than updating the world. If instead the update phase of the loop takes more than drawing it, we will

spiral into a terrible situation.

We can call it a “spiral of death”, where the simulation will take Y seconds (real time) to simulate X seconds (of game

time), with Y > X, being behind in your simulation makes the simulation take more steps, which will make the

simulation fall behind even more, thus making the simulation lag behind more and more.

8.3.5 Frame Limiting

Frame limiting is a technique where we aim for a certain duration of our game loop. If an iteration of the game loop

is faster than intended, such iteration will wait until we get to our target loop duration.

1
Let’s again consider a loop running at 60fps (or dt = 60 ):

Listing 31: Game loop with Frame Limiting

1 #i n c l u d e < algoritm >

3 f l o a t targetTime = 1.0/60.0;

4 bool game_is_running = t r u e ;

6 // We bootstrap dt to 1/60 th of a second for the first frame


7 f l o a t dt = 1.0/60.0;

9 while ( game_is_running ) {

10 // We get the system time in milliseconds


11 // since implementation varies here i 'll use a generic function name

8 THE GAME LOOP 182


2D Game Development: From Zero To Hero

12 f l o a t begin = get_system_time_millis () ;

13 process_user_input () ;
14 update_world ( dt );
15 draw () ;
16 f l o a t end = get_system_time_millis () ;

17 // We update our dt
18 dt = end - begin ;
19 sleep ( std :: max ( targetTime - dt , 0) );
20 }

Even if the frame is limited, it’s necessary that all updates are tied to our delta time to work correctly. With this loop

the game will run at most at 60 frames per second, if there is a slowdown the game will slow down under 60 fps, if

the game runs faster it won’t go over 60fps.

8.3.6 Frame Skipping/Dropping

A common solution used when a frame takes longer to update and render than the target time is using the so-called

“frame dropping”. The game won’t render the next frame, in an effort to “catch up” to the desired frame rate.

This will obviously cause a perceptible visual stutter.

8.3.7 Multi-threaded Loops

Higher budget (AAA) games don’t usually use a variation of the “classic” game loop, but instead make use of the

capabilities of newer hardware. Using multiple threads (lines of execution) executing at the same time, making

everything quicker and the framerate higher.

Multi-threaded loops are created in a way that separates the input-update part of the game loop from the drawing

part of it. This way the update thread can take care of updating our simulation, while the drawing/rendering loop

can take care of drawing the result to screen.

The catch is that we can’t just wait for the input-update thread to finish before rendering, that wouldn’t make it

quicker than just using a one-threaded game loop: instead we make the rendering thread “lag behind” the input-

update thread by 1 frame - this way while the input-update thread takes care of the frame number n, the drawing
thread will be rendering the prepared frame number n − 1.

Thread

Updating 1 2 3 4 5 6

Rendering 1 2 3 4 5

This 1-frame difference between updating and rendering introduces lag that can be quantified between 16.67ms (at

60fps) and 33.3ms (at 30fps), which needs to be added with the 2-5 ms of the LCD refresh rate, and other factors that

can contribute to lag. In some games where extreme precision is needed, this could be considered unacceptable,

so a single-threaded loop could be considered more fitting.

8 THE GAME LOOP 183


2D Game Development: From Zero To Hero

8.4 Issues and possible solutions

In this section we have a little talk about some common issues related to the game loop and its timing, and some

possible solutions

8.4.1 Frame/Screen Tearing

Screen tearing is a phenomenon that happens when the “generate output” stage of the game loop happens in the

middle of the screen drawing a frame.

This makes it so that a part of the drawn frame shows the result of an output stage, while another part shows a more

updated version of the frame, given by a more recent game loop iteration.

Figure 138: An example of screen tearing

A very common fix for this phenomenon is double buffering, where two color buffers are used. While the first is

shown on screen, the game loop updates and draws on the second color buffer.

When comes the time to draw the color buffer on screen, an operation called “flipping” is performed, where the

second color buffer is shown on screen, so that the game loop can draw on the first color buffer.

To make the game even smoother, a technique called “triple buffering” can be used, which adds a third color buffer

is used to make the animation smoother at the cost of a higher input lag.

8.5 Drawing to screen

When drawing to screen, the greatest majority of games make use of what is called the “painter’s algorithm”, which

looks something like the following:

1. Clear the screen

2. Draw The Farthest Background

3. Draw The Second Farthest Background

4. Draw The Tile Map

8 THE GAME LOOP 184


2D Game Development: From Zero To Hero

5. Draw The enemies and obstacles

6. Draw The Player

7. Display everything on screen

If we divide each “layer” we can see how the painter’s algorithm works:

Figure 139: A small example of the “painter’s algorithm”

Just like a real painter, we draw the background items before the foreground ones, layering each one on top of

the other. Sometimes games make use of priority queues to decide which items to draw first, other times game

developers (usually under the time constraints of a game jam) just hard-code the draw order.

8.5.1 Clearing the screen

Special note about clearing the screen: this is an operation that sometimes may look useless but, like changing the

canvas for a painter, clearing the screen (or actually the “buffer” we’re drawing on) avoids a good deal of graphical

glitches.

8 THE GAME LOOP 185


2D Game Development: From Zero To Hero

Figure 140: How not clearing the screen can create glitches

In the previous image, we can see how a black screen with only a FPS counter can end up drawing all kinds of

glitches when the screen buffer is not cleared: we can clearly see the FPS counter, but the rest of the screen should

be empty, instead the GPU is trying to represent residual data from its memory, causing the glitches.

Figure 141: Another type of glitch created by not clearing the screen

If you forget to clear your screen or set a background every frame, the old buffer data will remain on screen, creating

a “trail-like” effect on your game, which is probably undesirable.

8 THE GAME LOOP 186


2D Game Development: From Zero To Hero

9 Collision Detection and Reaction


Every detection of what is false directs us towards what is true: every trial

exhausts some tempting form of error.

William Whewell

When it comes to collision management, there are two main phases:

• Collision Detection: you find out which game objects collided with each other;

• Collision Reaction: you handle the physics behind the collision detected, making the game objects react to

such collision.

Collisions don’t only happen between game objects (two fighters hitting each other), but also between a character

and the world (or they would end up just going through the ground).

In this section we’ll talk about some ways you can detect and react to collisions.

9.1 Why Collision Detection is done in multiple passes

Collision detection algorithms can be quite costly, even more when you are using a brute force approach, but it’s

possible to have a more precise collision detection at a lower cost by combining different collision detection algo-

rithms.

The most common way to apply a multi-pass collision detection is by dividing the process in a “broad” and a “fine”

pass.

The broad pass can use a very simple algorithm to check for the possibility of a collision, the algorithms used are

usually computationally cheap, such as building quad trees.

When the simpler algorithm detects the possibility of a collision, a more precise algorithm is used to check if a

collision really happened, usually such finer algorithms are computationally expensive and will benefit from the first

“broad pass” filter, thus avoiding useless heavy calculations.

Note!

In this chapter we’ll see the easier narrow-pass detection first, followed by the more

complex broad-pass algorithms, but remember that a good collision detection system

does a “broad-pass” first, before delving into the “narrow-pass”.

9.2 Narrow-Phase Collision Detection: did it really collide?

First of all, we need to see how we can make sure that two objects really collide with each other.

Sometimes this presents a (quite common) problem when it comes to precision: computers have no knowledge of

infinity (due to their finiteness, see computers are (not) precise). This means that we may need to give some leeway

9 COLLISION DETECTION AND REACTION 187


2D Game Development: From Zero To Hero

and define an “acceptable error” in our calculations, thus we will create a “small enough value” (which in math is

represented by the Greek letter “epsilon”: ϵ) and change our algorithms accordingly.

9.2.1 Collision Between Two Points

This is the simplest case: points are mono-dimensional objects, and the only way two points can collide is when they

have the same coordinates.

An example algorithm would be the following:

Listing 32: Point to point collision detection

1 bool point_collision ( Point A , Point B){

2 i f (A.x == B.x && A.y == B.y){

3 return true ;

4 } else {
5 return f a l s e ;

6 }
7 }

A possible lazy/shorter version could be:

Listing 33: Shortened version of a point to point collision detection

1 bool point_collision ( Point A , Point B){

2 r e t u r n A.x == B.x && A.y == B.y;

3 }

This algorithm consists in a constant number of operations, so it runs in O(1).

Since numbers in computers can be really precise, a collision between two points may be a bit too precise, so it

could prove useful to have a “buffer” around the point, so that we can say that the two points collided when they’re

around the same place.

In this case, it may prove to be a lot more useful to do a point vs circle detection, or even a circle vs circle collision

detection, in that case the “radius” would be the “approximation” of a point.

If instead you want to use a different method that doesn’t involve square roots, you can use epsilon values to have

an approximation of the collision. In this case the collision area won’t be round, but square.

Listing 34: Point to point collision detection with epsilon values

1 #i n c l u d e < cmath >

2 bool point_collision ( Point A , Point B){

3 f l o a t epsilon = 0.0001; // Let 's take a sufficiently low value

4 // If both coordinates are " close enough ", we trigger a collision .


5 // We take the absolute value , just in case some subtractions end up being negative .
6 r e t u r n std :: abs (A.x - B.x) <= epsilon && std :: abs (A.y - B.y) <= epsilon ;

7 }

9 COLLISION DETECTION AND REACTION 188


2D Game Development: From Zero To Hero

9.2.2 Collision Between A Point and a Circle

Now a circle comes into the mix, a circle has two major characteristics: a center and a radius.

Figure 142: Reference image for Point-Circle Collision detection

We can see that the distance between the center of a circle and our point can be expressed with a formula:

d=r+x

Where r is the circle radius and x is the difference of the distance between the center of the circle and the point

(which can be negative):

x=d−r

The point is inside the circle when x ≤ 0, which means:

x≤0⇔d−r ≤0⇔d≤r

We can express this in a few words:

A point is considered inside of a circle when the distance between the point and the center of the circle is

less than or equal to the radius.

So we need a function that calculates the distance between two points, and then use it to define if a point is inside

a circle.

An example could be the following:

Listing 35: Point to circle collision detection

1 #i n c l u d e < cmath >

9 COLLISION DETECTION AND REACTION 189


2D Game Development: From Zero To Hero

3 s t r u c t Circle {

4 // Let 's define a circle class / structure


5 Point center ;
6 i n t radius ;

7 };
8

9 f l o a t distance ( Point A , Point B){

10 // Calculates the distance between two points


11 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

12 }
13

14 bool circle_point_collision ( Circle A , Point B) {

15 i f ( distance ( A. center , B) <= A. radius ){

16 return true ;

17 } else {
18 return f a l s e ;

19 }
20 }

Again, the lazier version:

Listing 36: Shorter version of a point to circle collision detection

1 #i n c l u d e < cmath >

3 s t r u c t Circle {

4 Point center ;
5 i n t radius ;

6 };
7

8 f l o a t distance ( Point A , Point B){

9 // Calculates the distance between two points


10 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

11 }
12

13 bool circle_point_collision ( Circle A , Point B) {

14 r e t u r n distance (A. center , B) <= A. radius ;

15 }

Although slightly more heavy, computation-wise, this algorithm still runs in O(1).

9.2.3 Collision Between Two Circles

Let’s add another circle into the mix now, and think in more or less the same way as before:

9 COLLISION DETECTION AND REACTION 190


2D Game Development: From Zero To Hero

r1 x r2

Figure 143: Reference image for Circle-Circle collision detection

We can see the distance between the center of the circles as expressed with the following formula:

d = r1 + x + r2

Where r1 and r2 are the radii, and x is defined as follows:

x = d − (r1 + r2 )

As before, our x can be negative, which means that the circles are colliding if x ≤ 0, which means:

x ≤ 0 ⇔ d − (r1 + r2 ) ≤ 0 ⇔ d ≤ r1 + r2

We can express the concept in words again:

Two circles are colliding when the distance between their centers is less or equal the sum of their radii

In pseudo code this would be:

Listing 37: Circle to Circle Collision Detection

1 #i n c l u d e < cmath >

3 s t r u c t Circle {

4 // Let 's define a circle class / structure


5 Point center ;
6 i n t radius ;

7 };
8

9 f l o a t distance ( Point A , Point B){

10 // Calculates the distance between two points


11 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

12 }

9 COLLISION DETECTION AND REACTION 191


2D Game Development: From Zero To Hero

13

14 bool circle_circle_collision ( Circle A , Circle B ){

15 i f ( distance ( A. center , B. center ) <= A . radius + B. radius ){

16 return true ;

17 } else {
18 return f a l s e ;

19 }
20 }

The shorter version would be:

Listing 38: Shorter Version of a Circle to Circle Collision Detection

1 #i n c l u d e < cmath >

3 s t r u c t Circle {

4 // Let 's define a circle class / structure


5 Point center ;
6 i n t radius ;

7 };
8

9 f l o a t distance ( Point A , Point B){

10 // Calculates the distance between two points


11 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

12 }
13

14 bool circle_circle_collision ( Circle A , Circle B ){

15 r e t u r n distance (A. center , B. center ) <= A . radius + B. radius ;

16 }

Again, this algorithm performs a number of operations that is constant, so it runs in O(1).

9.2.4 Collision Between Two Axis-Aligned Rectangles (AABB)

This is one of the most used types of collision detection used in games: it’s a bit more involved than other types of

collision detection, but it’s still computationally easy to perform. This is usually called the “Axis Aligned Bounding

Box” collision detection, or AABB.

Let’s start with a bit of theory. We have two squares:

9 COLLISION DETECTION AND REACTION 192


2D Game Development: From Zero To Hero

Figure 144: Example used in the AABB collision detection

To know if we may have a collision, we need to check if one of the sides is “inside” (that means between the top and

bottom sides) of another rectangle:

Figure 145: Top-Bottom Check

In this case we know that the “top side” of the second rectangle (highlighted in blue) has a y coordinate between

the first rectangle’s top and bottom sides’ y coordinates (highlighted in red).

Though this is a necessary condition, this is not sufficient, since we may have a situation where this condition is

satisfied, but the rectangles don’t collide:

Figure 146: Top-Bottom Check is not enough

So we need to check the other sides also, in a similar fashion:

9 COLLISION DETECTION AND REACTION 193


2D Game Development: From Zero To Hero

Figure 147: An example of a left-right check

This has to happen for all four sides of one of the rectangle.

Now we can try putting down a bit of code, we’ll assume that rectangles are defined by their top-left corner (as

usually happens) and their width and height:

Listing 39: Axis-Aligned Bounding Box Collision Detection

1 s t r u c t Point {

2 // Rewritten as a memo
3 int x;

4 int y;

5 };
6

7 s t r u c t Rectangle {

8 Point corner ;
9 i n t width ;

10 i n t height ;

11 };
12

13 bool rect_rect_collision ( Rectangle A , Rectangle B){

14 if (( A. corner . x < B. corner .x + B. width ) &&


15 (A. corner . x + A. width > B. corner .x) &&
16 (A. corner . y < B. corner .y + B. height ) &&
17 (A. corner . y + A. height > A. corner .y)){
18 return true ;

19 } else {
20 return f a l s e ;

21 }
22 }

This complex conditional checks 4 things:

• The left side of rectangle A is at the left of the right side of rectangle B;

• The right side of rectangle A is at the right of the left side of rectangle B;

• The top side of rectangle A is over the bottom side of rectangle B;

• The bottom side of rectangle A is underneath the top side of rectangle B.

9 COLLISION DETECTION AND REACTION 194


2D Game Development: From Zero To Hero

If all four checks are true, then a collision happened.

The best way to understand this algorithm properly is to test it by hand and convince yourself that it works.

This is a very light algorithm but can quickly become heavy on the CPU when there are many objects to check for

collision. We’ll see later how to limit the number of checks and make collision detection an operation that is not as

heavy on our precious CPU cycles.

9.2.5 Line/Point Collision

We can represent a segment by using its two extreme points, which proves to be a quite inexpensive way to represent

a line (it’s just two points). Now how do we know if a point is colliding with a line?

To know if a point is colliding with a line we need… Triangles!

Every triangle can be represented with 3 points, and there is a really useful theorem that we can make use of:

The sum of the lengths of any two sides must be greater than, or equal, to the length of the remaining side.

So, given a triangle ABC:

Figure 148: Example of the triangle inequality theorem

We get the following 3 inequalities:

AB + BC ≤ AC

AC + BC ≤ AB

AB + AC ≤ BC

What is more interesting to us is that when the one of the vertices of the triangle is on its opposite side, the triangle

degenerates:

Figure 149: Example of a degenerate triangle

9 COLLISION DETECTION AND REACTION 195


2D Game Development: From Zero To Hero

And the theorem degenerates too, to the following:

AC + BC = AB

So we can calculate the distance between the point and each of the two extremes of the line and we know that when

the sum of such distances is equal to the length of the line, the point will be colliding with the line.

In code, it would look something like the following:

Listing 40: Line to Point Collision detection

1 #i n c l u d e < cmath >

2 s t r u c t Point {

3 int x;

4 int y;

5 };
6

7 s t r u c t Line {

8 Point A;
9 Point B;
10 };
11

12 f l o a t distance ( Point A , Point B){

13 // Calculates the distance between two points


14 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

15 }
16

17 bool line_point_collision ( Point pt , Line ln ){

18 // First , let 's calculate the length of the line


19 f l o a t length = distance ( ln .A , ln .B );

20 // Now let 's calculate the distance between the point pt


21 // and the point "A" of the line
22 f l o a t pt_a = distance ( ln .A , pt );

23 // Same Goes for the distance between pt and "B "


24 f l o a t pt_b = distance ( ln .B , pt );

25 // Now for the detection


26 i f ( pt_a + pt_b == length ){

27 return true ;

28 } else {
29 return f a l s e ;

30 }
31 }

It could prove useful to put a “buffer zone” in here too, so that the collision detection doesn’t result too jerky and

precise. In that case you may want to take a look at the line vs circle algorithm, in that case the radius would be the

“approximation” of the point.

9 COLLISION DETECTION AND REACTION 196


2D Game Development: From Zero To Hero

9.2.6 Line/Circle Collision

As in the previous paragraph, we memorize a line as a pair of Points, so checking if the circle collides with either end

of the line is easy, using the Point/Circle collision algorithm.

Listing 41: Partial Implementation of a Line to Circle Collision Detection

1 s t r u c t Point {

2 int x;

3 int y;

4 };
5

6 s t r u c t Line {

7 Point A;
8 Point B;
9 };
10

11 s t r u c t Circle {

12 Point center ;
13 i n t radius ;

14 };
15

16 // ...
17

18 bool line_circle_collision ( Circle circle , Line line ){

19 collides_A = circle_point_collision ( circle , line .A);


20 collides_B = circle_point_collision ( circle , line .B);
21 i f ( collides_A || collides_B ){

22 return true ;

23 }
24 // ...
25 }

Now our next objective is finding the closest point on the line to the center of our circle. The details and demon-

strations on the math behind this will be spared, just know the following:

Given a line AB between points A = (x1 , y1 ) and B = (x2 , y2 ) and a point P = (xk , yk ), the point on the line
closest to P has coordinates:

x = x1 + u · (x2 − x1 )

y = y1 + u · (y2 − y1 )

With:

(xk − x1 ) · (x2 − x1 ) + (yk − y1 ) · (y2 − y1 )


u=
||B − A||2

9 COLLISION DETECTION AND REACTION 197


2D Game Development: From Zero To Hero

That’s a lot of math!

We need to be careful though, cause this formula gives us the point for an infinite line, so the point we find could be

outside of our line. We will use the line/point algorithm to check for that.

After we made sure the point is on the line, we can measure the distance between such point and the center of our

circle, if such distance is less than the radius, we have a hit! (Or just apply the circle/point collision algorithm again).

The final algorithm should look something like this:

Listing 42: Line to circle collision detection

1 #i n c l u d e < cmath >

3 s t r u c t Point {

4 int x;

5 int y;

6 };
7

8 s t r u c t Line {

9 Point A;
10 Point B;
11 };
12

13 s t r u c t Circle {

14 Point center ;
15 i n t radius ;

16 };
17

18 f l o a t distance ( Point A , Point B){

19 // Calculates the distance between two points


20 r e t u r n std :: sqrt ( std :: pow (( A.x - B.x) ,2) + std :: pow (( A.y - B.y) ,2) );

21 }
22

23 bool line_point_collision ( Line l , Point p){

24 // ...
25 }
26

27 bool circle_point_collision ( Circle c , Point p) {

28 // ...
29 }
30

31 bool line_circle_collision ( Circle circle , Line line ){

32 // We check the ends first


33 collides_A = circle_point_collision ( circle , line .A);
34 collides_B = circle_point_collision ( circle , line .B);
35 i f ( collides_A || collides_B ){

36 return true ;

37 }
38 // We pre - calculate "u ", we 'll use some variables for readability
39 i n t x1 = line . A.x;

9 COLLISION DETECTION AND REACTION 198


2D Game Development: From Zero To Hero

40 i n t x2 = line . B.x;

41 i n t xk = circle . center .x;

42 i n t y1 = line . A.y;

43 i n t y2 = line . B.y;

44 i n t yk = circle . center .y;

45 f l o a t u = (( xk - x1 ) * ( x2 - x1 ) + ( yk - y1 ) * ( y2 - y1 ))/ pow (( distance ( line .A , line .B)) ,2) ;

46 // Now let 's calculate the x and y coordinates


47 f l o a t x = x1 + u * ( x2 - x1 );

48 f l o a t y = y1 + u * ( y2 - y1 );

49 // " Reuse ", we 'll use some older functions , let 's create a point , with the coordinates we
found
50 Point P;
51 P.x = x;
52 P.y = y;
53 // Let 's check if the " closest point " we found is on the line
54 if (! line_point_collision ( line , P)) {
55 // If the point is outside the line , we return false , because the ends have already been
checked against collisions
56 return f a l s e ;

57 } else {
58 // Let 's Reuse the Point / Circle Algorithm
59 r e t u r n circle_point_collision ( circle , P);

60 }
61 }

9.2.7 Point/Rectangle Collision

If we want to see if a point collides with a rectangle is really easy, we just need to check if the point’s coordinates

are inside the rectangle.

Listing 43: Point/Rectangle collision detection

1 bool pointRectCollision ( f l o a t x1 , f l o a t y1 , f l o a t rectx , f l o a t recty , f l o a t rectwidth , f l o a t

rectheight ){
2 // We check if the point is inside the rectangle
3 r e t u r n x1 >= rectx && x1 <= rectx + rectwidth && y1 >= recty && y1 <= recty + rectheight ;

4 }

9.2.8 Point/Triangle Collision

A possible way to define if a point is inside a triangle, we can use a bit of geometry.

We can use Heron’s formula to calculate the area of the original triangle, and compare it with the sum of the areas

created by the 3 triangles made from 2 points of the original triangle and the point we are testing.

9 COLLISION DETECTION AND REACTION 199


2D Game Development: From Zero To Hero

Figure 150: Point/Triangle Collision Detection: division into sub-triangles

If the sum of the 3 areas (represented in different colors in the figure) equals to the original calculated area, then

we know that the point is inside the triangle.

Let’s see the code:

Listing 44: Point/Triangle Collision Detection

1 #i n c l u d e < cmath >

3 bool point_triangle_collision ( f l o a t px , f l o a t py , f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , f l o a t

x3 , f l o a t y3 ){
4 f l o a t original_area = std :: abs (( x2 - x1 ) * ( y3 - y1 ) - ( x3 - x1 ) * ( y2 - y1 ));

5 f l o a t area1 = std :: abs (( x1 - px ) *( y2 - py ) - (x2 - px ) *( y1 - py ));

6 f l o a t area2 = std :: abs (( x2 - px ) *( y3 - py ) - (x3 - px ) *( y2 - py ));

7 f l o a t area3 = std :: abs (( x3 - px ) *( y1 - py ) - (x1 - px ) *( y3 - py ));

8 i f ( area1 + area2 + area3 == original_area ){

9 return true ;

10 } else {
11 return f a l s e ;

12 }
13 }

Let’s see how we can change the algorithm to accommodate for some leeway, since the we may be requiring too

much precision from our algorithms. We can do that by using epsilon values.

Our main test is that the sum of the area of the 3 triangles we create (A1 , A2 , A3 ) is equal to the area of the original

triangle (A0 ), in math terms:

A1 + A2 + A3 = A0

We can also rewrite such equation this way:

A1 + A2 + A3 − A0 = 0

9 COLLISION DETECTION AND REACTION 200


2D Game Development: From Zero To Hero

Due to possible precision issues we know that there are some values where the equation above is not true, so we

choose a “low enough error” that we are willing to accept, for example ϵ = 0.0001, and use this test instead:

|A1 + A2 + A3 − A0 | < ϵ

Which can be expanded (if you want) to

−ϵ < A1 + A2 + A3 − A0 < ϵ

The code wouldn’t change much, but for sake of clarity, here it is:

Listing 45: Point/Triangle Collision Detection with epsilon

1 #i n c l u d e < cmath >

3 bool point_triangle_collision ( f l o a t px , f l o a t py , f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , f l o a t

x3 , f l o a t y3 ){
4 // We accept anything that is closer than 1/1000 th of unit
5 const f l o a t epsilon = 0.0001;

6 f l o a t original_area = std :: abs (( x2 - x1 ) * ( y3 - y1 ) - ( x3 - x1 ) * ( y2 - y1 ));

7 f l o a t area1 = std :: abs (( x1 - px ) *( y2 - py ) - (x2 - px ) *( y1 - py ));

8 f l o a t area2 = std :: abs (( x2 - px ) *( y3 - py ) - (x3 - px ) *( y2 - py ));

9 f l o a t area3 = std :: abs (( x3 - px ) *( y1 - py ) - (x1 - px ) *( y3 - py ));

10 i f ( std :: abs ( area1 + area2 + area3 - original_area ) < epsilon ){

11 return true ;

12 } else {
13 return f a l s e ;

14 }
15 }

9.2.9 Circle/Rectangle Collision

First of all we need to identify which side of the rectangle we should test against, so if the centre of the circle is to

the right of the rectangle, we will test against the right edge of the rectangle, if it’s above we’ll test against the top

edge and so on…

After that, we just perform some math on the distances and calculated values to detect if the circle collides with the

rectangle.

Listing 46: Rectangle to Circle Collision Detection

1 #i n c l u d e < cmath >

3 s t r u c t Point {

4 // Rewritten as a memo
5 int x;

9 COLLISION DETECTION AND REACTION 201


2D Game Development: From Zero To Hero

6 int y;

7 };
8

9 s t r u c t Rectangle {

10 // Let 's define a rectangle class / structure


11 Point corner ;
12 i n t width ;

13 i n t height ;

14 };
15

16 s t r u c t Circle {

17 // Let 's define a circle class / structure


18 Point center ;
19 i n t radius ;

20 };
21

22 bool circle_rectangle_collision ( Circle circ , Rectangle rect ){

23 // Detects a collision between a circle and a rectangle


24

25 // These variables are used as the coordinates we should test against


26 // They are temporarily set to the circle center 's coordinates for a reason we 'll see soon
27 i n t tx = circ . center .x;

28 i n t ty = circ . center .y;

29

30 // Let 's detect which edge to test against on the x axis


31 i f ( circ . center . x < rect . corner .x){

32 // We 're at the left of the rectangle , test against the left side
33 tx = rect . corner .x;
34 } e l s e i f ( circ . center .x > rect . corner .x + rect . width ){
35 // We 're at the right of the rectangle , test against the right side
36 tx = rect . corner .y + rect . width ;
37 }
38

39 // Same thing on the vertical axis


40 i f ( circ . center . y < rect . corner .y){

41 // We 're above the rectangle , test against the top side


42 ty = rect . corner .y;
43 } e l s e i f ( circ . center .y > rect . corner .y + rect . height ){
44 // We 're below the rectangle , test against the bottom side
45 ty = rect . corner .y + rect . height ;
46 }
47

48 // Let 's get the distance between the testing coordinates and the circle center
49 i n t distanceX = circ . center .x - tx ;

50 i n t distanceY = circ . center .y - ty ;

51 f l o a t distance = std :: sqrt ( std :: pow ( distanceX , 2) + std :: pow ( distanceY , 2) );

52

53 // Note that if the center of the circle is inside the rectangle , the testing coordinates
will be the circle 's center itself , thus the next conditional will always return true
54

9 COLLISION DETECTION AND REACTION 202


2D Game Development: From Zero To Hero

55 i f ( distance <= circ . radius ){

56 return true ;

57 }
58

59 // Default to false in case no collision occurs


60 return f a l s e ;

61 }

9.2.10 Line/Line Collision

Line/Line collision is quite simple to implement once you know the inner workings of geometry, but first we need to

explain the thought behind this algorithm, so… math warning!!

Let’s look at the following image:

y I
8

1 2 3 4 5 6 7 8

x
Figure 151: Example image for line/line collision

A generic point Pa of line A can be represented with the following formula:

Pa = P1 + ua · (P2 − P1 )

which translates into the coordinate-based equations:



xa = x1 + ua · (x2 − x1 )

ya = y1 + ua · (x2 − x1 )

This makes us understand that any point of line A can be represented by its starting point P1 , plus a certain fraction

9 COLLISION DETECTION AND REACTION 203


2D Game Development: From Zero To Hero

(represented by ua ) of the vector represented by P2 − P1 .

This also means that 0 ≤ ua ≤ 1, else the point won’t be on the segment.

In the same way, a generic point Pb of line B can be represented with:

Pb = P3 + ub · (P4 − P3 )

which becomes:



xb = x3 + ub · (x4 − x3 )

yb = y3 + ub · (x4 − x3 )

The two lines will collide when Pa = Pb , so we get the following equations:



x1 + ua · (x2 − x1 ) = x3 + ub · (x4 − x3 )

y1 + ua · (y2 − y1 ) = y3 + ub · (y4 − y3 )

That need to be solved in the ua and ub variables.

The result is:



 ua = (x4 −x3 )·(y1 −y3 )−(y4 −y3 )·(x1 −x3 )
(y4 −y3 )·(x2 −x1 )−(x4 −x3 )·(y2 −y1 )

 ub = (x2 −x1 )·(y1 −y3 )−(y2 −y1 )·(x1 −x3 )
(y4 −y3 )·(x2 −x1 )−(x4 −x3 )·(y2 −y1 )

Substituting either of the results in the corresponding equation for the line will give us the intersection point (which

may be useful for some particle effects).

Now some notes on our solution:

• If the denominator for the equations for ua and ub equals to zero, the two lines are parallel

• If both the numerator and denominator for ua and ub are equal to zero, the two lines are coincident

• If both 0 ≤ ua ≤ 1 and 0 ≤ ub ≤ 1 then the two segments collide.

Now we can translate all this math into code:

Listing 47: Implementation of the line/line collision detection

1 bool lineLineCollision ( f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , f l o a t x3 , f l o a t y3 , f l o a t x4 ,

f l o a t y4 ){

2 // Let 's calculate the denominator , this will allow us to avoid a


3 // " divide by zero " error
4 f l o a t den = (( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 ));

9 COLLISION DETECTION AND REACTION 204


2D Game Development: From Zero To Hero

6 i f ( den == 0) {

7 // The lines are parallel


8 return f a l s e ;

9 }
10

11 f l o a t uA = (( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 )) / den ;

12 f l o a t uB = (( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 )) / den ;

13

14 // Let 's see if uA and uB tell us the lines are colliding


15 if (( uA >= 0 && uA <= 1) && ( uB >= 0 && uB <= 1) ){
16 return true ;

17 }
18

19 // If not , they don 't collide


20 return f a l s e ;

21 }

This collision detection algorithm can be useful for line-based puzzle games, line the untangle puzzle.

9.2.11 Line/Rectangle Collision

Given the previous explanation about the Line/Line collision detection, it’s quite easy to build a Line/Rectangle

algorithm; distinguishing the cases where we want to account for a segment being completely inside of a rectangle

or not.

Listing 48: Implementation of the line/rectangle collision detection

1 bool lineLineCollision ( f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , f l o a t x3 , f l o a t y3 , f l o a t x4 ,

f l o a t y4 ){

2 // our previous implementation of the line / line collision detection


3 }
4

5 bool pointRectCollision ( f l o a t x1 , f l o a t y1 , f l o a t rectx , f l o a t recty , f l o a t rectwidth , f l o a t

rectheight ){
6 // our previous implementation of a point / rectangle collision detection
7 }
8

9 bool lineRectangleCollision ( f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , f l o a t rectx , f l o a t recty ,

f l o a t rectwidth , f l o a t rectheight ){

10 // If we want to test if a line is completely inside of a rect , we just need


11 // to see if any of its endpoints is inside the rectangle
12 i f ( pointRectCollision (x1 , y1 , rectx , recty , rectwidth , rectheight ) || pointRectCollision (x2

, y2 , rectx , recty , rectwidth , rectheight )){


13 // At least one of the ends of the segment is inside the rectangle
14 return true ;

15 }
16

17 // Now to test the rectangle against the line , if it 's not completely inside
18 bool left = lineLineCollision (x1 , y1 , x2 , y2 , rectx , recty , rectx , recty + rectheight );

9 COLLISION DETECTION AND REACTION 205


2D Game Development: From Zero To Hero

19 bool right = lineLineCollision (x1 , y1 , x2 , y2 , rectx + rectwidth , recty , rectx + rectwidth ,

recty + rectheight );
20 bool top = lineLineCollision (x1 , y1 , x2 , y2 , rectx , recty , rectx + rectwidth , recty );

21 bool bottom = lineLineCollision (x1 , y1 , x2 , y2 , rectx , recty + rectheight , rectx + rectwidth

, recty + rectheight );
22

23 i f ( left || right || top || bottom ){

24 // We hit one of the sides , we are colliding


25 return true ;

26 }
27

28 // In any other case , return false


29 return f a l s e ;

30 }

This can prove useful to test for “line of sight” inside an AI algorithm.

9.2.12 Point/Polygon Collision

Here we are, the most complex matter when it comes to narrow-phase collision detection: detecting collisions

between arbitrary convex polygons.

Note!

In this book we will focus on convex polygons “without holes”, which is the most com-

mon situation you’ll find yourself in.

First of all, we will start by talking about some theorems and requirements that will help us on the way to build a

“polygon vs polygon” collision detection algorithm.

9.2.12.1 Jordan Curve Theorem

Let’s imagine a plane, like our 2D screen: if we draw a non-self-intersecting, continuous loop in the plane we obtain

a Jordan Curve. This curve separates the plane in two distinct regions: the “inside” and the “outside”.

9 COLLISION DETECTION AND REACTION 206


2D Game Development: From Zero To Hero

Inside

Outside

Figure 152: Example of a Jordan Curve

Any non-self-intersecting polygon (be it convex or non-convex) can be seen as a Jordan curve, this means that we

can easily identify (programmatically) if a point is inside or outside the polygon. At least in the “convex” case.

Let’s take a convex polygon, and a point inside such polygon: we can see that if we choose a point outside the

polygon (non-colliding) we can strike a line between the “inside point” and the chosen point, and such line will

intersect one of the polygon’s edges. This gives us an idea on how to check for “point vs. polygon”.

Q
Figure 153: A simple case where a point is outside the polygon

This doesn’t happen if the point is inside the polygon, obviously:

9 COLLISION DETECTION AND REACTION 207


2D Game Development: From Zero To Hero

Figure 154: A simple case where a point is inside the polygon

This is all well and good, but we have two problems on hand:

• Finding a point inside the polygon;

• We have a non-convex polygon;

Let’s leave the first problem aside, since talking about it may end up being confusing and just empty talk (or writing,

being this a book), and let’s focus on the second problem.

If we have a non-convex polygon, we may end up with a line that intersects the polygon’s perimeter even if the point

is colliding:

P Q2
Q1
Figure 155: How a non-convex polygon makes everything harder

Here we call P the “point inside the polygon” while Q1 and Q2 are the points we are testing: as we can see Q2
triggers our “non-colliding” test even though it is inside the polygon.

Can you see what can help us solving this issue? I’m sure you have a number of ideas in mind, we’ll talk about it in

the non-convex polygon collision detection section.

9 COLLISION DETECTION AND REACTION 208


2D Game Development: From Zero To Hero

9.2.12.2 Thinking outside the box: polygon triangulation

As you can see, as simple as it can be, the Jordan curve theorem poses some problems that may be a bit out of our

reach as of now, so let’s try to find a less ideal but easier to understand solution.

Let’s now limit ourselves to convex polygons, which (again) is the most common situation.

We can take inspiration from 3D graphics, where any solid shape (and thus the polygons that make those up) are

decomposed to a bunch of triangles. Nothing stops us from doing the same and taking any polygon and decomposing

it to a group of triangles, like follows:

Figure 156: Decomposing a polygon into triangles

This specific triangulation is called “fan triangulation” and it is chosen for its Θ(n) (where n is the number of vertices)

execution time.

9.2.12.3 Bounding Boxes

Before making our poor CPU undertake big calculations, we may want to check if there is even a possibility of a

collision, maybe with a simpler algorithm.

The great majority of the lifetime of our game objects is spent not colliding with anything, so if we can easily exclude

a collision before starting complex algorithms, our game will just benefit from it.

We can take our complex polygon and give it a “bounding box”, any point that is inside such box has a possibility of

colliding with our polygon, but any point outside the bounding box surely will not collide.

9 COLLISION DETECTION AND REACTION 209


2D Game Development: From Zero To Hero

Figure 157: Example of a polygon with its bounding box

How do we calculate a bounding box? Simple, we just need 4 coordinates:

• The smallest x (which we’ll call xmin )


• The smallest y (ymin )

• The biggest x (xmax )

• The biggest y (ymax )

The vertices of our bounding box will always be:

A(xmin , ymin ) B(xmax , ymin ) C(xmax , ymax ) D(xmin , ymax )

Tip!

Thanks to how rectangles work, we can just use the points A and C to build a rectangle:

since they contain all 4 coordinates, we can infer B and D from them.

This is simple to achieve: we just need to loop over all the vertices and find our coordinates. The algorithm here

below:

Listing 49: How to find the bounding box of a polygon

1 s t r u c t Point {

2 // Rewritten as a memo
3 int x;

4 int y;

5 };
6

7 c l a s s Rectangle {

8 Point corner ;

9 COLLISION DETECTION AND REACTION 210


2D Game Development: From Zero To Hero

9 i n t width ;

10 i n t height ;

11 // ...
12 s t a t i c Rectangle from_points ( Point topleft , Point bottomright ){

13 // ...
14 }
15 // ...
16 };
17

18 Rectangle bounding_box ( Point [] vertices ){


19 // First we create and bootstrap the variables
20 i n t xmin = vertices [0]. x;

21 i n t xmax = vertices [0]. x;

22 i n t ymin = vertices [0]. y;

23 i n t ymax = vertices [0]. y;

24 // Now we iterate through all the other vertices


25 f o r ( i = 0; i < vertices . length () ; i ++) {

26 i f ( vertex [ i ]. x < xmin ){

27 xmin = vertex [i ]. x;
28 }
29 i f ( vertex [ i ]. x > xmax ){

30 xmax = vertex [i ]. x;
31 }
32 i f ( vertex [ i ]. y < ymin ){

33 ymin = vertex [i ]. y;
34 }
35 i f ( vertex [ i ]. y > ymax ){

36 ymax = vertex [i ]. y;
37 }
38 }
39 // Now we can build the needed points for the bounding box
40 A = Point () ;
41 C = Point () ;
42 A.x = xmin ;
43 A.y = ymin ;
44 C.x = xmax ;
45 C.y = ymax ;
46 // We build our bounding box
47 boundingBox = Rectangle . from_points (A , C) ;
48 // and return it
49 r e t u r n boundingBox ;

50 }

To check if the collision “may happen”, we can just use a simple Point vs Rectangle collision check.

9.2.12.4 Point/Polygon collision detection using triangulation

Finally, after all the math and preparations, we can start working towards our collision detection algorithm.

9 COLLISION DETECTION AND REACTION 211


2D Game Development: From Zero To Hero

Pitfall Warning!

This algorithm works only with convex polygons that have no holes, also it probably is

not the most efficient way to check for collisions between a point and a polygon.

This is more akin to an exercise in creativity and less about “notions”: we found a

simple solution to a complex problem. Even if it is not the most efficient, it may be

“efficient enough”.

9.2.12.4.1 The “Polygon” class

Differently from previous classes and structures, the “polygon” class will need a little more work. This is because

we are going to do more than just merely memorize vertices.

First of all we need an ordered list (or array) of vertices, which will be represented by points. Secondly, we need

facilities to calculate list of triangles, as well as their areas.

Pitfall Warning!

You may be tempted to memorize the “triangles” that are an output of the “fan trian-

gulation”, as well as their areas. This may be a good idea if well managed, but we

will need to take care of “moving” those triangles and manage when the polygon gets

deformed: in that case all the triangle areas will have to be recalculated.

Same goes for the bounding box, which will change in size when the polygon rotates

or deforms. In this book we will try to keep the class as generic as possible (as well as

simple), thus we will just recalculate everything every frame as needed.

Thirdly, we need the constructor to do some math before we can use the polygon. Finally we need to integrate a

“fanning” function.

Whew… That’s a lot of work, but here’s the code for the polygon class:

Listing 50: A (not so) simple polygon class

1 #i n c l u d e < vector >

3 c l a s s Polygon {

4 private :

5 Point * vertices ;
6

7 public :

8 Rectangle calculate_bounding_box () {
9 // This function calculates the bounding box
10 // -------------------------
11 // First we create and bootstrap the variables
12 i n t xmin = vertices [0]. x;

13 i n t xmax = vertices [0]. x;

14 /*
15 * ...

9 COLLISION DETECTION AND REACTION 212


2D Game Development: From Zero To Hero

16 * see the bounding box algorithm for the full version


17 * ...
18 */
19 // We build our bounding box
20 Rectangle boundingBox = Rectangle . from_points (A , C);
21 // and return it
22