Wizard Fu's Cocos2dx Platformer Game Engine v1.0.1

nat@wizardfu.com

See the file LICENSE for the license governing this code.

Level is a cocos2d::Node which contains the TMXTiledMap, Physics, backgrounds, foregrounds, LevelObjects, scripts, exit points and more. A Level can be given an overall color value which is used by dynamic texturing and some objects to derive color.

Level handles moving the camera by following the specified cameraFollowNode. It uses a smoothing and clamping algorithm which causes the camera to smoothly move from one position to another and never shows anything beyond the extent of the Level. Moving the camera automatically causes backgrounds and foregrounds to be parallaxed. A screen shake camera animation can be put into effect by using setScreenShakeTimer and setScreenShakeStrength.

The setMirrorY method can be used to set the y-position at which the Level should mirror all sprites. This can create water-like reflections. The default is 0 which disables all reflections.

Level can put the game into slow motion by using setSlowMotionTimer. The Player object uses this to go into slow-mo when melee attacking.

Because the Level updates all LevelObjects during its tick by iterating its children, arrays are maintained so that objects can be added or removed after the update has finished. Use addObject to add an object when the Level is already running.

Methods such as isClearTileArea and getDistanceFromGround are included to query the state of the TMX map’s tiles. These methods convert regular point-based math to tile-based math in order to determine if a tile exists.

Map Properties

Layer Properties

Dynamic World Generation

Each time a Level is created, the game’s random seed is used in conjuction with Assets/World.plist to generate the current overall area. Once the area has been generated, a level is generated (or loaded) within that area corresponding with the current area / level number.

An area can be completely structured with fixed tmx levels, completely random or a combination of both. Random level generation actually creates an xml tmx map as a string in memory and can be logged for debugging. Overall area maps can be logged to the console as well.

See LevelGenerator.cpp for detail on area and level generation.

World.plist

Assets/World.plist is a dictionary of all areas in the game. The key specifies the area number. Within each area dictionary, there are several key-value pairs which describe the area.

See World.plist for examples.

Dynamic Texturing

Once the level has been generated (or loaded in the case of static tmx files) it is passed through the dynamic texture generator. If the level has specified to use dynamic texturing, an algorithm is used to scan solid tiles and draw individual pixels into a buffer of memory. When finished, the buffer is turned into a texture, added as a child and the tmx layers of the level are set to invisible.

See LevelTextures.cpp for details on the process of procedural texture generation.

ExitPoint

ExitPoint represents a position in the Level which corresponds with an exit to another level. The ExitPoint contains the linked area, level and direction which the exit should animate.

Whenever the Player is found to be out of bounds of the level, the nearest ExitPoint is found and used to sucessfully complete the level. A new LevelScene is created for the new Level and a sliding transition is then used to smoothly animate between the scenes.

ExitPoint objects are specified in the tmx by creating objects of type Exit.

#pragma once
#include "Headers.h"

class LevelScene;

struct ExitPoint
{
	int area, level, direction;
	Vec2 pos;
	
	ExitPoint() : area(0), level(0), direction(0), pos(Vec2::ZERO) {}
	ExitPoint(int _area, int _level, int _direction, const Vec2& _pos) : area(_area), level(_level), direction(_direction), pos(_pos) {}
};

Level

class Level : public Node, public PhysicsDelegate
{
	public:
		Level(int areaNum, int levelNum, float ease);
		~Level();

Get current area / level number.

		GETTER(int, areaNumber, AreaNumber);
		GETTER(int, levelNumber, LevelNumber);

The node that the camera will follow. Defaults to the Player object.

		GETTER_SETTER(Node*, cameraFollowNode, CameraFollowNode);

Get the level color.

		const Color3B& getLevelColor() {return color;}

If the map has any automatic global Z layers.

		GETTER(bool, hasAutoGlobalZ, HasAutoGlobalZ);

Current camera position.

		GETTER(Vec2, cameraPosition, CameraPosition);

Offset of map.

		GETTER(Vec2, mapOffset, MapOffset);

If level is complete and did succeed.

		GETTER(bool, isComplete, IsComplete);
		GETTER(bool, didSucceed, DidSucceed);

The player entry / exit direction.

		GETTER(int, entryDirection, EntryDirection);
		GETTER(int, exitDirection, ExitDirection);

The Y height at which a mirror reflection has its horizon (the default, zero, indicates no reflection).

		GETTER(float, mirrorY, MirrorY);

Set a timer during which the game will play in slow motion.

		GETTER_SETTER(double, slowMotionTimer, SlowMotionTimer);

Set a timer during which the screen will be shook.

		GETTER_SETTER(double, screenShakeTimer, ScreenShakeTimer);
		GETTER_SETTER(double, screenShakeStrength, ScreenShakeStrength);

How long the level has been running.

		GETTER(double, upTime, UpTime);

Sets up the camera with the given screen middle.

		void setupCamera(const Vec2& screenMiddle);

Moves the camera to the given position using the given time delta for smoothing.

		void moveCamera(const Vec2& position, float delta);

Adds an object to the level with the given properties. Used to add objects dynamically once the level is already running. Automatically calls addChildAfterUpdate to ensure the addition happens outside the update loop.

		LevelObject* addObject(string className, ValueMap& properties);

Add a child outside of the update loop.

		void addChildAfterUpdate(Node* n, int z = 0, int tag = 0);

Updates the level and all the objects using tick and animate methods.

		void update(float dt);

Completes the level and either transitions to the next level or shows the player a continue screen. Use area -1, level -1 to flag the level completion as unsuccessful.

		void completeLevel(int nextArea, int nextLevel);

Return the tile position for the given world position.

