博主最近时间不多,所以不过多阐述,直接上代码
// TangDynastyVR_Complete.h
#pragma once
#include <openvr.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <string>
#include <map>
#include <random>
#include <iostream>
// ==================== 核心系统枚举和结构 ====================
enum class EmotionalState { NEUTRAL, JOYFUL, ANGRY, SAD, POETIC, NOSTALGIC, PROUD };
enum class TimePeriod { MORNING, NOON, AFTERNOON, EVENING, NIGHT };
struct DialogueMessage {
std::string speakerName, content;
float displayTime;
glm::vec3 speakerPosition;
bool isHistoricalFigure;
};
struct PBRMaterial {
glm::vec3 albedo = glm::vec3(0.8f, 0.8f, 0.8f);
float metallic = 0.0f, roughness = 0.8f, ao = 1.0f;
GLuint albedoMap = 0, normalMap = 0;
};
// ==================== 场景对象基类 ====================
class SceneObject {
public:
virtual ~SceneObject() = default;
virtual void render(const glm::mat4& view, const glm::mat4& projection) = 0;
virtual void update(float deltaTime) = 0;
virtual glm::vec3 getPosition() const = 0;
virtual void setSelected(bool selected) {}
virtual std::string getName() const { return "Unknown"; }
};
// ==================== 时间与季节系统 ====================
class TimeWeatherSystem {
private:
float timeOfDay = 8.0f; // 8:00 AM开始
float dayCounter = 0.0f;
float timeSpeed = 60.0f;
glm::vec3 sunDirection, sunColor, ambientLight;
TimePeriod currentPeriod = TimePeriod::MORNING;
public:
void update(float deltaTime) {
timeOfDay += deltaTime * timeSpeed / 3600.0f;
if (timeOfDay >= 24.0f) {
timeOfDay -= 24.0f;
dayCounter += 1.0f;
}
updateTimePeriod();
updateLighting();
}
void updateTimePeriod() {
if (timeOfDay >= 5.0f && timeOfDay < 8.0f) currentPeriod = TimePeriod::MORNING;
else if (timeOfDay >= 8.0f && timeOfDay < 12.0f) currentPeriod = TimePeriod::NOON;
else if (timeOfDay >= 12.0f && timeOfDay < 17.0f) currentPeriod = TimePeriod::AFTERNOON;
else if (timeOfDay >= 17.0f && timeOfDay < 21.0f) currentPeriod = TimePeriod::EVENING;
else currentPeriod = TimePeriod::NIGHT;
}
void updateLighting() {
float hourAngle = (timeOfDay - 6.0f) * 15.0f;
float radianAngle = glm::radians(hourAngle);
sunDirection = glm::normalize(glm::vec3(glm::sin(radianAngle), glm::cos(radianAngle), 0.0f));
if (currentPeriod == TimePeriod::NIGHT) {
sunColor = glm::vec3(0.1f, 0.1f, 0.2f);
ambientLight = glm::vec3(0.05f, 0.05f, 0.1f);
} else {
float intensity = 1.0f - abs(timeOfDay - 12.0f) / 6.0f;
sunColor = glm::vec3(1.0f, 0.9f, 0.8f) * intensity;
ambientLight = glm::vec3(0.3f, 0.3f, 0.4f) * intensity;
}
}
TimePeriod getCurrentPeriod() const { return currentPeriod; }
float getTimeOfDay() const { return timeOfDay; }
glm::vec3 getSunDirection() const { return sunDirection; }
glm::vec3 getSunColor() const { return sunColor; }
glm::vec3 getAmbientLight() const { return ambientLight; }
std::string getTimeString() const {
int hour = static_cast<int>(timeOfDay);
int minute = static_cast<int>((timeOfDay - hour) * 60);
return std::to_string(hour) + ":" + (minute < 10 ? "0" : "") + std::to_string(minute);
}
std::string getPeriodString() const {
switch(currentPeriod) {
case TimePeriod::MORNING: return "清晨";
case TimePeriod::NOON: return "正午";
case TimePeriod::AFTERNOON: return "下午";
case TimePeriod::EVENING: return "傍晚";
case TimePeriod::NIGHT: return "夜晚";
default: return "未知";
}
}
};
// ==================== 历史人物性格系统 ====================
class HistoricalPersonality {
private:
std::map<EmotionalState, std::vector<std::string>> dialogues;
std::map<TimePeriod, std::vector<std::string>> timeBasedDialogues;
public:
void setDialogues(EmotionalState state, const std::vector<std::string>& lines) {
dialogues[state] = lines;
}
void setTimeDialogues(TimePeriod period, const std::vector<std::string>& lines) {
timeBasedDialogues[period] = lines;
}
std::string speak(EmotionalState state, TimePeriod period) {
// 70%几率使用情感对话,30%几率使用时间对话
if ((rand() % 10) < 3 && !timeBasedDialogues[period].empty()) {
auto& periodDialogues = timeBasedDialogues[period];
return periodDialogues[rand() % periodDialogues.size()];
} else {
auto& stateDialogues = dialogues[state];
if (!stateDialogues.empty()) {
return stateDialogues[rand() % stateDialogues.size()];
}
}
return "";
}
};
// ==================== 增强历史人物类 ====================
class EnhancedHistoricalCharacter : public SceneObject {
private:
std::string characterName, characterType;
glm::vec3 position, historicalHeight;
glm::mat4 modelMatrix;
EmotionalState currentEmotion;
HistoricalPersonality personality;
TimeWeatherSystem* timeSystem;
// 渲染资源
GLuint VAO, VBO, textureID;
PBRMaterial material;
// 动画状态
float animationTime = 0.0f, emotionChangeTimer = 0.0f;
float speakCooldown = 0.0f, blinkTimer = 0.0f;
bool canSpeak = true, isSelected = false;
// 日常安排
std::map<TimePeriod, std::string> activities;
std::map<TimePeriod, glm::vec3> locations;
public:
EnhancedHistoricalCharacter(const std::string& name, const std::string& type,
const glm::vec3& pos, TimeWeatherSystem* timeSys)
: characterName(name), characterType(type), position(pos), timeSystem(timeSys),
currentEmotion(EmotionalState::NEUTRAL) {
initializeHistoricalData();
initializePersonality();
initializeDailySchedule();
setupRendering();
}
void initializeHistoricalData() {
// 基于历史记录设置特征
if (characterName == "李白") {
historicalHeight = glm::vec3(1.0f, 1.75f, 1.0f);
material.albedo = glm::vec3(0.3f, 0.3f, 0.5f); // 文人青衫
} else if (characterName == "杜甫") {
historicalHeight = glm::vec3(1.0f, 1.72f, 1.0f);
material.albedo = glm::vec3(0.4f, 0.3f, 0.2f); // 朴素褐衣
} else if (characterName == "杨贵妃") {
historicalHeight = glm::vec3(1.0f, 1.65f, 1.0f);
material.albedo = glm::vec3(0.9f, 0.1f, 0.1f); // 华贵红装
}
modelMatrix = glm::scale(glm::mat4(1.0f), historicalHeight);
}
void initializePersonality() {
if (characterType == "libai") {
personality.setDialogues(EmotionalState::POETIC, {
"李白:(举杯邀月)人生得意须尽欢,莫使金樽空对月!",
"李白:天生我材必有用,千金散尽还复来!当浮一大白!",
"李白:我本楚狂人,凤歌笑孔丘。手持绿玉杖,朝别黄鹤楼。"
});
personality.setTimeDialogues(TimePeriod::EVENING, {
"李白:如此良辰美景,当对月饮酒,吟诗作对!",
"李白:店家,再来一壶好酒!今夜不醉不归!"
});
} else if (characterType == "dufu") {
personality.setDialogues(EmotionalState::SAD, {
"杜甫:(忧心忡忡)朱门酒肉臭,路有冻死骨...",
"杜甫:国破山河在,城春草木深。感时花溅泪,恨别鸟惊心。"
});
personality.setTimeDialogues(TimePeriod::MORNING, {
"杜甫:晨起读书,当思天下百姓疾苦。",
"杜甫:这清晨的宁静,不知能持续到几时..."
});
}
}
void initializeDailySchedule() {
// 基于历史记载的日常安排
activities[TimePeriod::MORNING] = "晨读";
activities[TimePeriod::NOON] = "用膳";
activities[TimePeriod::AFTERNOON] = (characterType == "libai") ? "饮酒作诗" : "忧思国事";
activities[TimePeriod::EVENING] = "赏月";
activities[TimePeriod::NIGHT] = "就寝";
// 不同时间段的位置
locations[TimePeriod::MORNING] = glm::vec3(2, 0, -3);
locations[TimePeriod::NOON] = glm::vec3(0, 0, -4);
locations[TimePeriod::AFTERNOON] = glm::vec3(-2, 0, -3);
locations[TimePeriod::EVENING] = glm::vec3(0, 0, -5);
locations[TimePeriod::NIGHT] = glm::vec3(1, 0, -2);
}
void setupRendering() {
// 创建简单的人物几何体(实际应用应加载3D模型)
float vertices[] = {
// 位置 // 颜色
-0.3f, 0.0f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
0.3f, 0.0f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
0.0f, 1.5f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
}
void update(float deltaTime) override {
animationTime += deltaTime;
// 情绪变化
emotionChangeTimer -= deltaTime;
if (emotionChangeTimer <= 0) {
changeEmotionBasedOnTime();
emotionChangeTimer = 15.0f + (rand() % 15);
}
// 基于时间的活动
updateTimeBasedBehavior();
// 自然动画
float breath = sin(animationTime * 2.0f) * 0.005f;
modelMatrix = glm::translate(glm::mat4(1.0f), position + glm::vec3(0, breath, 0));
modelMatrix = glm::scale(modelMatrix, historicalHeight);
// 说话冷却
if (!canSpeak) {
speakCooldown -= deltaTime;
if (speakCooldown <= 0) canSpeak = true;
}
// 眨眼动画
blinkTimer += deltaTime;
}
void changeEmotionBasedOnTime() {
TimePeriod period = timeSystem->getCurrentPeriod();
switch(period) {
case TimePeriod::MORNING:
currentEmotion = (characterType == "libai") ? EmotionalState::POETIC : EmotionalState::NEUTRAL;
break;
case TimePeriod::EVENING:
currentEmotion = (characterType == "libai") ? EmotionalState::JOYFUL : EmotionalState::NOSTALGIC;
break;
case TimePeriod::NIGHT:
currentEmotion = EmotionalState::SAD;
break;
default:
currentEmotion = EmotionalState::NEUTRAL;
}
}
void updateTimeBasedBehavior() {
TimePeriod period = timeSystem->getCurrentPeriod();
position = locations[period]; // 移动到对应时间段的位置
// 根据活动调整姿态(简化实现)
if (activities[period] == "就寝") {
// 睡眠姿态
} else if (activities[period] == "饮酒作诗") {
// 豪放姿态
}
}
void speak(class DialogueUIManager& dialogueManager) {
if (!canSpeak) return;
std::string dialogue = personality.speak(currentEmotion, timeSystem->getCurrentPeriod());
if (!dialogue.empty()) {
dialogueManager.addMessage(characterName, dialogue, position, true);
speakCooldown = 10.0f + (rand() % 10);
canSpeak = false;
}
}
void render(const glm::mat4& view, const glm::mat4& projection) override {
// 简化渲染 - 实际应用应使用PBR着色器和复杂模型
glBindVertexArray(VAO);
// 基础着色器设置
// 如果是选中状态,改变颜色为高亮
if (isSelected) {
// 使用高亮颜色
}
glDrawArrays(GL_TRIANGLES, 0, 3);
}
glm::vec3 getPosition() const override { return position; }
void setSelected(bool selected) override { isSelected = selected; }
std::string getName() const override { return characterName; }
std::string getCurrentActivity() const {
return activities.at(timeSystem->getCurrentPeriod());
}
};
// ==================== 调试棒系统 ====================
class DebugWand {
private:
glm::vec3 position, direction;
bool isActive = false;
GLuint wandVAO, wandVBO;
SceneObject* selectedObject = nullptr;
public:
DebugWand() { initializeWandModel(); }
void initializeWandModel() {
float vertices[] = {
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 红色调试棒
0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 0.5f,
};
glGenVertexArrays(1, &wandVAO);
glGenBuffers(1, &wandVBO);
glBindVertexArray(wandVAO);
glBindBuffer(GL_ARRAY_BUFFER, wandVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
}
void update(const glm::vec3& wandPos, const glm::vec3& wandDir,
std::vector<std::shared_ptr<SceneObject>>& objects) {
position = wandPos;
direction = wandDir;
// 选择逻辑
selectedObject = nullptr;
float minDistance = 5.0f;
for (auto& obj : objects) {
float distance = glm::length(obj->getPosition() - position);
if (distance < minDistance) {
selectedObject = obj.get();
minDistance = distance;
}
}
// 更新选择状态
for (auto& obj : objects) {
obj->setSelected(obj.get() == selectedObject);
}
}
void handleInput(bool rightClick, std::vector<std::shared_ptr<SceneObject>>& objects) {
if (rightClick && selectedObject) {
// 从场景中移除选中的对象
auto it = std::find_if(objects.begin(), objects.end(),
this\](const std::shared_ptr\