Adding scripts
This commit is contained in:
parent
995e2c8e5b
commit
63c9d7b35b
@ -47,3 +47,6 @@ check_and_download("https://download.savannah.gnu.org/releases/freetype/freetype
|
||||
|
||||
# 8) SDL_ttf
|
||||
check_and_download("https://github.com/libsdl-org/SDL_ttf/archive/refs/tags/release-2.24.0.zip" "release-2.24.0.zip" "SDL_ttf-release-2.24.0" "CMakeLists.txt")
|
||||
|
||||
# 9) pybind11
|
||||
check_and_download("https://github.com/pybind/pybind11/archive/refs/tags/v3.0.3.zip" "pybind11-v3.0.3.zip" "pybind11-3.0.3" "CMakeLists.txt")
|
||||
|
||||
@ -547,3 +547,14 @@ if(NOT TARGET boost_external_lib)
|
||||
# Boost заголовки находятся непосредственно в корне распакованной папки
|
||||
target_include_directories(boost_external_lib INTERFACE "${BOOST_SRC_DIR}")
|
||||
endif()
|
||||
|
||||
# ===========================================
|
||||
# 9) pybind11 (3.0.3) - Python embedding
|
||||
# ===========================================
|
||||
set(PYBIND11_SRC_DIR "${THIRDPARTY_DIR}/pybind11-3.0.3")
|
||||
|
||||
if(NOT TARGET pybind11::headers)
|
||||
# pybind11 is header-only; add_subdirectory gives us pybind11::embed which
|
||||
# also locates and links the Python interpreter and development libraries.
|
||||
add_subdirectory("${PYBIND11_SRC_DIR}" "${CMAKE_BINARY_DIR}/pybind11_build" EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
@ -71,6 +71,8 @@ add_executable(space-game001
|
||||
# ../src/Space.cpp
|
||||
../src/GameConstants.h
|
||||
../src/GameConstants.cpp
|
||||
../src/ScriptEngine.h
|
||||
../src/ScriptEngine.cpp
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
@ -109,6 +111,7 @@ target_link_libraries(space-game001 PRIVATE
|
||||
SDL2_ttf_external_lib
|
||||
eigen_external_lib
|
||||
boost_external_lib
|
||||
pybind11::embed
|
||||
)
|
||||
|
||||
# Линкуем OpenGL (Windows)
|
||||
|
||||
4
resources/start.py
Normal file
4
resources/start.py
Normal file
@ -0,0 +1,4 @@
|
||||
import game_api
|
||||
|
||||
# Tell NPC 0 to walk to the origin (0, 0, 0) when the game starts.
|
||||
game_api.npc_walk_to(0, 10.0, 0.0, 0.0)
|
||||
432352
resources/w/default_walk001.txt
Normal file
432352
resources/w/default_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
25
src/Game.cpp
25
src/Game.cpp
@ -178,17 +178,24 @@ namespace ZL
|
||||
|
||||
auto defaultTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE));
|
||||
|
||||
auto zombie = std::make_unique<Character>();
|
||||
zombie->loadAnimation(AnimationState::IDLE, "resources/w/default_idle002.txt", CONST_ZIP_FILE);
|
||||
zombie->setTexture(defaultTexture);
|
||||
zombie->walkSpeed = 1.5f;
|
||||
zombie->rotationSpeed = 2.0f;
|
||||
zombie->modelScale = 0.01f;
|
||||
zombie->position = Eigen::Vector3f(0.f, 0.f, -15.f);
|
||||
zombie->setTarget(zombie->position);
|
||||
npcs.push_back(std::move(zombie));
|
||||
auto npc01 = std::make_unique<Character>();
|
||||
npc01->loadAnimation(AnimationState::IDLE, "resources/w/default_idle002.txt", CONST_ZIP_FILE);
|
||||
npc01->loadAnimation(AnimationState::WALK, "resources/w/default_walk001.txt", CONST_ZIP_FILE);
|
||||
npc01->setTexture(defaultTexture);
|
||||
npc01->walkSpeed = 1.5f;
|
||||
npc01->rotationSpeed = 2.0f;
|
||||
npc01->modelScale = 0.01f;
|
||||
npc01->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||
/*
|
||||
Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5f, Eigen::Vector3f::UnitX())) *
|
||||
Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ()));*/
|
||||
npc01->position = Eigen::Vector3f(0.f, 0.f, -45.f);
|
||||
npc01->setTarget(npc01->position);
|
||||
npcs.push_back(std::move(npc01));
|
||||
|
||||
loadingCompleted = true;
|
||||
|
||||
scriptEngine.init(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <cstdint>
|
||||
#include <render/TextRenderer.h>
|
||||
#include "MenuManager.h"
|
||||
#include "ScriptEngine.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
@ -93,6 +94,7 @@ namespace ZL {
|
||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
MenuManager menuManager;
|
||||
ScriptEngine scriptEngine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
62
src/ScriptEngine.cpp
Normal file
62
src/ScriptEngine.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "ScriptEngine.h"
|
||||
#include "Game.h"
|
||||
#include <pybind11/embed.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
// Static pointer used by the embedded module (set before interpreter starts).
|
||||
static ZL::Game* s_game = nullptr;
|
||||
|
||||
// The embedded module must be defined at file scope before the interpreter
|
||||
// is started. It exposes a minimal surface: one function per scripting command.
|
||||
PYBIND11_EMBEDDED_MODULE(game_api, m) {
|
||||
m.doc() = "Game scripting API";
|
||||
|
||||
// npc_walk_to(index, x, y, z)
|
||||
// Tells the NPC at `index` in Game::npcs to walk to world position (x,y,z).
|
||||
m.def("npc_walk_to", [](int index, float x, float y, float z) {
|
||||
if (!s_game) {
|
||||
std::cerr << "[script] game_api.npc_walk_to: engine not ready\n";
|
||||
return;
|
||||
}
|
||||
auto& npcs = s_game->npcs;
|
||||
if (index < 0 || index >= static_cast<int>(npcs.size())) {
|
||||
std::cerr << "[script] game_api.npc_walk_to: index " << index
|
||||
<< " out of range (0.." << npcs.size() - 1 << ")\n";
|
||||
return;
|
||||
}
|
||||
npcs[index]->setTarget(Eigen::Vector3f(x, y, z));
|
||||
},
|
||||
py::arg("index"), py::arg("x"), py::arg("y"), py::arg("z"),
|
||||
"Command NPC[index] to walk to world position (x, y, z).");
|
||||
}
|
||||
|
||||
namespace ZL {
|
||||
|
||||
ScriptEngine::ScriptEngine() = default;
|
||||
ScriptEngine::~ScriptEngine() = default;
|
||||
|
||||
void ScriptEngine::init(Game* game) {
|
||||
s_game = game;
|
||||
interpreter = std::make_unique<py::scoped_interpreter>();
|
||||
runScript("resources/start.py");
|
||||
}
|
||||
|
||||
void ScriptEngine::runScript(const std::string& path) {
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "[script] Could not open script: " << path << "\n";
|
||||
return;
|
||||
}
|
||||
std::string source((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
try {
|
||||
py::exec(source);
|
||||
} catch (const py::error_already_set& e) {
|
||||
std::cerr << "[script] Error in " << path << ":\n" << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
27
src/ScriptEngine.h
Normal file
27
src/ScriptEngine.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Forward-declare the heavy pybind11 type so including this header stays cheap.
|
||||
namespace pybind11 { class scoped_interpreter; }
|
||||
|
||||
namespace ZL {
|
||||
|
||||
class Game;
|
||||
|
||||
class ScriptEngine {
|
||||
public:
|
||||
ScriptEngine();
|
||||
~ScriptEngine();
|
||||
|
||||
// Must be called once, after the Game's NPCs are ready.
|
||||
void init(Game* game);
|
||||
|
||||
// Execute a Python script file. Logs errors to stderr.
|
||||
void runScript(const std::string& path);
|
||||
|
||||
private:
|
||||
std::unique_ptr<pybind11::scoped_interpreter> interpreter;
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
Loading…
Reference in New Issue
Block a user