Jump to content

  • Log In with Google      Sign In   
  • Create Account

Somewhere in space



Some notes about my game's world

Posted by , 15 July 2013 - - - - - - · 707 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 - - - - - - · 975 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().





Search My Journal

July 2013 »

S M T W T F S
 123456
78910111213
14151617181920
21222324252627
28293031   

Recent Comments



PARTNERS