Jump to content

  • Log In with Google      Sign In   
  • Create Account

Somewhere in space

In defence of hit points

Posted by , 14 August 2013 - - - - - - · 2,404 views
combat, hit points, rpg
My game will be Ultima with laser guns.

Attached Image
(Actually, I think the original Ultima already had laser guns. So my game will be Ultima with...more laser guns.)

The first Ultima had a simple interface (having to use keyboard shortcuts for everything notwithstanding). You bump into a monster to attack it. I want to maintain the simplicity of the first Ultima in my own game when handling gun combat. There may be effects like range and cover, but the game itself will likely have you just clicking on monsters until they're dead. No menus. No separate combat mode. No "action points." Nothing as elaborate as Jagged Alliance or the original Fallout.

Guns are deadlier than the swords and axes you typically see in games. The sci-fi guns in my game world would be deadlier than that. I don't want to make my game intrinsically harder than other games though. This eventually leads me to thinking about the somewhat thorny issue of hit points.

Every so often people like to complain about how weird hit points are, or how their pet game system has this better model for combat and wounds. It's true that one can't survive getting shot or stabbed several times as most games seem to depict. Hit points are often interpreted as the physical health of a character. This is reinforced in real-time action games where you see a character getting shot or stabbed, only to lose some magical hit points.

Action games don't always have hit points. The vast majority of arcade games kill you as soon as you touch a bullet, spike, or ghost. In the Playstation fighting game Bushido Blade you defeated your opponent as soon as you struck their head or torso. Your ability to survive in those games depends on your ability to physically evade and block attacks. This is realistic for both both real life and in fiction. Batman has to do backflips and tricks with his batarangs to survive gunfire.

A turn-based game doesn't let you manually move your character out of harm's way. Sometimes they do, like the Mario RPGs, but in most turn-based games your character's ability to evade and block attacks is abstracted and simulated.

The only model for evading/blocking attacks in turn-based games I've ever seen is the random "to-hit" check. One or more stats are taken, one or more random numbers are cranked out, and these are taken together to decide that either the attack did something or the attack did nothing. There are a variety of fancy systems to describe what happens when an attack does something beyond the usual hit point mechanic. But when it comes to avoiding an attack, every system boils down to rolling some dice while crossing your fingers.

If successful attacks are realistically deadly, this kind of random check for evasion is gambling.

This is fine in a pen-and-paper RPG where the game master can let you role-play yourself out of a dire situation, or at least fudge some dice rolls. This is fine in a game that's focused on storytelling where random and arbitrary events are part of the experience. This is fine in a game like X-COM where all your fighting is done by semi-anonymous, semi-disposable hirelings. This is not fine in a game with irreplaceable characters, an emphasis on tactical combat, and a win state that you are expected to reach with good strategy and foresight. Reloading from saves is not a valid game action.

For all their descriptive faults, hit points are good gameplay wise since they don't allow such uncontrollable character deaths. Your characters can die if you send them against enemies too big for them, or if you don't pull them back from a losing battle, but you'll never have a character die because the dice had a mood swing.

Hit points were meant to be fully abstract. They weren't really "health points." Characters getting "hit" and losing hit points could mean they deflected the blow, or the blow only made a scratch. Only the attack that brings a character's hit points to zero could be described as the one where the character gets stabbed in the face and finally dies. I assume in pen-and-paper games the game master was supposed to make up a description for an attack.

This segues with the common practise of hit points increasing (or inflating, to put it negatively) as a character develops. The character is getting more skilled and is getting the experience to engage in bigger and bigger battles. It's not like character is developing iron skin or something like that.

Only Dungeons and Dragons fans ever believed in this description of hit points though. And even Dungeons and Dragons doesn't sell hit points as well as I think it should. Losing hit points arguably encompasses events like evading and blocking, yet you still have to roll dice to check if an attack depletes any hit points or not. Hit points are used in deciding what happens after your character falls off a cliff for some reason. Drinking potions does...something...that replenishes your character's hit points.

