Cocos2D-Mono 2.7.0 is now out!

Cocos2D-Mono 2.7.0 is here, with the engine's first nullable reference type annotations. Nodes, actions, sprites, textures, labels and more now tell the compiler which of their members can be null. A game with nullable enabled learns where it needs a null check when it builds, instead of from a NullReferenceException while it runs. Nothing stops compiling: apart from nullability, no public API changed. The release notes have the full rundown.
Converting the engine also turned up plenty of long-standing bugs, so 2.7.0 is a big bug-fix release too. More on both below.
What the Annotations Do
In a project with <Nullable>enable</Nullable>, the compiler now knows that CCNode.GetChildByTag returns null for an unknown tag, and that a node's Parent is null until it's added to one:
var player = layer.GetChildByTag(PlayerTag);
player.RunAction(jump); // warning CS8602: Dereference of a possibly null reference.
if (layer.GetChildByTag(PlayerTag) is CCSprite sprite)
{
sprite.RunAction(jump); // no warning: sprite can't be null here
}
2.7.0 annotates the parts of the engine a game touches most:
- the base nodes
- input handling
- layers, scenes and transitions
- actions
- particles and grid effects
- sprites and their caches
- textures and labels
The rest, including menus, tile maps, the director and scheduler, the platform code, the extensions and Box2D, follows through the 2.x releases, a directory at a time. By 3.0 the annotations cover the whole public API. A type that hasn't been converted carries no annotations, so it raises no new warnings either way. Projects that don't enable nullable get no new warnings at all.
Upgrading
Bump your package reference to 2.7.0. Three things are worth a look:
-
Builds that treat warnings as errors. If your project enables nullable and sets
TreatWarningsAsErrors, the new warnings fail the build until the code checks for null. To upgrade now and fix them as you go, keep them as warnings for the time being:<PropertyGroup><WarningsNotAsErrors>nullable</WarningsNotAsErrors></PropertyGroup> -
More specific exceptions. Some failures that used to surface as a
NullReferenceExceptionnow throw an exception that names the problem. For example, several methods given a texture or font file that can't be loaded throwArgumentException, and reversing an action that has no reverse throwsNotSupportedException. If your code catchesNullReferenceExceptionfrom the engine, catch the new type instead. -
Fixes that change behavior. A few actions now do what they always claimed to:
CCShuffleTilesandCCTurnOffTilesfollow their seed.CCMoveFromandCCColorBlendAnimationchange their node.CCAccelDeccelAmplitudeanimates the effect it wraps.
If your game worked around the old behavior, check it.
The CHANGELOG covers every change under Upgrading, Changed and Fixed.
Bugs Found Along the Way
Annotating code means asking, member by member, "can this be null here?" A surprising number of the answers turned out to be bugs. The CHANGELOG lists 44 fixes. Some highlights:
- Copies that changed the original.
Copy(zone)onCCScaleTo,CCScaleBy,CCReverseTimeandCCOrbitCameracopied the wrong way, overwriting the original action with the new one's values. A copiedCCCardinalSplineBy,CCCatmullRomToorCCCatmullRomBycame back as aCCCardinalSplineTo. So a copied spline-by action moved the node to the spline's absolute points instead of relative to where it started. - Actions that never set their target.
CCMoveFromandCCColorBlendAnimationnever changed their node, andCCRotateAnimationthrew as soon as it ran. - Touch priority mid-touch.
CCTouchDispatcher.SetPriorityfailed when called during a touch dispatch. That happens when a menu callback opens a popup menu. CCLayerMultiplexbookkeeping. Its layer order, indexing andSwitchToAndReleaseMeall had bugs. It now switches, numbers and releases layers correctly.- Sprite sheets.
CCSpriteSheetCache.AddSpriteSheetignored the stream or dictionary it was given.CCSpriteFrameCache.RemoveSpriteFrameByNamethrew for a frame that had no alias.
The fixes come with regression tests: the unit suite grew from 132 tests in 2.6.2 to 300.
Full Changelog: https://github.com/Cocos2D-Mono/cocos2d-mono/compare/v2.6.2...v2.7.0
Also New Since 2.6.0
Two smaller releases shipped since our last post:
- 2.6.2: Mac Catalyst and tvOS from source. The engine now builds for Mac Catalyst and tvOS against our MonoGame fork. MonoGame publishes no package for either platform, so they aren't in the NuGet packages. The README's Platform support section has the build steps. It also sets out which platforms are in the packages and which build from source. On tvOS, the Siri Remote's select button arrives as gamepad input.
- 2.6.1: label fixes on Linux and macOS.
CCLabelnow disposes the native Skia canvas and font it creates on each redraw, instead of leaving them for the garbage collector.
NuGet Packages
-
Cocos2D-Mono (Windows, Linux, macOS, Android, iOS): Cocos2D-Mono
-
Cocos2D-Mono.Core — same engine, no content-pipeline dependency: Cocos2D-Mono.Core
-
Cocos2D-Mono.Box2D — the Box2D physics port: Cocos2D-Mono.Box2D
The samples package and the Visual Studio project templates move to 2.7.0 too.
What's Next
More annotations. The next releases take on menus, tile maps and the rest of the engine. If you find a member annotated wrong, either nullable where it can never be null or the other way round, please open an issue.
Thanks, as always, for being part of it. GO COCOS NUTS!