-
Notifications
You must be signed in to change notification settings - Fork 1
CHEATSHEET
The asset manager (at this moment) is for loading Textures and Tilemaps. The basic concept is to load a PNG file and add it to a C++ std::Map of <string, Texture*> or <string, Tilemap*>
Textures can be loaded at anytime, the beginning of your game, or the beginning of a Scene, etc. The way to load a Texture into the Asset Manager goes like this:
// Load texture and add it to the map
n2dAssetsLoadAndAddTexture("player", "res/player.png");
To use a texture, you can grab a pointer to the Texture like so:
// This is the way to get a texture
SDL_Texture* playerTexture = n2dAssetsGetTexture("player");
You may not need to go this low-level, as Sprites, Images, and Tiles simply take in the AssetName, which in the case above is "player". So to make a Sprite using that stored texture (after the n2dAssetsLoadAndAddTexture() command) would look like this:
// create player sprite at position (0, 0) with size (16, 16) on the 0th draw layer.
Sprite* player = new Sprite("player", Vec2(0.f, 0.f), Vec2Int(16, 16), 0);
Coming soon.
nova2d has a built in Color Manager. Some may find this useful, others may not. You can simply make your own Colors and reference them in any way but I recommend using the Color Manager. It works well when you want to add a bunch of colors for easy access.
Adding a color is as simple as calling the nova2d command: n2dAddColor(std::string your_reference_name, std::string colorHexCode, int alpha);
. An example of that goes as follows to add a white color: n2dAddColor("white", "ffffff", 255);
. (Alpha is 0-255)
Once colors are added to the engine, they can be retrieved by: n2dGetColor(std::string your_reference_name);
so to get the white color we added above, n2dGetColor("white");
Keep in mind, nova2d has some #defines for common colors. To use them type COLOR_ and if NovaCore.h is included somewhere, you'll get some autocompleted colors.
Controllers are extendable classes that have two main purposes: controlling the player or controlling an object or AI.
This controller is great for things like Bullets which shoot in a Linear path. Below is an example on how to use this class (without extending):
// Syntax:
// SimpleBulletController(Vec2Int startPosition, Vec2Int endPosition, const float moveUpdateDelay)
// Start at player position and go to top of screen (-32 Y)
SimpleBulletController* bullet = new SimpleBulletController(Vec2Int(playerPosition.x, playerPosition.y - 32), Vec2Int(playerPosition.x, -32), 4);
// Configure move speed and a Rectangular alive bounds (if bullet goes out of Alive Bounds then it is deleted from the game)
bullet->Configure(14, Rect(0, 0, Game::s_Width, Game::s_Height));
// Add a bullet sprite
bullet->AddSprite("player-bullet", bulletCreatePos, Vec2Int(16, 16), 1);
// Use the sprite as the rectangular physics collider
bullet->ConfigureCollider(bullet->GetSprite(), 0, "player-bullet");
// Create a collision function on the heap using a lambda function
// this can also be done with a simple function pointer with the type:
// std::function<void(Collision* collision)>
auto collisionFunction = new auto ([=](Collision* collision) {
// Use references (aliases)
Collider& a = *collision->m_ColliderA;
Collider& b = *collision->m_ColliderB;
// Handle collisions
});
// Assign collision function
bullet->ConfigureOnCollision(*collisionFunction);
Refer to the Drawables section
Drawing to the built-in Dear ImGUI UI is quite simple. Two steps are required:
- Create a function that uses ImGUI commands to draw your UI
- Add a GUIUpdater to call that function at the correct time inside the Game Loop Below is a very simple Example:
void MainScene::Start()
{
m_GUICleanID = n2dAddGUIUpdater(MainScene::DrawGUI, this);
}
void MainScene::DrawGUI()
{
ImGui::Begin("Create a New Window");
ImGui::Text("Draw some text in that window.");
ImGui::End();
}
void MainScene::DestroySelf()
{
n2dRemoveGUIUpdater(m_GUICleanID);
}
nova2d comes with an internal easy-to-use, barebones, scoring system which allows you to connect to a mySQL server and adjust scores. Below are a few examples on how to use this system.
Firstly, somewhere in your main.cpp, after you've created your Game object:
// The parameters are: (databaseName, connectionString, username, password, useNovaSQLScoring)
// below we set the database to "spaceshooter", then the connection string, username, password, and enable nova2dSQLScoring <- must enable to use
game.ConfigureSQL("spaceshooter", "tcp://127.0.0.1:3306", "root", "sqlpassword", true);
Then, maybe in your first level (Scene), start the score at 0 by executing this line of code:
n2dScoreSet(0);
And maybe on each enemy death, increase the score by 10 points, shown below:
n2dScoreAdd(10);
. You can also get the current score by using the #define n2dScore
Now, using the setup mySQL (which you enabled above), let's add "Sam" with the score of 10,000:
n2dSQLScoreAdd("Sam", 10000);
You can also remove scores like so: n2dSQLScoreRemove("Sam", 10000);
Getting the scores so that you can print them out is a bit more complicated but becomes easy once your are familiar with the syntax and how it works. Here is a quick example:
// Create variables to hold the scores
// -----
// Array(vector) of a Struct HighScore which simple has these fields: ID, PlayerName, PlayerScore
std::vector<HighScore> highscores;
unsigned long lowestScore; // Create a variable for lowest score (used to tell if player's score makes top N scores
n2dSQLScoreTopN(6, highscores, lowestScore); // Top N=6, top 6 scores
// Print all scores
for(size_t i = 0; i < highscores.size(); i++)
{
Highscore hScore = highscores[i];
LOGS(hscore.PlayerName + " : " + tostring(hScore.PlayerScore));
}
// -----
Create a Timer.
Below shows how to create a looping timer which creates an enemy every 1 second.
auto spawnEnemyFunc = auto new ([=](){
// Create an enemy
});
Timer* timer = new Timer(1000.f, true, *spawnEnemyFunc);
...
// When timer is no longer needed
timer->DestroySelf();
Below shows how to create one-time-run timer which changes the game level (Scene).
auto startGame = auto new ([=](){
// Goto level 1
n2dSceneChange("level1");
});
Timer* timer = new Timer(1000.f, false, *startGame);
...
// This type timer, one-time-run timer, auto-cleans up itself after onComplete function call.
Notice how the new
keyword is used on creation of the onComplete function and the timer. This is required if the timer must stay alive out of scope of the current function which is almost always the case
Tweens are nice because they allow you to animate a value from a starting value to an ending value along a function within a certain amount of time instead of the usual way (using a rate/speed to animate). Check out these cool Easing Functions. All of these have been implemented and can be used to, say, fade the alpha of a Sprite in, making the Sprite appear out of no where and become visible. Or imagine tweening an enemy to walk from X = 0 to X = 200 and then back again. Sound like a simple Mario character AI? Tweens are great for Cut Scenes as well and have such a flexible range of use that in UDRLController.cpp tweens are used for acceleration and deacceleration. Odd ey? Anyway, here's how you use them.
To simply tween a value from 0 to 100 in 1 second:
// First declare the value
int x = 0;
// Secondly, define and auto start the tween
// The function to add is this: n2dTweenAdd(isFloat, ref, start, end, durationMS, loop, del, type)
//
unsigned int cleanUpID = n2dTweenAdd(false, &x, 0, 100, 1000, false, true, TweenTypes::EaseInCubic);
//
//
// Above will do what we want and on completion, clean and delete itself since we set
// del = true, if del was = false then we need to do the following to clean up the tween:
//
// n2dTweenRemove(cleanUpID);
Notice how you have to pass a reference to x (&x) instead of just x. This allows the Tween Manager to properly change the linked value in the background. Also, it's important to note you must define whether you are using a FLOAT or INT data type. That may be fixed later but as of now, it is required.
Updates are a really simple way to adding a function onto the Game's main loop. In many cases you will be extending a nova2d class that has an Update() method and in those cases you can put your update each frame code inside that method. In other cases you could be creating your own class that needs to have an Update() method in it that's called each frame.
To do this in nova2d you use the nova2d command: n2dAddUpdater(functionToCall, context)
. Below is a small example.
namespace myproject
{
class PlayerController
{
private:
unsigned int m_CleanUpID = 0;
public:
PlayerController()
{
// Setup controller code here
// Add the updater (returns an ID for clean up)
m_CleanUpID = n2dAddUpdater(PlayerController::Update, this);
}
void Update()
{
// Code gets called every frame now after adding of updater
}
void DestroySelf()
{
n2dRemoveUpdater(m_CleanUpID);
}
};
}
Above demonstrates a basic use case for an Updater. It is important to note that using the n2dAddUpdater(...) will add the updater to the Scene and not the Game. This means when changing scenes, all the updaters are cleared.
To prevent the updater from being cleared on scene changes, use the alternative nova2d command:
n2dAddUpdaterPersistent(function, context)
. A persistent updater will remain in the game until removed manually. CHANGING SCENES will NOT clear persistent updaters. To remove and clean a persistent updater just use: n2dRemovePersistentUpdater(cleanID)
(works the same as normal updaters).