My ideas for my game's combat system have been revolving around making a "better" version of hit points, since the alternatives I've seen that truly get away from hit points are ultimately too random for the level of strategy I want to allow. My ideas can be summarized as:
  • Don't call the hit points hit points. Call them "stamina" and do things like represent them with yellow diamonds instead of red hearts. Get the semantics nailed down.
  • Don't allow potions and medkits that directly replenish your hit points to exist, or limit them such that they're a power-up rather than something your character chugs every five turns during a boss battle. Hit points only represent your fighting ability; they don't care about the bandages you need or don't need. Instead have hit points regenerate automatically. Some people complain about regenerating hit points in modern games but here it's justified.
  • Don't have to-hit or miss checks for attacks. Hit points already cover that, so all attacks automatically hit and do damage (whatever "hit" and "damage" means). Instead, your character's ability to dodge, block, whatever is represented by reducing the final damage an attack does, similar to how armour works in most games. This also means you'll never have to suffer through a never-ending string of attack misses.
  • Let terrain have a direct impact on the damage characters take. A character standing behind a crate takes less damage due to cover. A character standing on the edge of a cliff takes more damage due to having to expend the effort of not getting knocked over.
  • Have random critical attacks that represent a character truly getting hit by the attack, to add drama if nothing else. On top of the bonus hit point damage, the character receives a wound which directly penalizes the character's stats. These wounds are the things that potions and medkits heal. Armour could be the method of reducing the chance and severity of critical attacks, which can distinguish it from a character's evasion/block ability that's just used to reduce hit point loss.
  • Wide-area attacks like explosions are where my current hit point model starts to break down. With these attacks the character's escape and survival can only be rationalized if the character is seen to physically move across the game map away from the explosion. My best solution is to make characters do just that. When caught in an explosion a character is forced to move to the closest space outside the explosion's radius. The character has to expend hit points representing the effort of escape, more hit points expended the further the character has to move. If the character runs out of hit points before reaching the explosion's edge the character is fried. Or at least receives a wound.
  • Rather than have hit points that go down after an attack, have "stress points" that go up. Any attack requires a certain amount of stress in the target to be lethal. The target amount depends on the stats and equipment of the attacker and the defender. This may make it harder to tell how "alive" your character is since you have to compare your character's stress points against the combat potential of every enemy in sight, rather than simply observing how close to zero your character's hit points are. I think it's a neat twist nonetheless though since stress points wouldn't need a specific maximum value like hit points do.
I've been looking for alternatives to hit points. I'm not looking for something deadlier, but for something with more verisimilitude and at least the chance to be different. The alternatives I've seen, while having interesting models for wounding, still leave avoiding wounds to chance and thus end up too randomly deadly for my game. For that reason I've been driven to find ways to sell hit points to you better than other games have.


Some notes about my game's world

Posted by , 15 July 2013 - - - - - - · 746 views
worldbuilding
Here is a semi-random collection of notes about my game's background and setting. Some of these may change in the future.

The game will aim for some degree of verisimilitude, as in "hard science fiction," but will have a humorous tone. I'm going to avoid things like psychic powers, but flying toasters will count among your foes and you will heal your wounds by pouring HP sauce on them.

It is some unspecified future era. Mankind has established colonies throughout the solar system, in space stations and on other planets and moons. At least, the planets and moons that have anything worthwhile going for them.

Cybernetic, genetic, and nano engineering is commonplace. In addition to a wealth of other applications, this has let to human engineering that has branched mankind into four general races. Races as in kind you pick at the start of the game when creating your character.
  • Baselines; also known as standard humans. They're probably better fed and generally more fit than early 21st century humans though.
  • Androids; people who have replaced their bodies with mechanical bodies of metal, plastic, and diamond. There's no mind-uploading; the closest thing that exists is "crystallizing" a brain by replacing its flesh neuron by neuron with artificial matter until the brain becomes something that can be plugged in to a robot body. Some androids think they're the next step of human evolution and can be jerks about it.
  • Morphs; these people are biological, but they've modified their bodies into a variety of exotic forms. A morph can look like anything from monsters to cartoon characters. Some make fun of morphs for their tastes in physical forms. Morphs are also my game's answer to "rubber forehead aliens."
  • Sprites; these people live in deep space and have engineered their bodies explicitly for zero-gravity environments. They now look like classic arcade game sprites like space invaders and Pac-Man ghosts. Since most of my actual game will take place on a planet, I was thinking of some kind of anti-gravity for Sprites, though I haven't come up with a satisfactory way to explain or at least justify the anti-gravity yet.
