Suggestions for 2D (now 3D) game framework

Programming, for all ages and all languages.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Suggestions for 2D (now 3D) game framework

Post by AndrewAPrice »

If you haven't guessed by some of my previous posts, I'm writing a 2D game framework/engine. It's a C++ library - it's targeted for Windows but I making it cross platform may be a target in the future.

The current features I have so far:
* Create a game window in 1 line (including title, width, height, and optional fullscreen).
* A scene manager that contains wraps around everything within the scene.
* Sprites which can be
* - Scaled.
* - Rotated (and you can defined pivot aswell)
* - Tinted a colour.
* - Given a depth (closer sprites are drawn first).
* - Can be attached to a camera.
* A 2D camera (basically contains a 2D point which offsets a sprite at render time).
* Basic input handling (bool IsKeyDown([key]) at the moment).

This is an example program I've made with the framework so far: (it draws 2 bimaps on the screen and rotates one).

Code: Select all

#include <iostream>
#include <mgf.h>

using namespace MGF;
using namespace Core;

void Update();

Game *game;
Sprite *sampleSprite;
Sprite *sampleSprite2;
Camera2D *camera;

int main()
{
	game = new Game();
	if(!game->CreateGameWindow("Sample Game", 640, 480))
	{
		std::cout << "ERROR: Can't create game window.";
		return 1;
	}

	sampleSprite = game->GetScene()->CreateSprite(game->GetScene()->GetTexture("test.bmp"),Vector2Di(10,10));
	
	sampleSprite2 = game->GetScene()->CreateSprite(game->GetScene()->GetTexture("test.bmp"),Vector2Di(10,10));

	camera = game->GetScene()->CreateCamera2D();

	sampleSprite->SetScaling(Vector2Di(2,2));
	sampleSprite->SetCentre(); // sets the pivot point to the centre (only needed since we're scaling)
	sampleSprite->SetTint(Core::Colour(1.0f,1.0f,0.5f)); // tint the sprite a bright yellow
	sampleSprite->AttachCamera(camera);
	sampleSprite->SetDepth(0); // draw at the very front
	sampleSprite2->SetDepth(.1); // draw behind

	camera->SetPosition(Core::Vector2Di(-20,-20));

	game->Run(Update);

	delete game;

	return 0;
}

void Update()
{
	sampleSprite->SetRotation(game->GetTimeInMilliseconds()/500.0f);
	game->GetScene()->Render();
}
And alternative way of creating a sprite is:

Code: Select all

	sampleSprite = new Sprite(game->GetScene()->GetTexture("test.bmp"),Vector2Di(10,10));
	game->GetScene()->AddSprite(sampleSprite);
I haven't implemented a way to remove sprites from scenes yet (it'll just be void Scene::RemoveSprite(Sprite *sprite) probably and I'll have a Scene::DeleteSprite which removes it and frees the sprite's memory). I'll work on that when I get my input handler working correctly.

I haven't released anything yet until I finish writing a sample game with it (it's a turn-based war game - a little more complex than your average Pong game). This way I'll have implemented most features a 2D game would require and have tested them in a real-world example before making a release.

I'll later be adding sound and network. Sounds will be able to be attached to cameras too (for stereo left/right). But they're not my main priorities at the moment. Once I have a stable and mature 2D game framework I'll work my way up to supporting 3D primitives, then eventually loading meshes. But I'm holding 3D off until I fully implement 2D, input, sound, and network because it'll take up most of my time when I get around to it.

Is there anything I seem to be missing from my game framework so far?

(Unrelated, I've finished a 3D variation of Pacman with rockets and destructable walls: http://messiahandrw.netfast.org/portfol ... pacand.htm What do you guys think?)
Last edited by AndrewAPrice on Wed Oct 03, 2007 3:52 am, edited 1 time in total.
My OS is Perception.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re: Suggestion for 2D game framework

Post by Colonel Kernel »

Sounds like fun. I started on something like that for Java once, but then my summer vacation ended. :P
MessiahAndrw wrote:Is there anything I seem to be missing from my game framework so far?
A generic event-handling system.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Re: Suggestion for 2D game framework

Post by AndrewAPrice »

Colonel Kernel wrote:A generic event-handling system.
How do you mean? Well, I get what an event-handling system is (like calling a function when something happens). But what would the events be for?
My OS is Perception.
User avatar
eboyd
Member
Member
Posts: 97
Joined: Thu Jul 26, 2007 9:18 am
Location: United States

Post by eboyd »

I would like to see the BUFFER** handled in an #include.

Also, a more streamlined way of integrating audio would be much appreciated. I would love an API that would setup like this:

Code: Select all

#include "MyAPI.h"
#include "ScrBffr.h"
#define quit 1
int main(){
    
    gameControl = 0;
    level = 1;
    initGame(myGame);
    
    while(gameContol != quit){
        loadLevel(level, status);
        level++;
        gameControl = status;
    }
}

//the def might look like:
void loadLevel(int i, bool& q){
    
    loadBackground(i);
    loadAudiofile(i);
    q = routine();
}
"Simplicity" is the mother of invention.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re: Suggestion for 2D game framework

Post by Colonel Kernel »

MessiahAndrw wrote:How do you mean? Well, I get what an event-handling system is (like calling a function when something happens). But what would the events be for?
Simulation and animation. For simulation, take your turn-based war game for example -- each turn should be a loop that dispatches events to the objects in the game world, basically telling them to update themselves according to recent changes in game state. This scheme extends naturally from turn-based to real-time games, where each frame is an iteration of the main loop. For animation, imagine how you would add animation effects to the sprites in your war game and you'll see what I mean. Remember the old 2D version of SimCity, where buildings like power plants had animation loops that happened even if the game was idle? Same idea.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

I started writing my turn-based war game during a 2 hour plane ride (+ another 2 hours after). I've attached a screenshot of what I've done so far. It renders a map engine with buildings (they're tinted based on the player they're associated to, red = 1, green = 2, grey = neutral). The tile under the cursor tints grey to indicate it's selected, and the map scrolls so the cursor stays in the centre (which was simple, since I associated the tile sprites with a Camera2D, so I only had to update the Camera2D position) unless the camera is near a border.
My OS is Perception.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

I started writing my turn-based war game during a 2 hour plane ride (+ another 2 hours after). I've attached a screenshot of what I've done so far. It renders a map engine with buildings (they're tinted based on the player they're associated to, red = 1, green = 2, grey = neutral). The tile under the cursor tints grey to indicate it's selected, and the map scrolls so the cursor stays in the centre (which was simple, since I associated the tile sprites with a Camera2D, so I only had to update the Camera2D position) unless the camera is near a border.
Attachments
screenshot.JPG
screenshot.JPG (51.87 KiB) Viewed 2927 times
My OS is Perception.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

I've added support to my framework for basic 3D (flat lighting/only basic DirectX primitives (Box, Sphere, Teapot, Torus, Pyramid), cameras). Added a few more days of programming and I'll probably have mesh support along with custom meshes. There's a lot more setup code from when I last posted, but it's necessary for the level of object orientedness I'm inspiring for.

What's basically involved in setting up the framework is:
- Create the initial MGF:Game object.
- Create a display window
- Create a game scene
- Create a camera and attach it to a display window (and/or speakers when I have sound implemented) and a scene

You can have a number of camera's all looking at the same (or different) scene from different angles/positions and they can be attached to different windows or different areas of the same window.

To render a scene, just call the Render() function of the camera you want to render. Here is my updated sample program which places a box/torus in the middle of the scene with a movable camera:

Code: Select all

#include <iostream>
#include <mgf.h>

using namespace MGF;
using namespace Core;
using namespace Input;
using namespace Scene;

// Our logic loop below
void Update();

// Some required objects
Game *game;
DisplayWindow *gameWindow;
Camera *camera;
GameScene *scene;

// our primtive's we'll use
MeshPrimitive *box;
MeshPrimitive *torus;

int main()
{
	// create our game object
	game = new Game();

	// create our window
	gameWindow = game->GetObjectFactory()->CreateDisplayWindow(640, 480, "Sample Game", false);

	// create our scene
	scene = game->GetObjectFactory()->CreateGameScene();

	// create our camera and attach it to the scene and the window
	camera = game->GetObjectFactory()->CreateCamera(scene, Vector3Df(0, 2, -10));
	camera->AttachToDisplayWindow(gameWindow);

	// create our box and add it to our scene
	box = game->GetObjectFactory()->CreateMeshPrimitiveBox(1.0f, 1.0f, 1.0f);
	scene->AddEntity(box);

	// create our torus and add it to our scene
	torus = game->GetObjectFactory()->CreateMeshPrimitiveTorus(1.0f, 2.0f, 3, 20);
	scene->AddEntity(torus);
	

	// place the game in the logic loop
	game->Run(Update);

	// everything made in our object factory must be deleted in the object factory
	game->GetObjectFactory()->Destroy(box);
	game->GetObjectFactory()->Destroy(torus);
	game->GetObjectFactory()->Destroy(camera);
	game->GetObjectFactory()->Destroy(scene);
	game->GetObjectFactory()->Destroy(gameWindow);

	// delete the game object
	delete game;

	return 0;
}

void Update()
{
	// check to see if a key is down and move the camera the respective way
	if(game->GetInputManager()->GetKeyboard()->IsKeyDown(MGFKEY_D))
		camera->SetPosition(camera->GetPosition() + Vector3Df(0.2f,0,0));
	if(game->GetInputManager()->GetKeyboard()->IsKeyDown(MGFKEY_A))
		camera->SetPosition(camera->GetPosition() - Vector3Df(0.2f,0,0));
	if(game->GetInputManager()->GetKeyboard()->IsKeyDown(MGFKEY_W))
		camera->SetPosition(camera->GetPosition() + Vector3Df(0,0,0.2f));
	if(game->GetInputManager()->GetKeyboard()->IsKeyDown(MGFKEY_S))
		camera->SetPosition(camera->GetPosition() - Vector3Df(0,0,0.2f));

	// render our camera
	camera->Render();
}
Most methods (e.g. CreateCamera and the CreateMeshPrimitives) have about 4/5 different overloaded versions (placing their position/scale/rotation so you don't have to do it separately after).

Soon my camera will run in one of two modes; the "look at" camera (you provide a position the camera is facing), and the "rotate" camera (you provide the yaw/pitch/roll angles). And later I'm thinking about being able to 'lock' the camera position or look-at target onto on object.

Also, anything inside the GameScene inherits from SceneEntity. SceneEntity can hold a limitless about of SceneEntity children. All child position/scale/rotation is relative to it's parents (top level objects are relative to 0,0,0).
My OS is Perception.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

Okay, a few updates;
- You add nodes to a scene. A node contains a link to an entity. The node is what stores the position/rotation/scale. That way you can have multiple entities in one scene.
- You can attach materials to objects. There is a default white material if no material is attached (if you load a mesh from a file, you shouldn't have to worry about manually attaching materials).
- I fixed some rendering bugs.
- Cameras can either accept a rotation, or a position to look at.
My OS is Perception.
User avatar
t0xic
Member
Member
Posts: 216
Joined: Sat May 05, 2007 3:16 pm
Location: VA
Contact:

Post by t0xic »

That sounds really neat! Care to attach another screenshot?

Michael
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

I'll post another screen shot once I finish off lights, texturing, and loading meshes.

I don't have time to work on it right now (I have other college assessments too!), but those things are likely to be finished anytime from the next few days to the end of the week.
My OS is Perception.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

MessiahAndrw wrote:

Code: Select all

        *snip*
	// everything made in our object factory must be deleted in the object factory
	game->GetObjectFactory()->Destroy(box);
	game->GetObjectFactory()->Destroy(torus);
	game->GetObjectFactory()->Destroy(camera);
	game->GetObjectFactory()->Destroy(scene);
	game->GetObjectFactory()->Destroy(gameWindow);

	// delete the game object
	delete game;
        *snip*
Why not have the object factory maintain a list of all objects created. If you add a name to the objects you can search on object name for instance. To release the resources created by the object factory you could modify the game destructor to do a GetObjectFactory()->ReleaseAll(). The Destroy method of the ObjectFactory should of course remove the object from the list.
Author of COBOS
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

Thanks, I'll consider that.
My OS is Perception.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

It's been a while since I've been on these forums (a least a week) thanks to all the work given to me at college. A lot of it involved extending my framework. I currently have:
  • Multiple cameras (on same scene/many scenes/different part of the window)
    Multiple windows (although only one can be used for rendering)
    Multiple scene
    Incomplete HTML documentation (with help from Doc-o-matic)
    Texture manager
    Mouse/keyboard input
    Multiple instances of an object loaded once with scene nodes (saves a lot of memory) - scene nodes properties are also dependent on their parents node (rotation, position, scale).
    A few different types of scene entities:
    • Billboards
      Mesh Primitives (boxes, spheres, toruses, etc)
      Meshes (made up of mesh parts, which in term are made up of mesh indices/vertices)
      Mesh X's (a quick wrapper .X meshes, I want to intergrate this into my normal mesh class)
      3D Line lists
      2D text boxes
      Lights (spot, directional, point)
    Custom mathematics code (only a small amount of matrix code uses DX, most matrix and all colour, vertex, quaternion, vector math is mine)
I have a demo program (too big to attach - it's 9.9MB IIRC - I'll send it if anyone wants it) that demonstrates matrix/vector/light/material operations visually as part of a college project. There are also billboard trees, environment effects, and a hidden secret (you can get into one of the ships). Sadly, this demo is restricted to Win32/DirectX. The demo code itself does not contain any Win32 or DirectX specific code, only the framework.

On my todo list is:
  • Loose octrees (will significant speed up rendering, especially on my demo with such a populated environment)
    Make the framework API independent (to support both DX and OpenGL - any suggestions on the best way to do this?) which in turn will get rid of a lot of the code that ties it down to Windows.
My OS is Perception.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Make the framework API independent (to support both DX and OpenGL - any suggestions on the best way to do this?)
You'd need some sort of abstraction. I personally used a requestmodel()/rendermodel()/freemodel() set of calls that allowed me to render whatever I wanted without being aware of the underlying functionality (which I afterwards broke by inserting dx.setrenderstate calls in the main loop and such). You could extend that with a setcamera(matrix) and setparameter(function,value) calls and map either one to either glLoadMatrix and other glxxx functions or SetTransform / SetRenderState calls. BeginDraw and EndDraw calls would also be nice to have.
I have a demo program (too big to attach - it's 9.9MB IIRC - I'll send it if anyone wants it)
I'm interested :) If you want I can send you my directx engine in exchange if you want to. (its stuffed with funky directx features which you may find interesting, including some model loaders you probably won't have).
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply