Hi, ich möchte für mein Spiel die KI-Implementierung in Skripte auslagern. Um das ganze (was ich damit bewerkstelligen möchte) mal näher zu zeigen, habe ich mal ein minimales Beispiel gebaut:
game.hpp (in echt natürlich deutlich mehr als eine Header-File
)
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#pragma once
#include <string>
#include <vector>
namespace game {
struct Object {
std::string name, ai_script;
int pos, velocity;
Object(std::string const & name, int velocity);
};
struct Event {
enum class Type {
Move, Stop
} type;
std::string object_name;
};
// ----------------------------------------------------------------------------
class BaseSystem {
protected:
std::vector<Object*> objects;
public:
void addObject(Object& object);
};
class EventSystem {
public:
virtual void addEvent(Event const & event) = 0;
};
// ----------------------------------------------------------------------------
class PhysicsSystem: public BaseSystem {
public:
void update();
Object const * queryByPos(int pos) const;
};
class GraphicsSystem: public BaseSystem, {
private:
std::vector<Event> events;
public:
void render();
void addEvent(Event const & event);
};
class AiSystem: public BaseSystem {
private:
PhysicsSystem const & physics;
public:
AiSystem(PhysicsSystem const & physics);
void update();
};
}
|
game.cpp (in Echt natürlich deutlich mehr als eine cpp-File
)
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
#include <iostream>
#include "game.hpp"
namespace game {
Object::Object(std::string const & name, int velocity)
: name{name}
, ai_script{""}
, pos{0}
, velocity{velocity} {
}
// ----------------------------------------------------------------------------
void BaseSystem::addObject(Object& object) {
objects.push_back(&object);
}
// ----------------------------------------------------------------------------
void PhysicsSystem::update() {
for (auto ptr: objects) {
ptr->pos += ptr->velocity;
}
}
Object const * PhysicsSystem::queryByPos(int pos) const {
// implementation is of course a dummy ^^
for (auto ptr: objects) {
if (ptr->pos == pos) {
return ptr;
}
}
return nullptr;
}
void GraphicsSystem::render() {
for (auto& ev: events) {
std::cout << "Object '" << ev.object_name << "' is playing '";
if (ev.type == Event::Type::Move) {
std::cout << "Move";
} else {
std::cout << "Stop";
}
std::cout << "' animation" << std::endl;
}
events.clear();
for (auto ptr: objects) {
std::cout << "Object '" << ptr->name << "'\t@ "
<< ptr->pos << std::endl;
}
}
void GraphicsSystem::addEvent(Event const & event) {
events.push_back(event);
}
AiSystem::AiSystem(PhysicsSystem const & physics)
: physics{physics} {
}
void AiSystem::update() {
for (auto ptr: objects) {
if (ptr->ai_script.empty()) {
continue;
}
/* trigger script to perform on this object and pass various args like:
` loaded_script.main(*ptr, physics, eventsys); `
*/
}
}
}
|
main.cpp
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#include "game.hpp"
int main() {
game::Object tom{"tom", 1}, carl{"carl", 2}, bob{"bob", 5};
tom.ai_script = "example_ai.py";
bob.ai_script = "example_ai.py";
game::PhysicsSystem physics;
physics.addObject(tom);
physics.addObject(carl);
physics.addObject(bob);
game::GraphicsSystem graphics;
graphics.addObject(tom);
graphics.addObject(carl);
graphics.addObject(bob);
game::AiSystem ai{physics};
ai.addObject(tom);
ai.addObject(bob);
// terminating loop just for demonstration
for (auto i = 0; i < 100; ++i) {
ai.update();
physics.update();
graphics.render();
}
}
|
example_ai.py (ein KI-Skript)
|
Quellcode
|
1
2
3
4
5
6
7
8
9
10
|
# script needs some parts of the c++ code (classes, enums etc.)
# import game
def main(obj, physics, eventsys):
""" Stops movement if other object was found - not an AI task but it's just for demonstration what I mean :P """
target_pos = object.pos + object.velocity
other = physics.queryByPos(target_pos)
if other is not None:
obj.velocity = 0
eventsys.addEvent(game.Event(gameEvent.Type.Move, obj.name))
|
Dabei möchte ich jedem GameObject ein KI-Skript zuweisen, welches (wenn die KI mal wieder was machen soll) aufgerufen wird. Dabei benötige ich zum einen eine Schnittstelle in C++ um das Script auszuführen und eine weitere um vom Skript aus auf C++-Konstrukte zuzugreifen (Klassen, enums), z.B. um Events auszulösen auf die der C++-Code wieder reagieren soll.... Vielleicht stelle ich mir das alles auch nur zu einfach vor
Was könnt ihr mir empfehlen um das angestrebte realisieren zu können? Die Wahl der Skriptsprache ist dabei nebensächlich; Python ist hier nur ein Beispiel. Prinzipiell könnte ich auch Lua oder JavaScript nehmen. An dieser Stelle wäre ich für konkrete Implementierungen (d.h. wie könnte ich die auskommentierten Script-Calls / Imports im Script) realisieren.
LG Glocke