Humanity on Earth has grown relatively conservative in the future, so the majority of baseline humans exist on Earth while the other branches of humanity live in the rest of the solar system. Earth itself has an overall "second world" status following a cold war between Earth and its colonies. The current "capital" of humanity is on Mars.

The economic decline of Earth has allowed various regions of it to become breeding grounds for sophisticated criminal syndicates that rival large companies and small countries. These syndicates would later expand to the rest of the solar system's underbelly, allowing space pirates to exist.

Several decades ago, before many of Earth's colonies were established, before the technology that led to mankind branching into its four forms existed, Earth was wracked by strife (I haven't decided if it was an actual world war or not). In this tense era of conflict a private organization built a colony starship and sent it to a nearby star. The people on this starship were never heard from again.

Today, it has been announced that faster-than-light travel has been invented (like the Sprite's anti-gravity, I haven't come up with any satisfactory science or pseudoscience to describe what this FTL tech is like). For its first application, an FTL starship has been built to travel to the star that lost colony starship was sent to, to discover the lost interstellar colony's fate.


GUIs - Wheel reinvention

Posted by , 04 July 2013 - - - - - - · 1,046 views
c++, gui, madness
In a fit of madness I came up with this:

widget.h and widget.cpp
#ifndef WIDGET_HPP
#define WIDGET_HPP

#include <vector>

#include <SFML/Graphics.hpp>

using std::vector;

class Widget
{
	public:
		enum Visibility
		{
			VISIBLE,
			HIDDEN,
			COLLAPSED
		};

		bool isModal;

		sf::Vector2i pos;

		Widget() : parentPtr(NULL), isModal(false), pos(0, 0),
		  visibility(VISIBLE) {}
		virtual ~Widget() {}

		bool addChild(Widget &w);
		bool removeChild(const Widget &w);

		int childrenCount() const;
		Widget * const getChildPtr(const int index);

		Widget * const getParentPtr();

		// Is w an ancestor of this widget?
		bool hasAncestor(const Widget &ancestor) const;
		// Is w a descendant of this widget?
		bool hasDescendant(const Widget &descendant) const;

		virtual int getWidth() const = 0;
		virtual int getHeight() const = 0;

		virtual bool setWidth(const int newWidth) = 0;
		virtual bool setHeight(const int newHeight) = 0;

		Visibility getVisibility() const;
		void setVisibility(const Visibility newVisibility);

		sf::Vector2i getScreenPos() const;

		bool containsLocalPos(const sf::Vector2i &local) const;
		bool containsScreenPos(const sf::Vector2i &screen) const;

		Widget *mouseDown(const sf::Vector2i &mLocal);
		virtual void mouseMove(const sf::Vector2i &mLocal,
		  const sf::Vector2i &delta) = 0;
		virtual void mouseUp(const sf::Vector2i &mLocal) = 0;

		virtual void keyDown(const sf::Event::KeyEvent keyEvent) = 0;
		virtual void keyUp(const sf::Event::KeyEvent keyEvent) = 0;
		virtual void textInput(const sf::Event::TextEvent textEvent)
		  = 0;

		virtual void gainFocus() = 0;
		virtual void loseFocus() = 0;

		void update();
		void draw() const;

	private:
		vector<Widget *> children;
		Widget *parentPtr;

		Visibility visibility;

		virtual void mouseDownEvent(const sf::Vector2i &mLocal) = 0;

		virtual void doUpdate() = 0;
		virtual void doDraw() const = 0;
};

typedef vector<Widget *>::iterator WidgetIt;
typedef vector<Widget *>::const_iterator ConstWidgetIt;

typedef vector<Widget *>::reverse_iterator WidgetRIt;

#endif
#include "widget.h"

#include <algorithm>

using std::find;

bool Widget::addChild(Widget &w)
{
	bool result = false;

	// A widget is not allowed to become its own child or grandchild
	if ((&w != this) && !hasAncestor(w))
	{
		if ((w.parentPtr != NULL) && (w.parentPtr == this))
		{
			w.parentPtr->removeChild(w);
		}

		children.push_back(&w);
		w.parentPtr = this;

		result = true;
	}

	return result;
}

bool Widget::removeChild(const Widget &w)
{
	bool result = false;

	if (w.parentPtr == this)
	{
		children.erase(find(children.begin(), children.end(), &w));
		result = true;
	}

	return result;
}

int Widget::childrenCount() const
{
	return children.size();
}

Widget * const Widget::getChildPtr(const int index)
{
	return children.at(index);
}

Widget * const Widget::getParentPtr()
{
	return parentPtr;
}

bool Widget::hasAncestor(const Widget &ancestor) const
{
	return (parentPtr != NULL) && ((parentPtr == &ancestor)
	  || (parentPtr->hasAncestor(ancestor)));
}

bool Widget::hasDescendant(const Widget &descendant) const
{
	bool result = false;

	for (ConstWidgetIt it = children.begin(); it != children.end();
	  ++it)
	{
		if ((*it == &descendant)
		  || ((*it)->hasDescendant(descendant)))
		{
			result = true;
			break;
		}
	}

	return result;
}

//--------------------------------------------------------------------

Widget::Visibility Widget::getVisibility() const
{
	return visibility;
}

void Widget::setVisibility(const Visibility newVisibility)
{
	visibility = newVisibility;
}

//--------------------------------------------------------------------

sf::Vector2i Widget::getScreenPos() const
{
	sf::Vector2i result(pos);

	if (parentPtr != NULL)
	{
		result += parentPtr->getScreenPos();
	}

	return pos;
}

bool Widget::containsLocalPos(const sf::Vector2i &local) const
{
	sf::IntRect rect(0, 0, getWidth(), getHeight());
	return rect.contains(local);
}

bool Widget::containsScreenPos(const sf::Vector2i &screen) const
{
	sf::IntRect rect(getScreenPos(),
	  sf::Vector2i(getWidth(), getHeight()));
	return rect.contains(screen);
}

//--------------------------------------------------------------------

Widget *Widget::mouseDown(const sf::Vector2i &mLocal)
{
	Widget *resultPtr = NULL;

	if ((visibility == VISIBLE) && containsLocalPos(mLocal))
	{
		for (WidgetIt it = children.begin(); it != children.end();
		  ++it)
		{
			resultPtr = (*it)->mouseDown(mLocal - (*it)->pos);
			if (resultPtr != NULL)
			{
				break;
			}
		}

		if (resultPtr == NULL)
		{
			resultPtr = this;
			mouseDownEvent(mLocal);
		}
	}

	return resultPtr;
}

//--------------------------------------------------------------------

void Widget::update()
{
	if (visibility == VISIBLE)
	{
		doUpdate();
		for (WidgetIt it = children.begin(); it != children.end();
		  ++it)
		{
			(*it)->update();
		}
	}
}

void Widget::draw() const
{
	if (visibility == VISIBLE)
	{
		// Push (pos.x, pos.y) translation
		...

		doDraw();

		for (ConstWidgetIt it = children.begin();
		  it != children.end(); ++it)
		{
			(*it)->draw();
		}

		// Pop translation
		...
	}
}
gui.h and gui.cpp
#ifndef GUI_HPP
#define GUI_HPP

#include <vector>

#include <SFML/Graphics.hpp>

using std::vector;

class Widget;

class GUI
{
	public:
		GUI() : focusPtr(NULL) {}
		virtual ~GUI() {}

		void clear();

		bool pushWidget(Widget &w);
		bool removeWidget(const Widget &w);

		void clearFocus();
		void setFocus(Widget &w);

		bool mouseDown(const int screenX, const int screenY);
		bool mouseMove(const int screenX, const int screenY,
		  const int dx, const int dy);
		bool mouseUp(const int screenX, const int screenY);

		bool keyDown(const sf::Event::KeyEvent keyEvent);
		bool keyUp(const sf::Event::KeyEvent keyEvent);
		bool textInput(const sf::Event::TextEvent textEvent);

		void update();
		void draw() const;

	private:
		vector<Widget *> widgetPtrStack;
		Widget *focusPtr;

		sf::Vector2i mouseToFocusPos(
		  const int screenX, const int screenY) const;
};

#endif
#include "gui.h"

#include <algorithm>

#include "widget.h"

using std::find;

void GUI::clear()
{
	clearFocus();
	widgetPtrStack.clear();
}

bool GUI::pushWidget(Widget &w)
{
	bool result = false;

	// Only allow root widgets
	if (w.getParentPtr() == NULL)
	{
		removeWidget(w);
		widgetPtrStack.push_back(&w);

		if (w.isModal)
		{
			clearFocus();
		}

		result = true;
	}

	return result;
}

bool GUI::removeWidget(const Widget &w)
{
	bool result = false;

	WidgetIt it = find(widgetPtrStack.begin(), widgetPtrStack.end(),
	  &w);
	if (it != widgetPtrStack.end())
	{
		if (*it == focusPtr)
		{
			clearFocus();
		}

		widgetPtrStack.erase(it);
		result = true;
	}

	return result;
}

void GUI::clearFocus()
{
	if (focusPtr != NULL)
	{
		focusPtr->loseFocus();
	}
	focusPtr = NULL;
}

void GUI::setFocus(Widget &w)
{
	if (focusPtr != &w)
	{
		clearFocus();
		focusPtr = &w;
		focusPtr->gainFocus();
	}
}

//--------------------------------------------------------------------

bool GUI::mouseDown(const int screenX, const int screenY)
{
	bool result = false;

	for (WidgetRIt it = widgetPtrStack.rbegin();
	  it != widgetPtrStack.rend(); ++it)
	{
		sf::Vector2i mLocal = sf::Vector2i(screenX, screenY)
		  - (*it)->pos;
		Widget *newFocus = (*it)->mouseDown(mLocal);

		if ((newFocus == NULL) && (*it)->isModal)
		{
			break;
		}
		else if (newFocus != NULL)
		{
			setFocus(*newFocus);
			result = true;
			break;
		}
	}
	if (!result)
	{
		clearFocus();
	}

	return result;
}

bool GUI::mouseMove(const int screenX, const int screenY,
  const int dx, const int dy)
{
	bool result = false;
	if (focusPtr != NULL)
	{
		focusPtr->mouseMove(mouseToFocusPos(screenX, screenY),
		  sf::Vector2i(dx, dy));
		result = true;
	}
	return result;
}

bool GUI::mouseUp(const int screenX, const int screenY)
{
	bool result = false;
	if (focusPtr != NULL)
	{
		focusPtr->mouseUp( mouseToFocusPos(screenX, screenY) );
		result = true;
	}
	return result;
}

sf::Vector2i GUI::mouseToFocusPos(
  const int screenX, const int screenY) const
{
	return sf::Vector2i(screenX, screenY) - focusPtr->getScreenPos();
}

//--------------------------------------------------------------------

bool GUI::keyDown(const sf::Event::KeyEvent keyEvent)
{
	bool result = false;
	if (focusPtr != NULL)
	{
		focusPtr->keyDown(keyEvent);
		result = true;
	}
	return result;
}

bool GUI::keyUp(const sf::Event::KeyEvent keyEvent)
{
	bool result = false;
	if (focusPtr != NULL)
	{
		focusPtr->keyUp(keyEvent);
		result = true;
	}
	return result;
}

bool GUI::textInput(const sf::Event::TextEvent textEvent)
{
	bool result = false;
	if (focusPtr != NULL)
	{
		focusPtr->textInput(textEvent);
		result = true;
	}
	return result;
}

//--------------------------------------------------------------------

void GUI::update()
{
	for (WidgetIt it = widgetPtrStack.begin();
	  it != widgetPtrStack.end(); ++it)
	{
		(*it)->update();
	}
}

void GUI::draw() const
{
	for (ConstWidgetIt it = widgetPtrStack.begin();
	  it != widgetPtrStack.end(); ++it)
	{
		(*it)->draw();
	}
}
This is my take on an ostensibly light-yet-flexible core of a GUI system.

Everything is a Widget. Widgets can contain other Widgets, making trees of Widgets.

Widget trees are handled by a GUI manager. A GUI manager takes a root Widget and feeds it input events, updates it, and renders it. A GUI manager actually handles a stack of root Widgets to represent overlapping UIs to represent things like modal forms and pop-up menus.

The GUI manager also keeps track of the current focus, needed for keyboard events. A Widget, wherever it is in its tree, gains focus when clicked on. Focus is lost when an empty space is clicked.

I need to finalize how I'm going to handle Widget sizes. You'd be allowed to set the dimensions of most Widgets, but some Widgets like icons may have fixed sizes. I'd also want default sizing behaviour for certain types of Widgets, like containers that grow and shrink to fit their child Widgets, that would end when you set a specific size on the Widget.
Widgets also need to notify their parent when their dimensions, and their visibility, change. I'll likely do this through a callback like childResized().


