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 466388 times)

0 Members and 1 Guest are viewing this topic.

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #690 on: December 09, 2016, 04:20:06 pm »
it looks really neat,  :)

have you tested with U-shape ?

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #691 on: December 10, 2016, 10:11:28 pm »
Mario, but as you can see, there are rotated boxes which don't work with grids well. As for bezier curves... that's a possibility, but too much work, as for now. Maybe I'll add them later.
I think I'll just use grid based graphs with some edges and vertices removed just like I do in this demo. Probably will work fine! :D

Mortal, thank you! What do you mean by U-shape?
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #692 on: December 11, 2016, 12:05:23 am »
i mean the worst nightmare of Dijkstra’s algorithm, according to this site  ;D

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #693 on: December 11, 2016, 09:25:16 am »
Dijkstra’s algorithm will consider a lot of edges, but will still work in the case of U-shape. Perfomance is not critical for pathfinding at this point, as it's still very fast compared to rendering and collision. I'll write A* soon, though. :D
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 adventure about undeads
« Reply #694 on: April 19, 2017, 11:36:39 pm »
It's alive!

Sorry for the silence: I wanted to make a huge dev log once I've made a lot of new art and gameplay stuff, but the semester got hard and I only had time to work on engine stuff, but still made a significant progress.
Here's the latest dev log: https://eliasdaler.github.io/re-creation-devlog-december-march/

Hope you like it! And I hope that the next one will contain a lot more new things in it, not just engine/code related details.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #695 on: April 20, 2017, 10:43:45 am »
Would really be interested to see how your C++/Lua interaction works, especially considering the subclassing (in this example components). Are you just copying metatables around or are you doing more?

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #696 on: April 20, 2017, 10:59:42 am »
Would really be interested to see how your C++/Lua interaction works, especially considering the subclassing (in this example components). Are you just copying metatables around or are you doing more?
I use middleclass for OOP, and yes, it just copies metatables and for subclassing it stores base class metatable.

As for C++/Lua interaction. It mostly happens via events.For example, collision system checks for all the collisions and if they happen, it adds collision even to global event queue. After all systems finished processing, C++ calls Lua's "processEvent" function which calls callbacks for each happened event. Here's an example of enemy's callback on damage (it's going to get more complex later, but it works for now!):
callback = function(entity, event)
    if entity:getCurrentStateName() ~= "HurtState" then
      playSound("enemy_hit")
      local health = entity.components.health
      if health:getHealth() > 0 then
          entity:changeState("HurtState")
          health:decreaseHealth(event.data.damageAmount)
      end
    end
end

All Lua's components are currently accessed in Lua scripts only, so I don't have to deal with C++ getting components from Lua, as these components are very game-specific and game-specific things don't happen on C++ side anymore! :)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #697 on: April 20, 2017, 11:22:07 am »
Cool, didn't know that library so far. :)

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #698 on: April 20, 2017, 11:26:49 am »
Cool, didn't know that library so far. :)
It's very convenient for OOP. And check out other kikito's repositories, he does a lot of useful Lua (and not only) stuff. :D
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 adventure about undeads
« Reply #699 on: May 19, 2017, 11:37:08 pm »
I'm back! Starting out slowly, but with lots of confidence. Can't promise much, as I have lots of study to do (3 homeworks, 3 big projects, exams coming up, ugh!)
So, first of all, I was a little afraid that I'll look at the code and be either confused or have a burning desire to fix a lot of stuff in it. But thankfully major recent refactorings came out pretty well, so I started working on the game right away.

First, I decided to make platforms which follow waypoints.Waypoints are just entities without any components. All I need is to position them in the world and have platform follow them. Of course, this will also be used for other entities, like humans following predetermined paths.

I still have no idea how to store paths in a good way, so right now I just hardcode them by their tags. Each waypoint just gets a tag like "waypoint1", "waypoint2", etc. The path is stored in Lua like this:
somePath = { "waypoint1", "waypoint2", "waypoint3" }
Maybe I'll store them in map files at some point.

And then I realized that I can't set tag via level editor interface (previously I set them by hand in map file, ha-ha), so I quickly made this:

ImGui is trully brilliant for such quick and useful interfaces.

And then I've made platforms follow the path. It was very easy. I created FollowPathAction which is an action which can be used in action lists. It stores an array of waypoint tags and then iterates over them, creating GoToAction for each waypoint until the end of the path is reached. I've also made some additional conditions there:
  • Path following starts with the waypoint to which entity is closest too (e.g. guard chases the player and then returns to his idle path afterwards)
  • If path following starts from beginning of the path, it goes forward, otherwise - backward (e.g. 1->2->3 vs 3->2->1).
The result looks like this:


Nice! It took me 3-4 hours to make all this stuff (with some small bug-fixing of other stuff that I discovered was broken), so it's pretty nice how quickly I can make some gameplay things. :)

Next up is tile collision porting from my test project which has diagonal collisions. I also want to some simple tile interactions. For example, running on grass vs rock will have different sounds, running on tiles with sand will leave footprints, etc. I'll also use this system to implement falling into pits, because right now you can't do that! :D

