Oh hay! New DevBlog

I’ve create a new Dev Blog over there -> http://dss.stephanierct.com/DevBlog/ :)

Moving to Indie DB for DSS

Sorry for the lack of update. I’ve been neglecting my blog in favor of my Indie DB page for any Deep Space Settlement news. 

So to catch up a bit here are my latest videos: 

https://www.youtube.com/watch?v=sTellsCo0hY

https://www.youtube.com/watch?v=bjQiIz2ZwPE

https://www.youtube.com/watch?v=f90k028l_0A

https://www.youtube.com/watch?v=ZwKp4zNywyM

https://www.youtube.com/watch?v=IyCnd8Kxk2c

Hope you like! :)

Colony Station

The first thing to do when starting a new game in DSS is to build your colony station. This station is central to your local empire, as it will provide the work force to build and staff your other stations and ships. You will be able to train workers and pilots out of the available population. This population grows over time if you provide it with the necessary commodities such as entertainment and health care. The higher the moral and health are, the faster it grows.

The station itself has 6 customizable district sockets. Each sockets can host a district, that has a direct effect on the station and population:

Residential District
Increases the station population limit. Comes in form of a pyramid and provides quality living space.
High Density Residential District
Increases the station population limit even more. Influenced by totalitarian architecture, provides crammed living space, but comes at the price of a decrease in morale.
Park District
Provides a small moral boost. Inspired by the classic concept of a greenhouse in space, encapsulated by an atmospheric bubble. There’s a waterfall, some forest and a beach.

Several other districts are still in development, for instance: hospital will increase population health, academy will train higher tier professions, etc.

Also, as you progress in the game and unlock new technologies, you will be able to expand the colony station considerably to add new district sockets. Here’s a preview of how the station will grow:

So by the end of the game you should get a huge station that looks like a floating city in space. :D

Creative Process:

The initial brief for the artist was as follows:

Composed of a central hull with 6 districts and 6 expansions with 6 districts each.
The central hull is ~800 meters in diameter and provides living space for colonist, basic education system and commodities to sustain a small population. There is also a corvette shipyard for tiny ships of no more than 20 meters.

The city of Atlantis(from stargate atlantis) provided a rough starting point for how to lay out the colony station. Core structures in the center and additional structures in the periphery.
Additionally, a hexagonal shape was deemed as useful for the districts, because it allows for a nice, compact arrangement, without the static feel a square would have.

So, the colonystation with its 6 expansions is essentially a city in space, or rather a blueprint for a city in space, because the player can build districts on it.
One of the first things to do, was to figure out how to arrange the expansions and districts accordingly. Although we are in 3D space, a planar arrangement was preferred to provide best visibility and allow to see things at a glance.


The third variant was chosen, as it is the most compact and expansions “grow” most naturally.

Afterwards the central hull had to be worked out. The idea here was to have elements clearly separated by function. There should be an area for habitation, for education(training pilots, etc), a small shipyard, some part focused on engineering(life support systems, energy source etc) and finally 6 areas where a districts can be build upon.
Approved was the idea of a central ring fused with 6 hexagonal platforms at the outside and three vertical structures in the middle.
colonystation_concept

The ring and the platforms are used for habitation. The smallest tower is the shipyard. Opposite the bay opening is a medium sized tower, with elements inspired by Air Traffic Control towers. This one is also housing the education facilities. The tall, narrow structure is the engineering tower.

Home | Forum | IndieBd | Twitter

Battle mechanics and strategy

It’s been a while since I gave any news on DSS. So I thought I could write down a bit about some design ideas I am currently implementing.

As you may know, ships are designed by the player down to what kind of weaponry, defense, engines, reactors, etc are used. Players will have to choose components in regard to the role the ship will play in their strategies. It might be designed to be a fast scout ship, a heavy armored concrete block that can withstand heavy fire, a ship specialized to kill a specific enemy unit type, a support ship in a fleet, and the list goes on. Among those choices will be gun or laser and armor or shield. Each has their own distinctive strengths and weaknesses.

Weaponry: Guns and Lasers
Guns are rapid fire mass-based weapons. They are cheap, have infinite ammo but miss their targets quite often. Primary defense against it is maneuverability i.e. steering speed. The more maneuverable your ships are, the easier they can dodge enemy gunfire. Bullets travel long distances in one direction with limited speed, so that give plenty of time for ships to outmaneuver them. If you are designing a ship with low steering speed, make sure it is heavily plated with good armor because your shield will take a serious beating out of gunfire.

