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

0 Members and 2 Guests are viewing this topic.

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #435 on: December 18, 2015, 10:07:48 pm »
Okay, aside from the circular dependencies problems, I think about easier ways to solve the problem.
So, I think it would be good to make Json::toValue(T& obj) return null value for ALL non-standard types. What about the classes which can be serialized? Well, I think that it would be good for classes to provide serialization function to all members with non-standard types which have to be serialized. So, the Meta<T>::serialize will work like this:
1) Call toValue(T& obj) for all properties which have simple types (int, bool, string, etc.)
2) Ignore other properties and just call T::serialize

So, for GraphicsComponent this function will look like this:
void GraphicsComponent::serialize(Json::Value& root)
{
    root["specialAnimation"] = Meta<Animation>::serialize(specialAnimation);
    ... // serialize other stuff
}
So, it would just "append" all non-standard properties to existing Json::Value and the problem is solved.
The stuff I wanted to make previously is much more compilcated and isn't necessary as you can see (though it has some downsides, but they are okay!)

Update: so, I've made the changes, cast<T> function in Json::cast may seem silly, but this is one of the ways to be sure not change properties with non-default types. If I just returned T() for all non-standard classes, there's no way I could tell that this is T() for non-default value or some standard-type property is really T() (0, 0.0f, "", etc.)
« Last Edit: December 19, 2015, 11:31:12 am by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re:creation - a top down action adventure about undeads
« Reply #436 on: December 21, 2015, 05:35:26 am »
This thread kept popping up non stop last week in recent posts so I looked through the screens and I noticed in one of the gif screens you use a small console/prompt in your game to enter Lua code.
I don't know how much code you enter by hand into game itself vs. code in files but I decided to shameless promote myself a little anyway. :P
I happen to have a Lua SFML console/terminal lib for 5.1 and 5.2 (I'd not mind adding 5.3 if that's what you're using now, but it came after you started and there is little benefit in upgrading 5.1 to 5.2 to 5.3 for gamedev purposes so I'm guessing it's not).
It's a Slavic product too. ;D
« Last Edit: December 21, 2015, 05:38:17 am by FRex »
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 #437 on: December 25, 2015, 08:53:50 am »
I don't know how much code you enter by hand into game itself vs. code in files
Not much, it's mostly for testing purposes. The code is not saved, this console just calls some C++ functions if I need to call them.

I happen to have a Lua SFML console/terminal lib for 5.1 and 5.2 (I'd not mind adding 5.3 if that's what you're using now, but it came after you started and there is little benefit in upgrading 5.1 to 5.2 to 5.3 for gamedev purposes so I'm guessing it's not).
How does it work? Does it integrate into C++ program and then calls Lua/SFML bindings?

Progress update
I've passed lots of exams in my university, so the week was very busy and I didn't have any time to work on the game! But I'll be mostly free for the next month, so I'll work on the game a lot.
I'll write a big blog post about the stuff I've done this year later. :)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re:creation - a top down action adventure about undeads
« Reply #438 on: December 25, 2015, 10:48:21 am »
Quote
How does it work? Does it integrate into C++ program and then calls Lua/SFML bindings?
It's a Lua console so it's like the 'lua' command line program except in your game.
You type Lua code into it and it'll evaluate it for you (plus extras like completion, history, etc.).
Anything you exposed to Lua is available, you're basically doing luaL_dostring at runtime in a super fancy way.

It's a C++ lib which depends only on Lua, C++98 and SFML and is meant to be easy to use:
1. You create the view, input and model class and give input the model ptr (and set font and history if you don't want to use default ones from default paths) and give L pointer to the model.
2. You call  input.handleEvent(eve) to filter your events through the console in your pollEvent loop.
3. You call view.geoRebuild(&model) and then draw the view (it's SFML drawable) when you want to render it.

There is an example here of minimal program that has just a console in it, with default everything: https://github.com/FRex/LuaConsole/blob/master/examples/main.cpp
It shouldn't take more than 30 minutes to get into an app and I tried to make it well configurable and so on but with sane defaults.
« Last Edit: December 25, 2015, 10:52:11 am by FRex »
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 #439 on: December 25, 2015, 10:00:21 pm »
Heh, this is basically what I do with my console. Everything I write after "lua" is passed to luaL_dostring.
But I have other functions as well. Like if I write "open res/levels/someLevel.txt", it opens level, if I write "info 45", it prints info about entity with id=45, etc.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

FRex

  • Hero Member
  • *****
  • Posts: 1845
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re:creation - a top down action adventure about undeads
« Reply #440 on: December 25, 2015, 11:50:54 pm »
I do just Lua code, so everything I want to use there must be exposed to Lua for my apps, but then I get history, completion, incomplete chunks, colors, ect. and I like working with Lua so it's worth it to me. I was thinking about a simplified bash-like input without braces and commas or about adding moonscript or typedscript input (or even some user provided input handler via callback instead of making all go through Lua) but didn't try to do any of that yet.
« Last Edit: December 25, 2015, 11:57:43 pm by FRex »
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 #441 on: December 27, 2015, 04:27:41 pm »
I do just Lua code, so everything I want to use there must be exposed to Lua for my apps, but then I get history, completion, incomplete chunks, colors, ect. and I like working with Lua so it's worth it to me. I was thinking about a simplified bash-like input without braces and commas or about adding moonscript or typedscript input (or even some user provided input handler via callback instead of making all go through Lua) but didn't try to do any of that yet.
That's pretty cool. I'll check out your project. :D

Progress update
Okay, I'm almost done with Animation Tool. Here's how it looks now:

This gif actually uses Meta system I've been working on for so long. Previous gifs just used JSON and reloaded animation when something changed. This one changes C++ value, so when I change "frameTime", corresponding C++ variable changes!

Stuff I've also added:
  • Can select animations
  • Type displayed (I have std::map<std::type_index, std::string> for that, so it's accurate)
Stuff I need to add:
  • Add/delete animation. Will be very easy to make
  • Save to file. Again, pretty easy, considering Meta<T>::serialize function
Later I'll use this project to make entity editor. It will work by the same principle. What's cool is that most of the members in component classes are of these types: bool, int, float, size_t, std::string, sf::Vector2i, sf::Vector2f, sf::IntRect, sf::FloatRect which are supported by my meta system very well.

One current problem I have which someone may help me solve is this. Suppose I want to do this:
std::cout << meta.get("someProperty");
This isn't going to work, because I need to do this:
std::cout << meta.get<int>("someProperty");  // if someProperty is int
Why do I need to specify the type? I need this type to convert from IProperty<Class> to Property<T, Class> inside get function!  (where T is type of property, Class is class to which this property belongs)

Property<T, Class>  has T Property<T, Class>::get() function which returns value of the property, but IProperty can't have it as virtual, because it's a base class which I use to store all properties in one map.
When I store Property<T, Class> as IProperty<Class> pointer I lose type of the property. I've solved this by storing type_index of T inside IProperty, so I can later get it to identify which type Property has.

So I can do this:
if(meta.getPropertyType("someProperty") == typeid(int)) {
    std::cout << meta.get<int>("someProperty");
} else if(meta.getPropertyType("someProperty") == typeid(double)) {
    std::cout << meta.get<double>("someProperty");
} ...
but those if/else things are pretty awful to write! (but they work, he-he)
Are there any other solutions?
What I want to do is do is call template function by getting the type out of type_index. Any way to do it without if/else?
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re:creation - a top down action adventure about undeads
« Reply #442 on: December 27, 2015, 07:17:11 pm »
virtual std::ostream& IProperty::print(std::ostream& stream) = 0;

Again, you can then add some syntactic suger on top of that to make it look funnier.
Laurent Gomila - SFML developer

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #443 on: December 27, 2015, 09:21:34 pm »
virtual std::ostream& IProperty::print(std::ostream& stream) = 0;

Again, you can then add some syntactic suger on top of that to make it look funnier.
At first I wanted to say "I've oversimplified the problem, in MY case I can't use virtual functions!" but then I thought "oh wait... what if...?" and turns out I can use them! :D
So, I've just replaced lots of awful code with one line(!) which looks like this:
meta.setData(name, value); // where value is QVariant.
This call IProperty<Class>::setData which calls Property<T, Class>::setData and there I have something like this:
T v;
castFromQVariant<T>(v, value);
set(obj, v);
Virtual function saves the day!


P.S. and I just want to show this gif. I've realized how many cool animations I have drawn and it made me happy :D
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re:creation - a top down action adventure about undeads
« Reply #444 on: December 27, 2015, 09:45:09 pm »
Nice! And this looks like a really versatile tool to tweak the animations :)

The presence of explicit case differentiations based on any kind of type identifier (dynamic_cast, typeid, a type enum, ...) is usually a strong indicator of bad abstraction. Very often, a form of polymorphism can help in these cases. See also my reply here.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #445 on: December 27, 2015, 10:23:53 pm »
Nice! And this looks like a really versatile tool to tweak the animations :)
Thanks! And it'll be a lot more versatile once I move all entity data to JSON and then I'll be able to do same stuff with most entity parameters.

The presence of explicit case differentiations based on any kind of type identifier (dynamic_cast, typeid, a type enum, ...) is usually a strong indicator of bad abstraction. Very often, a form of polymorphism can help in these cases. See also my reply here.
Wow, this looks really interesting, I'll think about it. The only place I have dynamic_cast now is get/set functions for properties. So, if I call this:
auto value = meta.get<int>("someIntProperty");
IProperty<Class> is cast to Property<T, Class> inside the get function, so I can call
T Property<T, Class>::get()
{
    ...
}

this function cannot be virtual, because of different return types for each property type.
But maybe I can do some trickery with templates and virtual functions which will allow me to get needed type from IProperty*... :D
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re:creation - a top down action adventure about undeads
« Reply #446 on: December 27, 2015, 11:01:56 pm »
Do you need dynamic_cast for error checking? Otherwise, you can as well downcast with static_cast.

Or even better, combine the advantages of both. I've written a downcast function template that checks the type in Debug mode, but is fast in Release mode. It's a drop-in replacement for static_cast:
Base& base = ...;
auto& derived = aurora::downcast<Derived&>(base);
auto* derived = aurora::downcast<Derived*>(&base);

By the way, the Aurora library is header-only and very lightweight, so it can be used very easily within any project (without configuration, building or linking).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re:creation - a top down action adventure about undeads
« Reply #447 on: December 28, 2015, 09:35:34 am »
Oh... if you use QVariant then it's a totally different thing. It does all the crappy things for you (type abstraction, checking, conversion, JSON serialization, ...). But I thought that you wanted to stay away from Qt specific stuff for this part of the code.

So now, may I ask why you still need this IProperty class with typed derived classes?
Laurent Gomila - SFML developer

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #448 on: December 28, 2015, 09:40:11 am »
Do you need dynamic_cast for error checking? Otherwise, you can as well downcast with static_cast.
Yeah, I think that dynamic_cast is not really necessary, but I think that assert which checks that cast succeeded will be nice. Are there any speed diferences between static_cast and dynamic_cast?

Or even better, combine the advantages of both. I've written a downcast function template that checks the type in Debug mode, but is fast in Release mode. It's a drop-in replacement for static_cast:
Base& base = ...;
auto& derived = aurora::downcast<Derived&>(base);
auto* derived = aurora::downcast<Derived*>(&base);
Good idea.

By the way, the Aurora library is header-only and very lightweight, so it can be used very easily within any project (without configuration, building or linking).
I think I'll implement my template stuff first (this is so useful to learn template trickery!) and then I'll try to use your library to gain some perfomance, because I think that your code may be better :D
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re:creation - a top down action adventure about undeads
« Reply #449 on: December 28, 2015, 11:04:03 am »
Yeah, I think that dynamic_cast is not really necessary, but I think that assert which checks that cast succeeded will be nice. Are there any speed diferences between static_cast and dynamic_cast?
Yes, of course. As implied by the name, static_cast is resolved at compile time (the compiler computes the new start address of the class, which is more or less an addition at runtime), while dynamic_cast is a runtime operation that looks up the RTTI of the involved classes and checks their inheritance relation. But in any case, performance should not be the decisive factor here.

You can only use static_cast when you're sure about the conversion, and it's more limited (regarding cross-casts or casts through virtual inheritance). But the use of dynamic_cast should be questioned; often, a design with virtual functions can replace it.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything