Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Re:creation - a top down action adventure about undeads [hiatus]  (Read 501494 times)

0 Members and 5 Guests are viewing this topic.

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email

Site: https://eliasdaler.github.io/re-creation
Developers: Elias Daler (programming, art, game and level design, story, etc.), Torchkas (music and sound effects)
Dev logs (old): https://eliasdaler.wordpress.com/tag/devlog/
Dev logs (new): https://eliasdaler.github.io/tags/#Dev+log
Progress screenshot album: http://imgur.com/a/luoFe
Twitter: @eliasdaler
Platforms: PC, Mac, Linux
Release date: When it's done



The coolest screenshot yet (January 2016):


Hello, my name is Elias Daler and this will be a dev log of my game!
I'm a solo hobby developer and work on the game in my free time so the progress won't be very fast I hope I'll post some interesting stuff from time to time! You can read previous dev logs here.

The development of this game started in October 2013.
I'm writing the game in C++ and use SFML. I also use Lua for scripting. I'll try to explain how my game works in next posts. I'll write about how I use scripting, how my entity/component/system works and lots of more programming stuff!

Story
The main hero is an undead knight who was betrayed by his partner, Necromancer, during a fight with a giant demon. When the hero raises from the dead, he realizes that lots of time has passed since his death. The Great War between humans and undeads is being fought for several centuries. Necromancer is still alive. He actually became a Lich. He has lots of power and uses undeads as a cheap working force. The hero explores society of undeads and finds out that they don’t actually want to kill humans. They just don’t want people to use them for training and steal their treasure! The hero decides to stop the war and prove that undeads are not that evil as it seems.


Undead City becomes hero's new home.

Gameplay
The gameplay is very similar to top-down 2D Zelda games with the exception of the main mechanic of the game, called recreation.
At any point of the game, you can become a ghost and travel through objects easily.
You can also control enemies you killed with it to get their abilities and solve various puzzles. Here's how it works:



You can't carry any weapons other than a hammer in the game, so you need to control enemies with bows to be able to use arrows, enemies with shields, to be able to block attacks etc. If you're killed when you're controlling someone else, your ghost will automatically return to your body and the person which you were in will respawn shortly after (because you can't solve some puzzles without other bodies).

Here's are some puzzles which you can solve with recreation mechanic:





Other gifs / screenshots:


NPC's are interesting...


Hero reacting to items he gets from chests


Boss fight

As this is the first post, I'll edit it from time to time to add the latest and coolest screenshots and gifs.
« Last Edit: June 09, 2019, 10:44:18 am by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #1 on: May 02, 2015, 05:17:11 pm »
This is very outdated and doesn't reflect the state of the project well. I'll write about current architecture some day! (Posted on 21-02-17)

Some programming stuff.

I use C++11 with SFML and Lua for scripting. The most important aspect of the engine is entity/component/system model. Here's my implementation of it.
Entities are different objects in the game: characters, houses, items, etc.
Each entity has unique id (which is used to identify them) and a number of components.
So, characters have: GraphicsComponent, MovementComponent, CollisionComponent, HealthComponent, etc.
Static objects don't need all of that so they only have GraphicsComponent and CollisionComponent.

So, entities are made from "blocks". Those blocks can have unique behaviour by scripting. But I'll talk more about that later.

Basically, it looks like this in code:

class Entity {
public:
    ... // some stuff
private:
    int uid;
    std::vector<std::unique_ptr<Component>> components;
    ... // some other stuff
};

Component is simply a collection of data. For example, GraphicsComponent holds sprite and other stuff related to graphics, MovementComponent has velocity, etc.-etc.

Systems operate on components. Basically most of the game logics is there.
For example, MovementSystem iterates over MovementComponent's of active objects and adds  to a current position for each entity. Most systems operate on one type of component and it doesn't matter to them what entity any component belongs to. This makes adding new types of entities easy as I don't have to change logics very often.