		void getTilePos(const Point& posInPoints, int& x, int& y) const;

Clamp the tile position so it is guaranteed to be within bounds of the map size.

		void clampTilePos(int& x, int& y) const;

Return the TMX layer if a tile exists at the given tile position.

		TMXLayer* layerForTile(int x, int y, bool highlight = false) const;

Return true if a solid object at the given position with the given width and height can fit.

		bool isClearTileArea(const Vec2& posInPoints, float width, float height) const;
		bool isClearTileArea(TMXLayer* layer, int x, int y, int width, int height) const;

Get an object position which is guaranteed to be clear of tiles.

		Vec2 getClearObjectPosition(const Vec2& desiredPosInPoints, int tileWidth, int tileHeight);
		Vec2 getPlayerPosition(const Vec2& intialPosInPoints);

Return true if a solid tile is below the given object.

		bool hasSolidTileBelow(const Vec2& posInPoints, float width, float height);
		Vec2 getSolidTileBelow(const Vec2& posInPoints, float width, float height);

Return the object’s distance from the ground.

		float getDistanceFromGround(LevelObject& obj);

If possible, hang on an edge near the position.

		bool hangOnEdge(LevelObject& obj) const;

If possible, step up a tile.

		bool stepUp(LevelObject& obj) const;

Highlight a tile.

		void highlightTile(TMXLayer* layer, int x, int y, const Color3B& color) const;

Destroy a tile.

		void destroyTileNear(const Point& pos);
		void animateDestroyTileNear(const Point& pos);

Returns true if the level position is valid.

		bool isValidPosition(const Point& posInPoints, float radius) const;

Return true if the object is out of bounds.

		bool isOutOfBounds(const LevelObject& obj) const;

Create fixtures to represent a polygon.

		void createPolygonFixtures(vector<Vec2>& polygon, long type, float friction, int category);

Returns the total level size in tiles.

		Size getMapSize() const;

Returns the total level size in pixels / points.

		const Size& getTotalSize() const;
		Size getTotalSizeInPoints() const;

Returns the tile size in pixels / points.

		Size getTileSize() const;
		Size getTileSizeInPoints() const;

Return the color of the level.

		Color3B getLevelColor() const;

Get the Player object from the object layer’s children.

		Player& getPlayer();

Gets the parent LevelScene.

		LevelScene& getLevelScene();

Gets a level object by tag.

		LevelObject* getLevelObject(int tag);

Gets the closest exit point to the given position.

		const ExitPoint& getClosestExit(const Vec2& pos);

Get the given exit point.

		const ExitPoint& getExit(int area, int level);

Get an object by name.

		LevelObject* getObjectByName(const string& name);

Returns the object at the given destination or null if none found.

		LevelObject* objectAt(const Point& dest, LevelObject* forObject, bool isSolid, float fuzziness);

Animate a tile explosion.

		void animateExplosion(const Vec2& pos, float scale, float duration, const Color3B& color);

Wake physics bodies up after a pause.

		void wakePhysicsBodies();

Remove a script.

		void removeScript(const string& filename);

Push / pop music to play.

		void pushMusic(const string& filename, bool playImmediately);
		string popMusic();

Implements PhysicsDelegate to pass on collision contact data to level objects.

		virtual bool beginContact(void* userDataA, int categoryA, void* userDataB, int categoryB);

If kDebugDrawBoxes is set to 1, this will draw debug boxes around all the tiles and objects.

		virtual void draw(Renderer* renderer, const Mat4& transform, uint32_t flags) override;

Handlers.

		virtual void onEnter();
		virtual void onEnterTransitionDidFinish();
		virtual void onExit();

Private

	private:
		typedef Node super;
		typedef Level self;

		TMXTiledMap* map;
		Physics physics;
		Color3B color;
		LayerColor* bgColor;
		int layerCount,objectCount;
		Size totalSize,cameraExtent;
		Point cameraMin,cameraMax,cameraOffset,cameraDest;
		double accumulator,lastTickTime,completeTime;
		vector<Node*> objectsToAdd,objectsToRemove;
		std::map<LevelObject*,bool> levelObjects;
		int entryX1,entryX2,entryY1,entryY2;
		LayerColor* shadowLayer;
		float* shadowMap;
		Sprite* fgTerrain,*bgTerrain;
		LayerColor* radialLayer;
		bool disableParallax;
		std::map<int, Node*> backgrounds;
		std::map<int, Node*> backgroundLayers;
		std::map<int, Node*> foregrounds;
		std::map<string,string> scripts;
		vector<ExitPoint> exits;
		double screenShakeAccumulator;
		std::vector<string> music;
		std::map<string, int> soundLoops;
		string texturing;
		Mat4 modelView;
		CustomCommand customCommand;

		void loadMap(const string& filename);
		void createMap(int areaNum, int levelNum, float ease);
		void parseMapProperties();
		void createPhysicalWorld();
		void createFixtures(TMXLayer* layer, int onewayDirection);
		void createRectangularFixture(TMXLayer* layer, int x, int y, int onewayDirection);
		void prepareLayers();
		int prepareLayer(TMXLayer* layer);
		void setAutoGlobalZ(TMXLayer* layer);
		void setTileOpacity(TMXLayer* layer, int opacity);
		void createTerrain(TMXLayer* layer);
		void animateParallax();
		void addObjects();
		void tickObjects(float delta);
		void animateObjects(float delta);
		void addAndRemoveObjects();
		bool destroyTile(int x, int y);
		void animateEntry();
		void onDraw();
		void updateShadowsShader();
		void updateRadialShader();
		bool runScript(const string& key);
		void animateDestroyTile(int x, int y);
};
 
h