About

Breakout3D is a clone of the classic breakout game extended into three dimensions with modern OpenGL. At this time, the game is too difficult to play due to the difficulty of determining depth without shadows, so it is more of a demo. The floor is thus treated as a wall so you can experiment with the Breakout3D world without it ending almost immediately.

Gameplay

The paddle has three degrees of freedom, all controlled using the mouse. The scroll wheel moves the paddle up and down, and mouse movements move the paddle around the ground plane. At any time, you can press the q key to quit, or the space bar to pause the game.

In the classic two-dimensional breakout and its clones, paddle collisions are not treated as ordinary collisions. The reflected angle of the ball is determined by the distance of the collision from the center of the paddle. For Breakout3D, this concept has been extended to three dimensions.

Features

  • Phong model lighting
  • The shader for this program implements phong lighting. The game can define materials for each object to control the specular, diffuse, ambient, and shininess components to use when it is rendered.
  • Collision detection
  • Each object that requires collision detection contains a bounding box component, and is checked against all other such objects during each iteration of the game loop. Objects implement an interface to respond to collision events.
  • Exploding bricks
  • When a ball collides with a brick, the game demonstrates a simple particle effect to model the destruction of the brick. A cube mesh is generated and then copies of random sizes, rotations, velocities, and lifetimes are distributed throughout the volume previously occupied by the brick.

Design

In the classic book on object-oriented design patterns, the Gang of Four stated an overarching principle: "favor composition over inheritance". Managing a large type hierarchy has many significant downsides, which can be circumvented by implementing complex objects as an aggregation of components. This approach has recently been catching on, as several new programming languages such as Go and Rust, eschew inheritance altogether. Also, many game studios are beginning to adopt a composition-based design pattern known as the entity-component model.

In an entity-component system, an object is represented by a unique ID and a container of components. One of the myriad benefits of this model is efficiency. Consider the typical case where you have a parent class, of which all game objects derive from, which defines a common element such as velocity. Every game object must then manage velocity on every game update, even if the object is stationary. The alternative is to implement velocity in the subclasses, which defeats one of the main purposes of inheritance (code reuse). Using an entity-component system, velocity is implemented as a component. An instance is registered with the ID of all non-stationary objects. Problem solved.

C++ is an extremely versatile programming language, which means there are quite a few ways one could implement this model. In the main game class, Breakout3D, I created a System (a map of components of a single type) for each type of component in the game. Some (not all) of the components I used were:

  • PositionComponent
  • This component simply contains a vector specifying the location of the object in world space. Most components depend either directly or indirectly on this component.
  • VelocityComponent
  • This moves the objects position component once every game update. An object without this component is stationary.
  • RenderComponent
  • A render component contains the mesh and material properties of an object, which is then used to render each object with OpenGL. An object without this component is invisible.
  • BoundingBoxComponent
  • This component allows other components to collide with this object. If a collision occurs, each object with a collision component will have its OnCollision method called.
  • LifetimeComponent
  • This component contains a counter that is decremented every game loop. When it reaches zero, the object is removed from the system.
See the code for more information.