Entity definitions are stored in Lua scripts. Here's an example of a chest entity: http://pastebin.com/P3mAD8NN
As you can see, every component parameter is here but I can also define functions in Lua script. This let's me specify object behaviour so it's not hard coded in C++! This is very useful as I don't have to recompile the game very often.
Lots of Lua function have bindings to functions in C++, so I can use this function in a script:
setAnimation(someEntity, "animationName")
which will call this function in C++
void setAnimation(ind entityId, const std::string& animationName) {
    auto e = engine_system.em->getEntity(entityId);
    ... // code to set animation
}

Notice, that I don't pass around pointers or entity references but instead pass ints which is faster.
Getting entity from id is also fast, as each entitiy is stoped in a hash map and can be quickly accessed by unique id.

Once the entity templated is loaded in C++, every entity of this "class" is created with the template which is a lot faster than reading properties from scripts over and over.

There's some basic support for "inheritance" so if some entities have lots in common, they can use other entities properties, overwrite some properties and add new components.
Here's an example of that a chest that uses different sprite:  http://pastebin.com/6pQKJz5P
As you can see, there's no need to copy-paste everything, I can just change some of the parameters, the rest will be copied from base entity.


Chest vs super_chest. The only thing different is the graphics and size.

(You can read more about inheritance and scripting here)

My game also has in-game level editor.

Bigger gif: http://i.imgur.com/8HtWIYU.webm
It has lots of features: tile map editing, multiple object selection and moving, object creation, undo, etc.