Lasers are beams that instantaneously hit their targets. They never miss. They however need power to shoot. Fitting your ship with a decent reactor core is crucial to sustain a laser fire. Primary defense against lasers are shields, your armor will melt fast under laser fire, you wouldn’t want that to happen.

Defense: Armor and Shield
Armor is basically the ship’s HP. When it hits 0, your ship explodes. Plain and simple.
Shields however are more complicated. They have damage absorption, damage reduction and regenerate over time.
Damage absorption is a fix quantity removed from every hit. Damage reduction is a percentage of the damage removed after the absorption. The damage left after absorption and reduction is removed from the shield’s HP. When it hits 0, the armor is exposed to enemy fire.

Actual Damage = (Damage – Absorption) * (1-Reduction)

So a high damage absorption means you will be best protected against swarm of small enemy ship fire. A high damage reduction on the other hand will be more effective against heavy fire power.

Pew Pew

So that makes the foundations of the DSS combat system. There are other types of weapons like missiles that could have a wide variety of effects but those will be implemented later.

I’ll keep you posted!

Still Alive

It’s been a long time since my last post so I’d figured I’d make a new video for your eyes to enjoy. A lot of new features are in, of which there is guns and corvette class ship dogfight behavior.
D.S.S. will feature epic space battles with tons of ships and lots of pew pew. So this is where i am in the development of such battles.

Pew pew pew! :D

D.S.S. Fleet System

What I often find lacking in most strategy game is the presence of any sort of fleet management system. What I mean by that is a mechanism that allows the player to setup the unit’s positions within the fleet when they are in formation. Usually you would put ships with more defense up front and ships with a wider weapon range back. Also, if you have ships that buff/debuff other ships within some range, you would certainly want them to hold a specific position in the fleet.

I find it to play a very important role strategy-wise in my game. So I spent a lot of effort in making a fleet editor that would give the player full control while (hopefully) being easy to use.

Placing ships in three dimensions can be challenging but I think I found an elegant way to solve this. The player puts ships on a X-Y grid which he can move up and down the Z axis by ctrl+left click and dragging it. And there is a green cursor that shows how high the grid is from the origin.

So that’s it, hope you enjoyed my first video of D.S.S. :D

Multi-threading my way

In D.S.S. I have to handle tons and tons of ships and projectiles in many star-systems. Consequently, if I want a decent framerate I’ll have to multi-process all this to take advantage of new multi-core CPUs.
So without further ado, here is how I did it. It’s actually a pretty standard way to do it. It’s just the simplest way I could think to implement it. I’ll be using common primitive like mutex, event and thread so I won’t go into details for these classes. I’m using FastDelegate library as well cause I just like it a lot.
The model is basically: queue a bunch of tasks (or jobs) and process them with several threads. The magic happens in 3 classes: JobQueue, MPWorker and MultiProcess.

JobQueue:
This one synchronizes job addition and retrieving. It really just acts as a synchronization primitive.

MPWorker:
this guy process job from the JobQueue. There are usually several of them spawned at initialization time. They literally fight each other to get and execute jobs. They are pretty good workers indeed.

MultiProcess just ties everything together.

So here goes a wall of code:
JobQueue:

class JobQueue{
public:
    JobQueue()
    : muiNbWorkingJob(0)
    , muiMaxSimultaneous(0){}
    void addJob(const fastdelegate::FastDelegate0<>& a){
        Mutex::Lock lock(mJobMutex);
        mAllDone.reset();
        mJobs.push_back(a);
    }
    fastdelegate::FastDelegate0<> retrieveNextJob(){
        Mutex::Lock lock(mJobMutex);
        if(mJobs.size()>0){
            fastdelegate::FastDelegate0<> job = mJobs.front();
            mJobs.pop_front();
            _InterlockedIncrement(&muiNbWorkingJob);
            updateMaxSimultanious();
            return job;
        } else{
            return nullptr;
        }
    }
    // called when a job is done
    void markJobDone(fastdelegate::FastDelegate0<>& a){
        Mutex::Lock lock(mJobMutex);
        // _InterlockedDecrement is used to force updating local variable 
        // with up-to-date variable changed by other thread
        // a volatile pointer would probably work as well.
        uint32 uiNbWorking = _InterlockedDecrement(&muiNbWorkingJob); 
        if(uiNbWorking == 0 && mJobs.size()==0 ){
            mAllDone.raise();
        }
    }
    // waits until all job are done
    void waitForAllDone(){
        mAllDone.wait();
    }
    uint32 getMaxSimultanious()const {return muiMaxSimultaneous;}
    void resetMaxSimultanious(){muiMaxSimultaneous=0;}
private:
    // prevent copying this class
    JobQueue(const JobQueue&);
    JobQueue& operator=(const JobQueue&);
    void updateMaxSimultanious(){
        if(muiNbWorkingJob>muiMaxSimultaneous) muiMaxSimultaneous=muiNbWorkingJob;
    }
    std::list< fastdelegate::FastDelegate0<> > mJobs;
    Mutex mJobMutex;
    long muiNbWorkingJob; // number of job currently executing at the moment
    Event mAllDone; // Event raised when all jobs have been processed
    uint32 muiMaxSimultaneous; // max number of simultaneous worker working at the same time. use for statistics
};