Most GUI libraries are terrible

Posted by , 28 June 2013 - - - - - - · 30,785 views
gui, cegui, sfgui, berkelium and 2 more...
The title is hyperbole. Mostly.

I need a GUI library. RPGs require a robust user interface. I've attempted to write my own GUI systems in the past and this has killed many a project. There was always something I didn't anticipate and couldn't work into my existing design. General application frameworks like Qt typically aren't suited for games due to performance needs and the custom graphics games usually demand (and in Qt's case I'm unsure about installing a whole development framework that rivals .NET and the Java SDK just for a GUI).

My own project has specific constraints that limit what libraries I can use.
  • My game is a hobby project that will be freeware. I'm not getting paid for this game so I can hardly justify paying money for any library or toolkit.
  • My game will be open source. Sine I'm not making money off this game, I might as well not hog the source code. I'm eventually going to put my game up on my Bitbucket account. I actually have a completed game there already, developed with Löve. For faintly obvious reasons, I'm going to have a bias for open source libraries
    • I have to worry about the specific license of any library I use. I normally use the Apache 2.0 License for my own projects and I lean towards BSD/MIT/zlib(/Apache) style licenses for third party libraries. Lots to keep track of.
  • I'm developing on a Mac and intend to release my game for Mac and Windows; the Windows port mainly a courtesy of my ability to dual boot. Any library I use ought to be compilable on Mac computers, which usually means C/C++.
Beyond that, any library I use would hopefully be well established and actively maintained. Something that's not only available on someone's university web page that hasn't been updated since 1999.

Web searching has left me with a small pool of candidate libraries: CEGUI, SFGUI, Berkelium, GWEN, and libRocket. Each one falls short in at least one aspect for my project. They might not fall short for your project, but I'm still left wanting.

CEGUI

Arguably the final word on open source, C++ based, game oriented GUIs. Beyond handling widgets and input logic, CEGUI also does its own rendering (with a choice of built-in renderers) and handles all of its resource loading and management. For a library meant to be used in other multimedia applications, I don't consider this a plus.

I would prefer to have an interface I could write against so that CEGUI goes through my game's rendering and resource management system instead of working in its own universe. Granted, I'm using SFML, which is based on OpenGL, and CEGUI has an OpenGL renderer available, but using CEGUI will still introduce inconsistency.

I've written a sprite system with SFML that makes heavy use of batching and texture atlases, with sprites associated with an ID. To draw a sprite I just need an ID and a transform. CEGUI would have to exist independently of of that. I would have to draw my GUI in a separate step, and I'm not sure how I'd put sprites used in my game in a CEGUI widget short of loading the sprite's image separately into CEGUI.

I've heard rumours that it's possible to write custom renderers for CEGUI, but I haven't seen anything that tells you how. Support for the Mac is also not the best apparently.

SFGUI

SFGUI also controls its own rendering like CEGUI. It's meant to work with SFML though, so in my game it might not be such a mismatch.

SFGUI's default GUI theme is only coloured borders and rectangles though, and I haven't seen any documentation on how to create a custom theme aside from the source code and Doxygen class documents. SFGUI also requires GLEW as an extra dependency and I've been unsuccessful in building SFGUI on my machine anyway. SFGUI is overall a bit too new for my tastes.

Berkelium

There's an interesting school of thought in GUI development about using web technologies to create GUIs. The layout and look of your interface is defined in a markup document while your application just handles the logic. WPF for example uses XAML and C# in much the same way web sites use HTML and JavaScript.

There are pair of WebKit/Chromium frameworks that lets you display web pages in your program. There is the original and commercial Awesomium and its open source offshoot Berkelium. Both of them promise you the ability to create your application's UI with web technologies. If you can create a web page, you can create a UI for a program with Berkelium in it.

Berkelium and Awesomium don't use HTML and CSS like WPF uses XAML though. They stuff a whole self-contained web browser into your program. By self-contained, I mean you need to use JavaScript to make your UI dynamic. I have not seen a way to control the DOM through Berkelium's C++ API. Considering that my game engine will be wrapped in Squirrel, I'd be forced to use a total of three programming languages for my game.

What I'd really want is a pure HTML/CSS renderer. Such a library doesn't seem to exist, except for libRocket (coming later) and the commercial Windows-only library HTMLayout.