And that's basically it. If you have some questions, feel free to ask!
(I'll write about messaging between systems, events and decoupling soon!)
« Last Edit: February 20, 2017, 11:03:46 pm by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Raincode

  • Full Member
  • ***
  • Posts: 118
    • View Profile
Re:creation - a top down action rpg about undeads
« Reply #2 on: May 02, 2015, 06:13:00 pm »
This looks pretty awesome! I could imagine it was a lot of work. When did you start it? Do you have some screenshots from earlier development stages?

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #3 on: May 02, 2015, 06:39:13 pm »
This looks pretty awesome! I could imagine it was a lot of work. When did you start it? Do you have some screenshots from earlier development stages?

Thanks a lot! I've started it in October 2013 (should probably add this to the first post, ha-ha).
Here is a progress album of my game. (I'll add it to the first post too)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Cirrus Minor

  • Full Member
  • ***
  • Posts: 121
    • View Profile
Re:creation - a top down action rpg about undeads
« Reply #4 on: May 02, 2015, 07:11:59 pm »
It looks really nice and fun!
Are you making the 2D-art?

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #5 on: May 02, 2015, 08:47:04 pm »
It looks really nice and fun!
Are you making the 2D-art?

Thanks! Yes, I do. I would love to have an artist working with me, but I don't have money or artistic friends, so the only thing left to do is to do my own art. :D
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re:creation - a top down action rpg about undeads
« Reply #6 on: May 02, 2015, 11:09:33 pm »
The game looks awesome but your post also is!

I'm very interested in reading more about systems and how they communicate with each other. I'm also interested in the Lua binding (what did you use, what did you bind).

What do you think about getting rid of the Entity class and just store arrays of components indexed by the entity ID ? It's something I read a lot about.

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #7 on: May 02, 2015, 11:42:40 pm »
The game looks awesome but your post also is!

I'm very interested in reading more about systems and how they communicate with each other. I'm also interested in the Lua binding (what did you use, what did you bind).
Thanks!

I use LuaBridge for binding. It's a fantastic and easy to use library and I've also written two articles about it on my blog. :)
I'm binding any function which needs to be called from the scripts. For example, here's how setVelocityX function looks in C++:

void setVelocityX(int entityId, float vx) {
    auto e = engine_system.em->getEntity(entityId);
    auto mc = e->get<MovementComponent>();
    if(mc) {
        mc->setVX(vx);
    } else {
        engine_system.log->write("Entity named" + e->getName() + " doesn't have MovementComponent!", LogManager::ERR);
    }
}

Then I can use LuaBridge and just write
getGlobalNamespace(L).addFunction("setVX", setVelocityX)

And then call it in scripts, for example in init() function (stored in entity template table) which is called when the entity is created:

init = function(this)
    setVX(this, 0.05)
end

So, when I call any Lua function, I pass entity id as a parameter which is later used to get entity in C++ after Lua function calls some C++ functions.

What do you think about getting rid of the Entity class and just store arrays of components indexed by the entity ID ? It's something I read a lot about.

I'm thinking about it and this can be a lot more efficient than what I use now. (Faster iteration, less cache misses, object pools...)
And I'll possibly implement it this way at some point in future and I won't have to change lots of code. (There's no need for it now though, as I don't see any perfomance related issues with the stuff I have now).
The only thing which I can't figure out is how to actually create arrays for each component and then easily get it.
For example, suppose I want to be able to get some component this way:
auto mc = get<MovementComponent>(entityId);
So, I need some kind of type/component array mapping. And while the key can be a std::type_index, what will the value of the map be? I can't store arrays of different types in one std::map.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re:creation - a top down action rpg about undeads
« Reply #8 on: May 03, 2015, 01:31:46 am »
As I've understood, one way of doing it is by having each System own an array of the Component it manages.

Something like:
template<typename T, typename std::enable_if<std::is_base_of<Component>::value>::type* = nullptr>
class System
{
      public:
            System();
           
            virtual void update(float dt) = 0;
           
            T& get(int idx);

      private:
            container_of_your_choice<T> components;
};
 

Something like that. It can be pretty much however you want of course.
Then just derive from that for each System/Component type, implement any virtual functions you have, and there you go.

So like:
class GraphicsSystem : public System<GraphicsComponent>
{
      // stuff goes here...
};
 

I'm planning to adjust my own code base to something like this soonTM.

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #9 on: May 03, 2015, 08:39:41 am »
I've done this before, but this led to another problem: I couldn't store Systems in one collection and had to update them like this:
void EntityManager::update() {
    renderingSystem->update();
    collisionSystem->update();
    ... // etc.
}
So, every time I add a new system, I need to add it to update, process and other
 functions, because I can't just iterate over all of them. (And I had to insert it in particular order everywhere, because it matters)

I have this instead now, because I have a base class EntitySystem and std::vector<EntitySystem*> systems:
void EntityManager::update() {
    for(auto it != systems.begin(); it != systems.end(); ++it) {
        (*it)->update();
    }
}

RenderingSystem looks like this, for example:
class RenderingSystem : public EntitySystem {
public:
    ...
private:
   std::vector<GraphicsComponent*> components
}
So, every system has it's own vector of components (and if systems needs to operate on two different types of components, it can!), but I still can store systems in one place and easily add new systems.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re:creation - a top down action rpg about undeads
« Reply #10 on: May 03, 2015, 07:56:31 pm »
Ah. I see. Well, I guess you could then have a BaseSystem class of sorts that System<T> inherits from, and then have a container of BaseSystem*s or something, if each System<T> is all going to have the same functions. Then you could iterate over all the systems. And just add them to the container in the order you need them to update.

Though I do like your method as well.

It's interesting to see the different methods people come up with!

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #11 on: May 04, 2015, 10:55:37 am »
That's a good suggestion, maybe I'll try it out someday. :)

And I love to see different ways of doing stuff, I hope my dev log will inspire others and they'll show off their ways of doing things.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re:creation - a top down action rpg about undeads
« Reply #12 on: May 04, 2015, 11:11:47 am »
Cool, I don't like "pixel" styled games but this one is really fun.

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #13 on: May 04, 2015, 12:08:18 pm »
This looks stunning! :-)

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action rpg about undeads
« Reply #14 on: May 04, 2015, 01:32:11 pm »
Cool, I don't like "pixel" styled games but this one is really fun.

Thanks! I use pixel art because creating high-res art is really hard while working solo. It also looks less professional when done by not very skilled artist. I try to make my pixel art look unique, though!

This looks stunning! :-)
Thanks a lot! :)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler