-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event logic #744
Event logic #744
Conversation
Maybe use |
You got a point there. I have tried to condense the gamestate down into the most basic datatypes that need to be timely tracked. Container TypesContainer types hold lists of items at any given time. They store a creation and a deletion timestamp for each item, and offer iteration logic to traverse the active elements in the container. Map ContainerThe map container stores items based on an unique identifier mapped to an item. It keeps track of the existence of the item. No guaranteed order of items within this container is given (similar to std::unordered_map). https://github.com/SFTtech/openage/blob/master/libopenage/gamestate/player.h#L139 Set ContainerThe set container stores items, just as a normal array would. It keeps track of the existence of the items, but does not guarentee any particular ordering (similar to std::unordered_set). Queue ContainerThe queue container represents a random access queue while keeping the ordering of the queue. https://github.com/SFTtech/openage/blob/master/libopenage/pathfinding/path.h#L189 Simple TypesSimple types only have one distinct value at a specific point in time. Discrete Interpolation"Step function" style values. These types adopt the new value exactly at the point in time changed. https://github.com/SFTtech/openage/blob/master/libopenage/gamestate/population_tracker.h#L85 Linear InterpolationLinear connections between two points. These types have to overload the operators + and *, since these https://github.com/SFTtech/openage/blob/master/libopenage/unit/unit.h#L68 Nyan ValuesThis container keeps track of nyan objects over time and their respective properties.
|
2d8891b
to
f2bd2ab
Compare
I will put my thoughts on curves here
Example:
Note: The wrappers would also implement the Curve interface
Example:
where the first const curve has the old value with a duration of the timer and the second curve the new value with infinite duration Note: @TheJJ So the
Example: int hitpoints
hitpoints = 10
...
hitpoints += 2 * delta to: IntLinearCurve hitpoints = new IntLinearCurve()
hitpoints[now] = 10
...
hitpoints[now + (50 - hitpoint[now]) ] = 100 Side note to @TheJJ: |
I agree on the thing, that curves are hard, but actually we have a working prototype. The curves are very tightly entangled with the event execution pipeline. The events are basically the future part of the curves, executed to extend the validity of curves. Curves are just another normal datatype, you can put some curves into a struct, and you can put structs into a curve. // Curve in a Struct
struct thing {
curve::Continuous<int> hitpoints;
int id;
};
// Struct in a curve
// It is not possible to use a continuous curve here - would need + and * for interpolation.
struct parameters {
int a;
int b;
};
curve::Discrete<parameters> params; It is only very confusing to use a curve in a curve, because every new keyframe would store a new curve for the inner curve, dropping the history of the contained curve. Repeating curves can be implemented using callbacks at the end of a loop, reinserting values again. Your example would be in the current API: auto hitpoints = std::make_shared<curve::Continuous<int>>(); // If a think wants to be targeted by an event it has to be a `std::shared_ptr`;
hitpoints.set_drop(now, 10); // set as new last value, ignoring all previous history
...
time_until_damage = 30; // time between attacks of a unit (sword-strikes) in ms
damage = 1; // the damage the unit takes on the attack
hitpoints.set_drop(now + time_until_damage, hitpoints.get(now) - damage); To make sure, that multiple units can damage another unit, it would be better to implement this damage by an event "target_hit" as a This would lead to a little bit more code, which shall be part of the standard library: // The Damage Event, that has to be set up in order to register an event.
class EventDamage : public curve::EventClass {
public:
EventDamage() : curve::EventClass("openage.damage", EventClass::Type::ONCE) {}
// The Damage Event does not depend (for re-prediction) on any other values
void setup(const std::shared_ptr<Event> &evnt,
const std::shared_ptr<State> &state) override {
// if it would depend, we have to add dependencies:
//this->add_dependency(evnt, evnt->target);
}
// Whenever the event is up for execution do this. It is guaranteed, that all events up to this point
// have been executed - but it is not guarenteed, that it will be executed only once!
void call(curve::EventManager *mgr,
const std::shared_ptr<EventTarget> &target,
const std::shared_ptr<State> &state,
const curve::curve_time_t &now) override {
// Do the actual logic here
target->hitpoints->set_drop(target->hitpoints->get(now) - 1);
}
};
...
// Add the event class to the pool of events - this is done during startup.
EventManager mgr;
mgr.add_class(std::make_shared<EventDamage>()); Now it can be used from the game logic. // This connection between objects and events can be derived from defaults, abilities, or nyan
// Unit has to implement the EventTarget interface, or be a curve.
mgr.on("openage.damage", unit); Currently I am still working on a nice interface to add additional parameters to the Still the question, what would be better - |
1e86a47
to
e3cde6b
Compare
The tube demo runs a simple curses based pong, that shall demonstrate the functionality where and why a prediction interface is built.
@@ -1,5 +1,5 @@ | |||
# Prerequisite steps for Ubuntu users (Ubuntu 16.04) | |||
|
|||
- `sudo apt-get update` | |||
- `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libpng-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` | |||
- `sudo apt-get install cmake libfreetype6-dev python3-dev python3-pip libepoxy-dev libsdl2-dev libsdl2-image-dev libopusfile-dev libfontconfig1-dev libharfbuzz-dev libncurses5-dev opus-tools python3-pil python3-numpy python3-pygments qtdeclarative5-dev qml-module-qtquick-controls` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libpng
is still needed. and the other distros need the ncurses package as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libncurses
should be an optional dependency, like it is done for inotify
.
double offset = time - e->time; | ||
// If we do not have a next (buffer underrun!!) we assign values | ||
if (nxt == this->container.end()) { | ||
// log::log(WARN << "Continuous buffer underrun. This might be bad! Assuming constant."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover, what do? probably crash :)
@@ -0,0 +1,120 @@ | |||
TUBE DATATYPES | |||
================= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pls move this file to $root/doc/code/
| if (flag & time) time1 | # In the second quadruple the usage of the data is stored | ||
| if (flag & time2) time2 | # | time | time2 | data | UNUSED | delete | add | del_after | UNUSED | | ||
| if (flag & data) keyframe: size(16) | data | | ||
+-----------------------------------------------------------+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is broken. shall it be a table or a <pre>
?
Meaning of Flags | ||
---------------- | ||
|
||
== DELETE == |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those headlines just show up as == DELETE ==
, maybe you meant ## DELETE ##
? otherwise, maybe ``?
mgr->on("demo.ball.reflect_panel", state->ball->position, state, now); | ||
// FIXME once "reset": deregister | ||
|
||
// reset(state, mgr, now); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover
// state->ball.position->set_drop(now, state.resolution * 0.5); | ||
//} | ||
//update_ball(state, now, init_recursion_limit); | ||
//break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
many leftovers
Event Queue Magic | ||
===================== | ||
|
||
The Event Queue consists of Events and their Context: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also move to doc/code/
pls
|
||
The Event Queue consists of Events and their Context: | ||
|
||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to enhance the highlighting, c++
could improve it
|
||
Internas | ||
========= | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either leave out of fill with content :)
* cppclass Continuous(ValueContainer): | ||
* _T get(const curve_time_t&) except + | ||
*/ | ||
template<typename _T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should agree on a project wide style for naming template parameters. _T
is new to me, maybe we could do that everywhere. Needs discussion.
namespace openage { | ||
namespace curvepong { | ||
|
||
std::vector<event> &Gui::getInputs(const std::shared_ptr<PongPlayer> &player) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
camelcase getInputs
-> get_inputs
COLOR_2 = 7, | ||
COLOR_3 = 8, | ||
COLOR_4 = 9, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not important, but could be a enum class
and you then access with color::player1
etc.
curvepong::Gui gui; | ||
#endif | ||
bool running = true; | ||
srand(time(NULL)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have our util/random
system that should be used instead
#elif REALTIME == 2 | ||
now += 4; | ||
#else | ||
#error no REALTIME plan set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indent
auto positioncurve = std::dynamic_pointer_cast<Continuous<util::Vector<2>>>(target); | ||
auto speedcurve = state->ball->speed; | ||
|
||
// All the magic in the next lines |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pls explain the magic
* Every Object in the gameworld that wants to be targeted by events or as | ||
* dependency for events, has to implement this class. | ||
*/ | ||
class EventTarget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would Entity
be a better name? Or would Entity be the "main" class that inherits from EventTarget
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only used to interface with the event system. I would have a core Game Entity, that inherits this event interface
add_sources(libopenage | ||
keyframe_container.cpp | ||
value_container.cpp | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can rename the internal
folder to data_container
because that's what's in the folder?
public: | ||
/** | ||
* A element of the curvecontainer. This is especially used to keep track of | ||
* the value-timing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indent
|
||
// We want to remove a possible equal timed element from the container | ||
// to do fabs(x-y) < min is only necessary when curve_time_t is floating point! | ||
//if (std::abs(hint->time - at) < std::numeric_limits<curve_time_t>::min()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indent and leftover
@@ -0,0 +1,111 @@ | |||
// Copyright 2017-2017 the openage authors. See copying.md for legal info. | |||
|
|||
#pragma once |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we added this file as a prototype but we should remove this from the pull request to then work on its creation in #964
#1008 obsoletes this one. |
The tube demo runs a simple curses based pong, that shall
demonstrate the functionality where and why a prediction interface is
built. 🤢