Jump to content

  • Log In with Google      Sign In   
  • Create Account

speciesUnknown

Member Since 08 Oct 2006
Offline Last Active Nov 20 2012 04:52 PM

#4840953 Self set Challenge: 2 month dev cycle

Posted by speciesUnknown on 26 July 2011 - 11:27 PM

I've set myself a personal challenge; to turn around a game inside of 2 months, while also working full time. I've decided that over the next year (starting a month ago) I'm going to work towards being able to turn around a game inside of 2 months.

What has spurred this somewhat bold idea?

So far, I've always worked on one pie in the sky idea or another, and this has usually resulted in a fun, but fruitless, process and very little playable material. I spent no less than 3 years trying to produce something resembling GTA3 with zombies (grand theft zombie or similar), but while I was doing this, the industry was moving around me. If I can reliably turn around a game inside of 2 months, then i will be able to turn around a commercial game product given externally set deadlines. Or so goes the theory.

I've set myself challenges before, but these challenges have had far-future ending dates and uncertain goals. I know based on things I've done in the past that if I focus on something I can churn out a vast amount of not-terrible code in a short amount of time, even with a few arbitrary requirements. I've spent years studying how games are put together and can quite successfully teach others to do it, so why not do it myself?


The reward:

If I succeed within this dev cycle (allowing for things such as moving house at the beginning of july, ludumdare, hopefully visiting some family early next month) I will buy myself a 360 and pay the subscription for publishing XNA games. I've set my deadline for a playable prototype at August 19th, which is approximately 8 weeks after my start date on June, ignoring the week I moved house.

The litmus test:

My game has to have the following features:

Maintainable
The code has to be maintainable; not necessarily perfect, but I want to avoid my usual "object orgy" approach to programming; to this end I'm using a component based architecture. Although some would say that component based architecture is Object Orgy writ large. Rapid prototyping does mean that you can throw away a lot of code but i dont want to throw away ALL my code as this is very wasteful.

Playable
This is critical. the player has to be able to drive around the level, in pursuit of some goal, while being attacked by enemies. I've started implementing a very very basic system of seperation between semantically "engine" code and semantically "game" code. I'll do some cleanup once my goal is achieved.

Performance
I'm using c# and this produces some performance challenges which are outside of my usual comfort zone. I've given myself a slightly challenging goal - no allocations at runtime in normal circumstances (i.e. with basic level planning, I need to be able to avoid too many run time allocations). This is important on the 360 because the GC is not so sophisticated, having various performance issues not experienced on the PC platform. (every 1mb allocated triggers a full recursive mark and sweep). So far, I've used a limited amount of object reuse / pooling to overcome this problem. The ability to use structs (a value type in c#) for math and logic is critical here also and has helped considerably. On modern hardware, it seems that a copy of a small to medium sized value type is cheaper than dynamic allocation.

3D: Yes, the game is 3d. believe it or not, provided I have a reasonable bit of physics middleware, I'm just as happy working in 3d as I am in 2d. I've picked up the physics engine BEPU which so far, appears to be very well engineered, and most operations with it don't allocate huge amounts of shit to be collected by the GC.

Sound, music
Just the basics; placeholder artwork which is integrated properly with the rest of the world, thus demonstrating that I am actually capable of turning around such a system quickly enough.

Scripted events
A storyline is impossible without this. The initial prototype will consist of a scripted demo level, with hopefully about 10 minutes of gameplay.

I have a blog on tumblr documenting my progress here;


http://newoldstuff.tumblr.com/

I began my challenge in its current form on the 21st of June, the same day I wrote my basic lighting functionality for 3 directional lights. I'll be taking a few days out because of ludumdare on the 19th-22nd and so my final prototype should be arriving on the 26th.

Tonight I will implement my damage modelling system to accompany my projectile system (which took a few days but which I'm quite proud of because it works and its damn fast to boot).

[Edit] Oops, I actually started on the 21st


#4840935 What's the point of C++0x?

Posted by speciesUnknown on 26 July 2011 - 09:29 PM

The point of c++0X is to add language features to overcome the problems with the other language features.
A few technical issues drove me away from c++ for small games, and I'm sad to note that c++0x doesn't solve any of those issues. I've determined that for small games, almost any other language with reasonable API's is a superior choice, and that for larger games, a C api DLL, with heavy use of c++ in the background to save time, and with a less performant scripting language for gameplay programming, is the best solution.

My list of problems with c++ are as follows:

Very limited ability to build a DLL for use with other languages. In practical terms, we are pretty much limited to the C api if we want language interop. This became a problem when I wanted to put a class library into a DLL; i found that it was almost impossible to have Engine.dll (c++) and Game.exe(lua) without Engine.dll using the C interface. I went through luabind and found that it was an incredibly intrusive and tedious task to bind up functions and methods and constructors and instances, and I got pretty confused when I tried to use it with shared_ptr. I looked at other scripting languages and their problems were similar in nature; they only really worked well with a pure C interface. The work required to shoehorn a c++ api into a C api and then bind this C api into an OO scripting language makes c++ counterproductive to use.

Memory management. shared_ptr is the only viable way to do this but I find that if one is using shared_ptr suddenly everything becomes a lot more complex, especially if one is using a library which performs template metahackery but does not explicitly support shared_ptr, as I found with luabind. I wanted to tag an object in the Havok physics engine with the shared_ptr to a game entitiy, but this is impossible; instead I had to do a hack using a static std::map<int, shared_ptr<...> >.

smart pointers don't live up to their expectations in that they do not really function properly as a determinstic garbage collection system. The biggest problem I found is the inability to pass anything a pointer to self (e.g. foo(this) from within a constructor. enable_shared_from_this does not function from within a constructor as all the binding is done after the constructor has been called. I also had a go at using intrusive_ptr but that was also a bust because of the boilerplate involved; I couldn't create a thread safe base class of IntrusiveRefCountedObject or anything similar without some serious work.

The compile model. 0x still relies on macros to help it compile. Circular references are an irritation. Having to modify the code in a file to make it compile faster (forward declaration, p_impl shenanigans, precompiled headers) is counterproductive.

Language level support for delegates. When I tried to use boost.function and boost.bind I ran into several brick walls, mainly due to a lack of compatibility with shared_ptr; boost.bind keeps shared_ptr alive basically forever. I don't think it would be that hard to implement delegates as a language level feature, but this is where the lack of an ABI kicks in. You cannot combine any of the various versions of function bind and shared_ptr / weak_ptr together; you have to use them from all the same version.

I don't think any of these problems will be ever solved to my satisfaction, at least not in my lifetime; most c++ programmers seem not to find any of these things to be a problem, but in fact, they welcome them as the side effects of what they see as good design decisions. Usually I am told that the way to solve these problems is to use more and more template metahackery or other language features, not use scripting languages and to use c++ as a scripting language instead, and I find that all this additional work one must do erodes the benefits of compatibility and performance.




#4797648 [Help] Metro GUI

Posted by speciesUnknown on 12 April 2011 - 02:26 PM


Most important question to make the difference "easy GUIs are easy to do yourself" and "just ignore the bloat". Do you need your elements to have complex scaling like you get in regular GUIs by using lots of spacers and sizers or is it fixed at one size (or at least scales 1:1 with the window size)?

Do you prefer actual events to process in your main loop or direct callbacks? How special will some of your elements get? Will it be limited to labels, pictures, buttons or will you need sliders, check boxes, radio buttons and the like?


I guess I will just ignore the bloat for now, my GUI will be a dynamic UI with shuffling and scaling text. I will be utilizing check boxes, radio buttons, etc. But no GUI window management(moving windows with mouse, etc).



Thanks for the response!


A simple static tree based GUI system is very simple to implement; do it a few times and it sticks with you forever. Ive done this several times in the past; in different languages, or just for fun. Currently im using one I wrote for C#. For a university assignment I wrote a very simple one consisting of button only for WinBGI. For another university assignment I did a different one in C#, which is designed for XNA, but still supports the mouse (for testing) and keyboard (in a very crude way).

This system consists of a statically build tree of widgets. An alternative to this is an immediate mode GUI which is a different matter entirely; i have no experience with this.

0) Your base class of widget should have a list of child widgets and an API for adding them. Children are linked with their parent and parents to their children - in c++ you will need to use shared_ptr for parent->child relationships and weak_ptr for child->parent. Children have a position which is relative to their parent widget.

For simplicity of implementation, but less flexibility and a lot of annoyance when laying out your GUI, you can just have every widget exist in global coordinates.

1) Special widgets extend the base class and change the rendering behaviour. THey may use a different set of coordiantes when being skinned using a texture.

A more complex option seperates state from rendering but this is not necessary - For a simple implementaion, I just override BaseWidget::draw. More complex implementations use a renderable component. Dont do this if its your first time.

2) Your base class of widget has a series of callbacks for getting events *out* of the GUI - at a bare minimum you need mouseUp for detecting clicking. Each widget will first test itself; if the event is within the bounds of the widget, but no callback was bound, it will then test its children. In C# I use delegates, in C / C++ I use plain old fashioned function pointers, or boost.function / boost.bind.

You can replace this system with a series of direct queries, so that you can do code such as

someButton.wouldBeClicked(int mouse_x, int mouse_y, int mouse_button);

This brings you some benefits of an immediate mode GUI system. If your widgets are all in global coordinates this is just a bounding box test. If they are relative to their parents, you need to calculate the absolute position by following the tree back up through the parents of parents etc.If your widgets do not change depending on whether the mouse is over them, you can use this system exclusively and totally forget about point 3) but I usually have both systems implemented.

3) Your base class of widget will have a series of event *input* functions - these go in the opposite direction, starting on the outer widget and moving down through children, depth first.
At a bare minimum you need onMouseUp(int mouse_xpos, int mouse_ypos, int mouseButton) and onMouseMove(int old_x, int old_y, int new_x, int new_y).

This is necessary for maintaining the state of each widget in a system where things display themselves differently depending on the mouse state. If you drop that feature, you can forget about this.

4) Skinning is relatively easy if you use a basic texture coordinate based system. Each widget is a 3x3 grid of quads, with texture coordinates aligning to a square texture. Each corner is mapped to a corner of the texture, and does not scale when the widget changes size. The left and right edges scale vertically. The top and bottom edges scale horizontally. The centre scales in both directions.

If you use semitranslucent textures and multiplicative blending, this can look very, very cool, for minmimal effort. I tend to use a single vert / frag shader and a single texture for each skin. Ive used several other methods of skinning, including having a mesh for each widget, but this gives the best balance of simplicity and flexibility.

5) Usually your base class of widget would be invisible. You can then make a set of extended widgets like so:
a) A container - extends base and draws itself the same way regardless of the state of the widget. Does nothing else interesting.
b) A label - draws some text. Thats it really.
c) A button - draws itself one way when the mouse is over it and another when the mouse is not. Then draws its text on top.
d) A check box - has an "unchecked" property and a "checked" property, draws itself as a text check box. returns one or the other when you ask it for its value.
e) Radio button - the same as the check box, but is also linked to a list of the other radio buttons it is associated with via weak pointers (c++)
f) Slider - so long as the LMB is down, wherever you move the mouse to within the widget, thats where the slider goes.

Beware of having too deep an inhertiance tree here; i tend to only have one level of inheritance. I can implement all of this in a few hours if the feature set is known at the start. There are of course many far more advanced ways of doing this stuff. I tend to have my Base widget unusually large, but have it uses a series of public instances of more dedicated member classes, so instead of having a billion method calls one will do code such as
widget.components.addComponent(x, y, button);
or
widget.callbacks.addCallback(butnFoo_onClick);

6) When drawing, you need to do the following:
set up an orthographic projection
disable depth testing and depth sorting
iterate the tree, drawing each widget followed by its children.