MPWorker

class MPWorker{
public:
    MPWorker(uint32 auiId, JobQueue& aJq)
        :muiId(auiId)
        ,mJobQueue(aJq) {
        mpThread = new Thread(fastdelegate::MakeDelegate(this,& MPWorker::workerFunc));
        mpThread->start();
    }
    ~MPWorker(){
        delete mpThread;
    }
    void workerFunc(){
        while(1){
            fastdelegate::FastDelegate0<> job = mJobQueue.retrieveNextJob();
            if(job){
                job();
                mJobQueue.markJobDone(job);
            }
        }
    }
    uint32 muiId; // don't really need this, it is just for debug purpose
    Thread * mpThread;
    JobQueue& mJobQueue; // the queue from which to get jobs
private:
    MPWorker(const MPWorker& a);
    MPWorker& operator=(const MPWorker& a);
};

MultiProcess

class MultiProcess{
public:
    MultiProcess()
        :mbWorkInSingleProcess(true){}
    // initialize system with number of desired workers
    void init(uint32 auiNbWroker){
        if(auiNbWroker==0){
            mbWorkInSingleProcess=true;
        } else {
            mbWorkInSingleProcess=false;
            for(uint32 i = 0; i < auiNbWroker; ++i){
                mWorkers.push_back( new MPWorker(i, mJobQueue));
            }
        }
    }
    ~MultiProcess(){
        for(uint32 i = 0; i < mWorkers.size(); ++i){
            delete mWorkers[i];
        }
    }
    void addJob(const fastdelegate::FastDelegate0<>& aJob){
        if(mbWorkInSingleProcess){
            aJob();
        } else {
            mJobQueue.addJob(aJob);
        }
    }

    // called when the user want all jobs to be processed
    void flush(){
        fastdelegate::FastDelegate0<> job = mJobQueue.retrieveNextJob();
        while(job){
            job();
            mJobQueue.markJobDone(job);
            job = mJobQueue.retrieveNextJob();
        }
        if(!mbWorkInSingleProcess)
            mJobQueue.waitForAllDone();
    }
    // some stats
    uint32 getMaxSimultaniousWorker()const {return mJobQueue.getMaxSimultanious();}
    void resetMaxSimultaniousWorker(){mJobQueue.resetMaxSimultanious();}
private:
    JobQueue mJobQueue;
    std::vector< MPWorker* > mWorkers;
    bool mbWorkInSingleProcess; // if work in single process, job are executed when added. otherwise they are put in the job queue.
    //prevent copying this class
    MultiProcess(const MultiProcess&a);
    MultiProcess& operator=(const MultiProcess&a);
};

Now to use it, do something like:

class MPUser{
public:
    void expensiveJob(){
        float fValue=0;
        for(uint32 i = 0; i < 50000; ++i){
            fValue+=rand()/(float) RAND_MAX;
        }
        printf("", fValue);
    }
    void use(){
        MultiProcess mp;
        mp.init(3);
        for(uint32 i = 0; i < 100; ++i){
            mp.addJob(fastdelegate::MakeDelegate(this, &MPUser::expensiveJob));
        }
        mp.flush();
    }
};

If you don’t know how much worker you should spawn, I suggest using the CPU number of processor – 1

    SYSTEM_INFO sysinfo;
    GetSystemInfo( &sysinfo );
    uint32 nbWorker = sysinfo.dwNumberOfProcessors-1;

Be aware that if your jobs are too small, the overhead of adding and getting job will be quite high. For instance, in D.S.S., I update whole star-systems in a job. Updating each ships with its own jobs would be terrible. Also, as ships usually interact only with other ships in the same star-system, I don’t have a lot of synchronization to handle.

Here is the full code with VS 2010 solution.

Follow

Get every new post delivered to your Inbox.