GWEN

GWEN stands for GUI Without Extravagant Nonsense. There's no HTML. No CSS. No JavaScript. No markup or config files. It doesn't handle rendering. It doesn't handle resource loading or resource management. It's just GUI logic. Anything else you have to provide. In other words, it's designed to not cramp your style.

It also only has a GitHub page to its name. It used to have an actual web page, but that's now gone. And with the original web site gone, the only real documentation GWEN ever had is now also gone. This doesn't inspire confidence about GWEN's status.

I'm also unsure about GWEN's skinning system. You give it a texture image containing all the graphics GWEN needs for a skin, but I'm unsure how I'm supposed to define size parameters like margins and paddings.

libRocket

Due to the shortcomings of the libraries described above, libRocket ended up being the only library I've actually tried.

Like Berkelium, libRocket uses HTML and CSS to define interfaces. Unlike Berkelium, libRocket doesn't hide the DOM from you, so you don't have to stick JavaScript in the middle (though you can optionally use Python instead). libRocket fully expects you to write a custom renderer for it, and there's actual documentation on how to do this. libRocket still assumes that the images it's being given are files, but since it lets you create a custom renderer I've been able to take control of this so that it uses sprite IDs instead like the rest of my renderer.

I'm afraid the project is dead though. libRocket's last commit on its GitHub page is only a couple of months old, but the front page of its main site hasn't been updated in two years and the forums are dead.

There are a few other quirks with libRocket too. It doesn't use actual HTML and CSS, just its own subset (RML and RCSS). I also haven't wrapped my head around handling RML events application-side yet.

***


I wrote this after scouring the Internet, reading thread after thread about suggested GUI libraries for games. With the current selection today, picking a GUI library is not so much about deciding which one is the best as it's about deciding what I'm willing to put up with.


The start

Posted by , 24 June 2013 - - - - - - · 859 views
rpg, ultima, science fiction, c++ and 4 more...
Here I will attempt to chronicle the efforts of creating a science fiction Ultima-inspired RPG.

I'm a hobbyist game developer, and this game will be freeware and open source. I suppose if the code turns out good enough I may follow up with a commercial game, but that's another story.

Decades ago, colony starships headed off from Earth. Half of these lost contact with Earth. Today, mankind has invented faster-than-light space travel. A task force of starships are being sent to recontact these lost colonies, or at least discover their fate.

You are an agent manning one of these starships, and you have reached the star system one of the lost colony ships was heading for. You are sent out in a shuttle to survey one of the planets.

You are shot down from orbit. It turns out that space pirates have surreptitiously acquired faster-than-light technology and have taken this world, conquering the lost colony. Now you have to deal with the space pirates, the untrusting colonists, and the hostile native wildlife. Adventure ensues.

So far I have this:
Attached Image
I figure this art style will be a fair trade-off between attractiveness, required skill, and required effort. If it's going to be programmer art, hopefully it'll be good programmer art.

Gameplay-wise this is a top-down, tile-based, turn-based RPG in the style of the first five Ultimas, only with a science fiction theme. And hex tiles. You have to talk to people, collect items, solve puzzles, and shoot bad guys. All the while you have to figure out how to get off this world, reach your starship and your crew, and maybe do something about those space pirates.

Tech-wise the game going to be written in Squirrel with a C++ core. Squirrel will be used for the main game logic, and C++ will manage the infrastructure of the graphics, resources, and the application itself. The graphics (and audio, when I get to it) is powered by SFML, I'm using yaml-cpp for some of my config files, and RandomLib is providing my game with, well, randomness.

There's still some stuff I need to bake into my C++ core before writing the game proper in Squirrel. For one thing, I'll probably bake in a game state system so that I don't have to worry about it in the Squirrel side.

I also need some kind of GUI solution, which is filling me with trepidation. This I will likely detail in another post, but my project has certain constraints and conditions that limit what kind of libraries I can use, this project being freeware and open source being one of them. I'm also developing on a Mac, so there's that too. Meanwhile, all the possible GUI libraries I've seen seem lacking in their own special way, and building my own GUI system would lead to madness.

Wish me luck.





Search My Journal

December 2016 »

S M T W T F S
    123
4567 8 910
11121314151617
18192021222324
25262728293031

Recent Comments