P.S. I've also made some nice organization change: now all transform related things (position, facing direction) are grouped in Transform component, all child-parent related things are in HierarchyComponent, so now I do something like this:
auto pos = someEntity.transform.getPosition();
/* ... */
someEntity.hierarchy.addChild(otherEntity);
I made this components public, so I could have easy access to them, instead of calling template get<ComponentType> function every time. Not much difference, but the code looks less noisy. :)
« Last Edit: May 19, 2017, 11:39:29 pm by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re:creation - a top down action adventure about undeads
« Reply #700 on: May 20, 2017, 01:39:04 pm »
Why a pop up and not an edit box right in the same window? I thought more modern UX/UI is moving away from such pop ups.
Back to C++ gamedev with SFML in May 2023

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #701 on: May 20, 2017, 03:01:39 pm »
Why a pop up and not an edit box right in the same window? I thought more modern UX/UI is moving away from such pop ups.
Hmm, I just found popups easier to implement, because for edit box in the same window to work, I need to somehow catch event of exiting edit box and then apply it to entity. I'll see if it's easy to do with ImGui, I agree that it'll be better. Maybe I'll even make property table like this:
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 adventure about undeads
« Reply #702 on: June 01, 2017, 09:09:51 pm »
Okay, I've made lots of stuff again!

Tile collision, falling into pits
First of all, you can fall into pits now.


For that to work, I had to integrate previously implemented collision detection into my game. This only took several hours, but now I have diagonal collision as well, which will allow me to make more interesting levels!


I also used cornering system from tiles to entities as well, so that hero now doesn't get stuck on corners of another objects and gets pushed it needed direction automatically.


So, how does falling work?
Now in every frame I check if common tile of entity changes. As most entities don't occupy many tiles, I just iterate over all tiles it intersects and if all of them are of the same type (e.g. "fall tiles"), I send CommonTileChanged event. Hero's state machine catches that event, sees that common tile is now a "fall tile" and changes hero's current state to FallState.
This will work with other systems good as well, for example if I add footstep sounds, I will use CommonTileChanged event to change walking sounds from "grass" footsteps to "rock" footsteps, depending on which tiles player walks on.

Platforms
Things don't stop here. If player steps on the platform, he doesn't fall! This is not as simple as it looks, but I'm glad I didn't have to hardcode it.


When player collides with platform, CollisionEvent is queued. CommonTileChanged event is queued too, but as CollisionSystem checks collisions before TileCollisionSystem, CollisionEvents is processed first afterwards. When something collides with moving platform, it adds it to child list (if it wasn't added before). Hero becomes a child of moving platform and inherits platform's position (moves with it).
Then CommonTileChanged event is checked, but in the callback I check if entity has a parent or not. If it does, it won't go to FallState, so the hero doesn't fall into a pit, as it has moving platform as a parent. I'll probably make it event more explicit, maybe I'll add isFlying flag which will be true for moving platform and later in CommonTileChanged callback I'll check it on parent of entity which is about to fall down. I'll see what works the best. :)

Huge changes to ECS implementation
I've also checked out EntityX source code and found some very useful things which I liked about its implementation. In my implementation references to components of currently active entities were stored in corresponding systems. So, CollisionSystem had vector of references to CollisionComponents. But now I implemented the system which allows me just to do this:

for(auto& e : entityManager.getEntitiesWith<CollisionComponent, MovementComponent>()) {
    auto& mc = e.get<MovementComponent>();
    auto& cc = e.get<CollisionComponent>();
    ... // do something
}
Nice! This allows me to always get active entities with needed components and not have to store and constantly update component lists as entities get deactivated or components get disabled.

The implementation is pretty simple. First of all, each component type get unique id from 0 to N. And I also started to store all entity's components in a std::array<std::unique_ptr<Component>, MAX_COMPONENTS>. I don't have a lot of component types (I'm only counting those implemented in C++, low level ones!), so this array is very small and holds pointers after all. But this means that I can get needed components very fast just by using their unique id as an array index! I previously used unordered_map for getting storing components and getting components was pretty slow, especially when done frequently, it became noticeable in profiler.
I can also now very quickly test if entity has needed components or not. I store activeComponentMask bitset which has bits set to 1 in corresponding positions if component is active (not only present, but active, as I can sometimes disable collision, for example!).

EntityManager stores ids of currently active entities (entities nearby the hero which need to be updated) and getEntitiesWith returns EntityView object which is then used for easy iteration. Iterator just checks if entity has needed components by comparing mask being searched to activeComponentMask. It all works very fast even with lots of entities, which makes me very happy, as I don't have to store component lists anywhere now.

Iterating over tile indices
I've also implemented cool range/iterator for 2d indices. I had lots of code like this:
const auto tilesIdx = TileMap::getTileIndicesInRect(boundingBox);
// tilesIdx is sf::IntRect which has (left-top) set to left-top tile in range and (width, height) correspond number of X and Y tiles
for (int y = 0; y < tilesIdx.height; ++y) {
    for (int x = 0; x < tilesIdx.width; ++x) {
    // for all tiles that entity intersects...
        const TileIndex tileIndex(tilesIdx.left + x, tilesIdx.top + y); // this is sf::Vector 2f
        const auto& tile = tileMap.getTile(tileIndex);
        ... // do something
But this got really annoying as I wrote this code again and again... And then I realized, what if I make range which returns indices like this?
(0, 0), (1, 0), (2, 0), ... (5, 0), (0, 1), (1, 1), ...
And I've made this range by implementing RowColumnIterator which operator++ increases x if it's less than number of X tiles in range. And it worked perfectly! Now I just write code like this:
for(const auto& tileIndex : TileMap::getTileIndicesInRect(boundingBox)) {
    const auto& tile = tileMap.getTile(tileIndex);
    ... // do something
}
Much better!
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Ethan.Calabria

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #703 on: June 03, 2017, 06:52:07 pm »
That's a great falling animation!

It's always really interesting to me to see how other developers program their engines...there's a lot of ways to accomplish things I never would have thought of with my own style.
----
Follow me on twitter: here

Carlos Augusto Br Cpp

  • Newbie
  • *
  • Posts: 40
  • Programming is life
    • View Profile
    • Email
Re:creation - a top down action adventure about undeads
« Reply #704 on: June 04, 2017, 12:38:00 am »
Hey Elias... when will you give to us the grace of an demo?  :D