Tutorial 01: Introduction to CNA

CNA Tutorial Series  ·  Beginner

What is CNA?

CNA is a C++23 reimplementation of the Microsoft XNA 4.0 game framework. It exposes the same Microsoft::Xna::Framework API that XNA developers know, but compiles to native code using modern C++23 and runs on Linux, Windows, Android, and the web through SDL3.

The name "CNA" is a deliberate reversal of "XNA" — it signals that you are writing C++ instead of C#, but the programming model is the same. If you have ever written an XNA or MonoGame game you will find CNA immediately familiar.

CNA implements 227 of the 245 public types in the XNA 4.0 API, measured against FNA. That includes full 2D and 3D rendering, audio, input, the math types, and content loading — verified by 4,373 unit tests and 490 GPU pixel-readback tests across four rendering backends. Two things are deliberately missing and worth knowing up front: CNA cannot read .xnb content files, and it cannot load compiled .fx shaders.

CNA is research and demo quality, not yet recommended for shipping commercial games. It is ideal for learning game development, porting XNA/MonoGame projects to C++, building demos, and experimenting with game engine design.

The four rendering backends

CNA supports four interchangeable graphics backends selected at CMake configure time:

BackendCMake flagUse case
SDL_RENDERER-DCNA_GRAPHICS_BACKEND=SDL_RENDERERPortable 2D only, no shaders
EASYGL-DCNA_GRAPHICS_BACKEND=EASYGLOpenGL ES 3.0 / OpenGL 3.0+, full 2D and 3D
VULKAN-DCNA_GRAPHICS_BACKEND=VULKANVulkan, low-level control
BGFX-DCNA_GRAPHICS_BACKEND=BGFXCross-backend abstraction layer

For these tutorials we will use EASYGL as the primary backend because it supports both 2D and 3D rendering and runs on any machine with a modern GPU driver.

sharp-runtime

CNA depends on sharp-runtime, a companion C++ library that provides C#-compatible primitive types. This gives you types like intcs (equivalent to C# int), bytecs, Single, floatcs, boolcs, and C# string/array semantics. These types make the CNA source code mirror the original XNA C# code as closely as possible and help when porting existing XNA games.

You will see sharp-runtime types in CNA API signatures. In practice you can often pass plain C++ values (int, float, bool) directly because the types are implicitly convertible. The sharp-runtime repository must be cloned as a sibling directory to the cna directory.

The NOXNA marker

Some CNA APIs that have no XNA equivalent are annotated with a NOXNA marker in the source. This helps you distinguish CNA extensions from XNA-faithful APIs when porting code.

CNA vs XNA vs MonoGame

PropertyXNA 4.0MonoGameCNA
LanguageC#C#C++23
Runtime.NET Framework.NET / MonoNative (no runtime)
StatusDiscontinued 2013ActiveActive (research)
PlatformsWindows / Xbox 360ManyLinux, Windows, Android, Web
RenderingDirectXDirectX / OpenGL / Metal / VulkanSDL3 + pluggable backend
API compatibilityReference~100%227 / 245 types
GC overheadYes (.NET GC)Yes (.NET GC)None — RAII/smart pointers

If you already know XNA or MonoGame, porting to CNA is mostly a matter of translating C# idioms to C++ idioms. The class names, method names, and overall structure stay the same.

Key Differences: C++ vs C#

The biggest adjustment when coming from XNA/MonoGame is moving from C# to C++. Here are the most common differences you will encounter throughout these tutorials:

Memory management

C# uses garbage collection — you can allocate objects freely and forget about them. C++ requires explicit memory management. CNA games use smart pointers to handle this safely:

// C# (XNA/MonoGame)
SpriteBatch spriteBatch;
spriteBatch = new SpriteBatch(GraphicsDevice);

// C++ (CNA) — use unique_ptr for exclusive ownership
std::unique_ptr<SpriteBatch> spriteBatch_;
spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());

Properties become getter/setter methods

C# properties like GraphicsDevice.Viewport become getViewport() / setViewport() in CNA's C++ API:

// C# (XNA)
var vp = GraphicsDevice.Viewport;

// C++ (CNA)
auto vp = getGraphicsDeviceProperty().getViewport();

Namespaces and includes

Every CNA class lives in the Microsoft::Xna::Framework namespace hierarchy and requires a corresponding include:

#include "Microsoft/Xna/Framework/Game.hpp"
#include "Microsoft/Xna/Framework/Color.hpp"
#include "Microsoft/Xna/Framework/Graphics/SpriteBatch.hpp"

using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics;

sharp-runtime types

CNA function signatures use sharp-runtime types. In practice you can usually pass standard C++ types and they will implicitly convert:

// These are equivalent — intcs is implicitly constructible from int
intcs width  = 800;
int   height = 600;
graphics_.setPreferredBackBufferWidth(width);
graphics_.setPreferredBackBufferHeight(height);

No LINQ or delegates

Where XNA C# code uses delegates or LINQ, CNA uses C++ lambdas and standard algorithms. You will see this most in audio and effects APIs.

What You Can Build

CNA has enough of the XNA API implemented to build a wide variety of game types today:

  • 2D games — platformers, shoot-em-ups, puzzle games, visual novels. SpriteBatch, Texture2D, SpriteFont, and full input handling are all working.
  • 3D games — BasicEffect, VertexBuffer, IndexBuffer, Model loading, and draw primitives work on the EASYGL and VULKAN backends.
  • Tech demos — The CNA House 3D demo runs in the browser via WebAssembly.
  • Ports of XNA/MonoGame games — If you have an existing XNA or MonoGame project, CNA provides a migration path to C++ without rewriting your entire game.

Audio (SDL3_mixer backend), touch input, and some advanced effect types are partially implemented. The roadmap lists what is planned.

How These Tutorials Are Structured

This tutorial series builds a complete knowledge base in a linear sequence. Each tutorial adds one concept and provides working, compilable code examples.

  • Tutorials 01-02 — Introduction and environment setup. No code yet.
  • Tutorials 03-05 — Getting a window open, understanding the game class and game loop.
  • Tutorials 06-09 — Rendering: shapes, colors, textures, and text.
  • Tutorials 10-11 — Input: keyboard and mouse.
  • Tutorials 12-13 — Movement and animation.

Each tutorial assumes you have completed the previous ones. If you have XNA experience you may skim the early tutorials quickly — the C++ patterns will be the main new thing.

Code examples use the following conventions:

  • Member variables end with _ (e.g., spriteBatch_)
  • using namespace Microsoft::Xna::Framework; is assumed in all code examples
  • Headers are abbreviated — full include lists are shown only in tutorial 03

Prerequisites

These tutorials assume:

  • C++ basics — you are comfortable with classes, inheritance, pointers, and the standard library. You do not need to be a C++ expert, but you should know what std::unique_ptr is.
  • Game development concepts — you understand what a game loop is at a high level (update state, render frame, repeat).
  • Command line — you can run CMake and build commands in a terminal.
  • XNA/MonoGame familiarity is helpful but not required — the tutorials explain every concept from first principles.

You do not need to know C# or have used XNA before. Tutorial 02 walks you through installing every dependency from scratch.

Ready to get started? Head to Tutorial 02: Setting Up Your Dev Environment.