I tend to have a dedicated GUIRenderer class; so, my draw function typically looks like this:

void Widget::Draw(shared_ptr<GUIRenderer> renderer)
{
drawSelf(renderer);
drawChildren(renderer);
}

I break it up to increase the flexibility of extended classes of widget, as some will override one function or the other, or even both.

This is what I recommend you aim for if you are trying to implement your own GUI from scratch. Obviously, you will get a lot more functionality if you use an existing GUI framework; its that age old decision about whether or not to spend time implementing ones own system.


#4784492 zzz

Posted by speciesUnknown on 11 March 2011 - 12:58 PM

I don't think you understand what "epic" means. An IntelliSense bug, particularly one related to templates, is hardly even worth noticing, let alone creating a dedicated "epic" thread about.


Translation: Stop dissing your favourite IDE, Visual Studio. You should just rate this guy down if you don't like his post.


#4779760 reason i love my wife

Posted by speciesUnknown on 27 February 2011 - 01:03 PM

So the wife and I got a new computer last weekend. It has been 5 years since we got a new one, so the specs seemed off the charts compared to the one we had. We had windows installed on the old one before the hardware died.

So we bring this computer home. I boot it up, its got ubuntu. I am thinking to myself, she used ubuntu before and liked it. Always said she needed ubuntu to print out coupons or whatever.

She played resturant city for a few days and commented on how much the game plays. I never really got a go on the ubuntu as I didn't want to go through with tracking down and installing drivers and all the other third party plugins and stuff.

Then one day. Danny (my wife) says to me.

"Ahh I hate ubuntu. I have to do too much crap just to do something. Install windows."

She was right too. I also hated gnome, with it being so ugly. The way I have to compile the kernel just to get my wifi to work. The confusing command line utils that takes forever to find documentation for. Oh and let's not forget all of the unnecessary bloat that come with the default ubuntu installation. I was missing the simple, it just works, windows.

And now that win 7 is up and running. My wife feels at home. And it is running way better then our last computer. I am in heaven ^_^

Now to play "back to the future" without having to run directx and wine.



#4767963 Game timer

Posted by speciesUnknown on 01 February 2011 - 08:54 AM

People really like to over-engineer this. You get people telling you that you can never have enough precision. its quite silly.

Here is my timer class. It uses ctime.

// Timer.h

#pragma once

class Timer
{
	public:
		Timer();
		~Timer(){}

		void Tick();

		float getTimeSlice()const{return timeslice;}
		unsigned int getElapsedTime()const{return elapsed_time;}
		
		/*
			allows you to cap the frame rate.
			returns false if the number of ms passed is less than
			you would need at the given framerate.

			returns true if more than that amount of time has passed
		*/
		bool isTimeForUpdate(int framerate);
		
	private:
		unsigned int app_ticks;//total ticks so far in this app
		unsigned int elapsed_time;
		float timeslice;
};

// Timer.cpp

#include <iostream>
#include <ctime>

#include "Timer.h"

Timer::Timer()
{
	app_ticks = clock();
}

void Timer::Tick()
{
	int elapsed_ticks =  clock() - app_ticks;
	app_ticks = clock();
	elapsed_time = elapsed_ticks;
	timeslice = (1.f / 1000.f) * (float) elapsed_ticks;
}

bool Timer::isTimeForUpdate(int framerate)
{
	int actual_ticks = clock() - app_ticks;
	if (actual_ticks >= (1000.f / (float)framerate))
	{
		Tick();
		return true;
	}
	else
	{
		return false;
	}
}

The isTimeForUpdate feature makes pedantic individuals particularly angry for some reason.


#4761247 manager classes

Posted by speciesUnknown on 19 January 2011 - 08:09 AM

The Manager model always seems to me like the one to use if you don't know what else to do; it is very tempting to use it as a golden hammer, with everything being a manager. Effectively, its a brute force design pattern which lets you have any list of objects interacting with any other list of objects.


The point of the manager pattern is that the manager receives all the messages and arbitrates what happens, and if those messages are coming into the manager in the form of method calls, each manager will have different calls. The most abstract form of a manager is just an aggregation of objects, so putting a lot of work into a "manager model class" is pointless. All your base manager will have is addObject, removeObject, etc. You might be able to specialise it with templates e.g. <class KeyT, class ValueT> or add querying capabilities but this is all moot; not all mangers use these systems.

Among others, I've seen the following things called "FooManager" when they really have a more specialised task, resulting in an epic facepalm:

A table of resources with searching, caching, and a load / unload heuristic. (several of these being inside a ResourceManagerManager)
A factory for constructing items (with an aggregation of those items tacked on)
A sorted render list.
An octree container.
A scene graph.
An undo / redo history.
A controller in an MVC architecture.
An abstract "view "in an MVC architecture (ViewManager. its a view ffs. Just call it a view.
A wrapper for all 3 items in an MVC architecture (!?)

Please people... stop calling everything a Manager and think about the actual architecture of your application.


#4759158 How does my resource manager suck?

Posted by speciesUnknown on 14 January 2011 - 11:03 PM

Your first mistake is trying to manage memory manually, and arent obeying all the rules. As a result, horrible things are being done to your stuff.
Rely on RAII to manage your SDL_Surface's.

First off, store your SDL structs in a wrapper struct like this:

struct SurfaceHolder
{

    SurfaceHolder() : surface(null), valid(false) {}

    void load(const std::string& filename)
    {
        // your current code to load your texture
    }

    virtual ~SurfaceHolder() 
    {
        unload();
    }

    void unload()
    {
        if (valid) 
        {
            SDL_FreeSurface(this->surface);
            valid = false;
        }
    }

    SDL_Surface * surface;
    bool valid;
};
This will guarantee you creation and timely deletion of your SDL surface, providing you don't do anything stupid with your SDL surfaces.

Secondly, I note that you load_surface function returns an ID for the surface it represents. Thats perfectly sensible. However, storing things as old fashioned arrays means you don't have all the semantics you need; you need associativity (an array is only associative because your keys are integers) but you also need sparseness - right now you can't unload a single surface and have things remain valid. Your issue of references being invalidated is down to the fact that vectors move their memory around when they resize.


Try a map instead; you will be able to use a key type other than an integer to load your resources.
std::map<int, SurfaceHolder> surfaces;
You can then use map's functions such as find, remove, etc. to load, unload, and store your resources. For more powerful control over the system, consider a smart pointer such as boost.auto_ptr which will manage deletion for you but still give you pointer semantics:
std::map<int, boost::auto_ptr<SurfaceHolder> > surfaces;

There is also shared_ptr (which might be a better option as you can then pass around a shared_ptr<SurfaceHolder> ) and intrusive_ptr(which does a similar job and is worth looking into)

You might want to keep something similar to your current behaviour and use a deque, however; deque does not move its memory around (reallocate) when it is resized so you will be totally safe, but it does exhibit most of the behaviour you have now. Either way, because you are storing your SurfaceHolder by value rather than by pointer, there is no manual operation required to free up memory when it is no longer needed. Your problem of freeing a pointer will disappear.

As an aside, a couple of recommendations;
1) Avoid manual memory operations at all costs unless you are really trying to squeeze performance out of something and know what you are doing; use existing stuff, slow or otherwise, until you reach that point. 90% of your code is only executed 10% of the time.
2) Check out this popular link when you next come to choose a storage medium: Container Choice Flowchart
3) Before you say "but I need the best performance" I would advise you do do some profiling first and then optimise this some more later. To start out you need safe and reliable resource management, because it is the backbone of any game.


#4756076 What Does Everyone Think About The New Site Layout?

Posted by speciesUnknown on 09 January 2011 - 11:43 AM

I Don't like change *crosses arms and makes a puffing sound*

Actually I kid, I like the new layout; I've yet to take stock of the new features but this is long overdue!




PARTNERS