Compare commits
10 Commits
a6cb5db26c
...
da7dccf3ae
| Author | SHA1 | Date | |
|---|---|---|---|
| da7dccf3ae | |||
| 0b31c30b38 | |||
| 8b88904ef7 | |||
| 0ae47e5d6a | |||
| 80d088316b | |||
| 88f039348a | |||
| dc0213dc16 | |||
| 585724b512 | |||
| 1fb1ef4639 | |||
| bf35c6f0d8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
build/
|
||||
DNF/
|
||||
.cache/
|
||||
|
||||
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -94,6 +94,10 @@
|
||||
"string_view": "cpp",
|
||||
"numbers": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"cinttypes": "cpp"
|
||||
}
|
||||
"cinttypes": "cpp",
|
||||
"netfwd": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"cfenv": "cpp"
|
||||
},
|
||||
"Codegeex.RepoIndex": true
|
||||
}
|
||||
@@ -4,6 +4,16 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/DNF)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
if(MINGW) # 你的环境是 MinGW(Strawberry Perl 自带)
|
||||
# 保留 -g2 精简调试信息(避免体积过大),同时移除可能的优化选项
|
||||
string(REPLACE "-O2" "-O0" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "-O2" "-O0" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
add_compile_options(-g2) # 明确保留调试信息
|
||||
add_compile_options(-Wa,-mbig-obj) # 解决 MinGW 大文件限制(之前的问题)
|
||||
add_compile_options(-fno-omit-frame-pointer) # 帮助调试器定位栈帧
|
||||
|
||||
endif()
|
||||
|
||||
# 添加子目录,引用squirrel项目
|
||||
add_subdirectory(Library/squirrel)
|
||||
# 添加zlib子项目
|
||||
@@ -32,6 +42,8 @@ set(SDL2MIXER_DEPS_SHARED OFF CACHE BOOL "Compile vendored deps as static libs"
|
||||
set(SDL2MIXER_BUILD_SHARED OFF CACHE BOOL "Disable SDL2_mixer shared library" FORCE)
|
||||
set(SDL2MIXER_BUILD_STATIC ON CACHE BOOL "Enable SDL2_mixer static library" FORCE)
|
||||
set(SDL2MIXER_SAMPLES OFF CACHE BOOL "Disable SDL2_mixer examples (playmus/playwave)" FORCE)
|
||||
set(SDL2MIXER_VORBIS "VORBISFILE" CACHE STRING "Enable OGG via vorbisfile" FORCE)
|
||||
set(SDL2MIXER_VORBIS_VORBISFILE_SHARED OFF CACHE BOOL "Link vorbisfile statically" FORCE)
|
||||
add_subdirectory(Library/SDL_mixer)
|
||||
|
||||
set(SDL2NET_INSTALL OFF CACHE BOOL "Disable SDL2_net installation" FORCE)
|
||||
@@ -74,7 +86,7 @@ file(GLOB_RECURSE SOURCES
|
||||
)
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O1 -g" CACHE STRING "" FORCE)
|
||||
|
||||
|
||||
if (MINGW)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE
|
||||
@@ -112,8 +124,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
SDL2_ttf
|
||||
SDL2_net
|
||||
|
||||
zlibstatic # zlib库
|
||||
squirrel_static # squirrel库(根据实际目标名调整)
|
||||
zlibstatic
|
||||
squirrel_static
|
||||
sqstdlib_static
|
||||
|
||||
mingwex
|
||||
|
||||
1
Library/KoishiEx_MinGW
Submodule
1
Library/KoishiEx_MinGW
Submodule
Submodule Library/KoishiEx_MinGW added at df446b0a66
@@ -418,7 +418,8 @@ static void IME_Init(SDL_VideoData *videodata, HWND hwnd)
|
||||
if (WIN_ShouldShowNativeUI()) {
|
||||
videodata->ime_uiless = SDL_FALSE;
|
||||
} else {
|
||||
videodata->ime_uiless = UILess_SetupSinks(videodata);
|
||||
// videodata->ime_uiless = UILess_SetupSinks(videodata);
|
||||
videodata->ime_uiless = SDL_FALSE;
|
||||
}
|
||||
IME_UpdateInputLocale(videodata);
|
||||
IME_Disable(videodata, hwnd);
|
||||
|
||||
@@ -202,5 +202,41 @@
|
||||
},
|
||||
"source_game/Asset/Squirrel/Sqr_UI.hpp": {
|
||||
"description": "注册UI脚本"
|
||||
},
|
||||
"source_game/Asset/Squirrel/Sqr_CommonFunc.hpp": {
|
||||
"description": "通用工具函数"
|
||||
},
|
||||
"source_game/Asset/Squirrel/Sqr_System.hpp": {
|
||||
"description": "注册系统脚本"
|
||||
},
|
||||
"source_game/Asset/Squirrel/Sqr_Asset.hpp": {
|
||||
"description": "注册资源脚本"
|
||||
},
|
||||
"source/EngineFrame/Component/NumberText.h": {
|
||||
"description": "数字文本"
|
||||
},
|
||||
"source/EngineFrame/Attribute": {
|
||||
"description": "属性"
|
||||
},
|
||||
"source_game/Actor/Map/GameTown.h": {
|
||||
"description": "城镇类"
|
||||
},
|
||||
"source_game/Global/Script/TownConfig.h": {
|
||||
"description": "城镇配置信息"
|
||||
},
|
||||
"source_game/Actor/Map/GameWorld.h": {
|
||||
"description": "游戏世界类"
|
||||
},
|
||||
"source/EngineFrame/Component/AnimationMap.h": {
|
||||
"description": "动画组类"
|
||||
},
|
||||
"source/EngineFrame/Component/Animation.h": {
|
||||
"description": "动画类"
|
||||
},
|
||||
"source/EngineFrame/Component/Animation.cpp": {
|
||||
"description": "动画类"
|
||||
},
|
||||
"source/EngineFrame/Component/AnimationMap.cpp": {
|
||||
"description": "动画组类"
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ namespace AniScriptParser
|
||||
case 7:
|
||||
{
|
||||
Key = "IMAGE_RATE";
|
||||
VecFPos pos{
|
||||
Vec2 pos{
|
||||
blob.getFloat(),
|
||||
blob.getFloat()};
|
||||
FrameObject.Flag.emplace(Key, pos);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AniScriptParser
|
||||
int,
|
||||
float,
|
||||
VecPos,
|
||||
VecFPos,
|
||||
Vec2,
|
||||
std::string,
|
||||
std::vector<int>,
|
||||
std::vector<float>>;
|
||||
|
||||
306
source/Asset/Asset_Audio.hpp
Normal file
306
source/Asset/Asset_Audio.hpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include "rapidxml/rapidxml.hpp"
|
||||
|
||||
class AudioConfigReader
|
||||
{
|
||||
public:
|
||||
// --------------------------
|
||||
// 1. 结构体定义:放在类内public区,外部可通过 AudioConfigReader::SoundEffect 访问
|
||||
// --------------------------
|
||||
struct SoundEffect
|
||||
{
|
||||
std::string file_path; // 文件路径(FILE属性)
|
||||
int volume_adjust = 100; // 音量调整(默认100)
|
||||
int priority = 0; // 优先级(默认0)
|
||||
};
|
||||
|
||||
struct RandomItem
|
||||
{
|
||||
std::string tag; // 关联的音效ID(TAG属性)
|
||||
int prob = 0; // 概率(PROB属性)
|
||||
};
|
||||
|
||||
struct RandomSoundGroup
|
||||
{
|
||||
std::vector<RandomItem> items; // 组内所有项
|
||||
int delay = 0; // 延迟(DELAY属性)
|
||||
int loop_delay = 0; // 循环延迟
|
||||
int loop_delay_range = 0; // 循环延迟范围
|
||||
};
|
||||
|
||||
struct Music
|
||||
{
|
||||
std::string file_path; // 文件路径(FILE属性)
|
||||
int loop_delay = 0; // 循环延迟(LOOP_DELAY属性)
|
||||
};
|
||||
|
||||
public:
|
||||
// 构造函数:初始化解析器
|
||||
AudioConfigReader() = default;
|
||||
|
||||
// 析构函数:清理资源
|
||||
~AudioConfigReader() = default;
|
||||
|
||||
// 核心函数:解析XML文件(返回是否成功)
|
||||
bool LoadFromFile(const std::string &xml_path)
|
||||
{
|
||||
// 1. 读取XML文件内容
|
||||
std::ifstream file(xml_path, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw std::runtime_error("无法打开XML文件: " + xml_path);
|
||||
}
|
||||
std::string xml_content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
// 2. 解析XML
|
||||
rapidxml::xml_document<> doc;
|
||||
try
|
||||
{
|
||||
doc.parse<rapidxml::parse_default>(&xml_content[0]);
|
||||
}
|
||||
catch (const rapidxml::parse_error &e)
|
||||
{
|
||||
throw std::runtime_error("XML解析错误: " + std::string(e.what()) +
|
||||
"(位置: " + std::string(e.where<char>()) + ")");
|
||||
}
|
||||
|
||||
// 3. 获取根节点
|
||||
rapidxml::xml_node<> *root = doc.first_node("AudioTagDatabase");
|
||||
if (!root)
|
||||
{
|
||||
throw std::runtime_error("XML根节点错误: 找不到AudioTagDatabase");
|
||||
}
|
||||
|
||||
// 4. 解析所有节点
|
||||
ParseEffects(root); // 解析<EFFECT>
|
||||
ParseRandomGroups(root); // 解析<RANDOM>
|
||||
ParseMusics(root); // 解析<MUSIC>
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口1:获取音效配置(<EFFECT>)
|
||||
// ------------------------------
|
||||
bool HasEffect(const std::string &effect_id) const
|
||||
{
|
||||
return m_effects.find(effect_id) != m_effects.end();
|
||||
}
|
||||
|
||||
const SoundEffect &GetEffect(const std::string &effect_id) const
|
||||
{
|
||||
auto it = m_effects.find(effect_id);
|
||||
if (it == m_effects.end())
|
||||
{
|
||||
throw std::out_of_range("音效ID不存在: " + effect_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有音效ID列表
|
||||
std::vector<std::string> GetAllEffectIds() const
|
||||
{
|
||||
return GetAllKeys(m_effects);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口2:获取随机音效组配置(<RANDOM>)
|
||||
// ------------------------------
|
||||
bool HasRandomGroup(const std::string &group_id) const
|
||||
{
|
||||
return m_random_groups.find(group_id) != m_random_groups.end();
|
||||
}
|
||||
|
||||
const RandomSoundGroup &GetRandomGroup(const std::string &group_id) const
|
||||
{
|
||||
auto it = m_random_groups.find(group_id);
|
||||
if (it == m_random_groups.end())
|
||||
{
|
||||
throw std::out_of_range("随机组ID不存在: " + group_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有随机组ID列表
|
||||
std::vector<std::string> GetAllRandomGroupIds() const
|
||||
{
|
||||
return GetAllKeys(m_random_groups);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 接口3:获取背景音乐配置(<MUSIC>)
|
||||
// ------------------------------
|
||||
bool HasMusic(const std::string &music_id) const
|
||||
{
|
||||
return m_musics.find(music_id) != m_musics.end();
|
||||
}
|
||||
|
||||
const Music &GetMusic(const std::string &music_id) const
|
||||
{
|
||||
auto it = m_musics.find(music_id);
|
||||
if (it == m_musics.end())
|
||||
{
|
||||
throw std::out_of_range("背景音乐ID不存在: " + music_id);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 获取所有背景音乐ID列表
|
||||
std::vector<std::string> GetAllMusicIds() const
|
||||
{
|
||||
return GetAllKeys(m_musics);
|
||||
}
|
||||
|
||||
private:
|
||||
// 辅助函数:解析<EFFECT>节点
|
||||
void ParseEffects(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("EFFECT");
|
||||
node; node = node->next_sibling("EFFECT"))
|
||||
{
|
||||
|
||||
// 必选属性:ID和FILE
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
|
||||
if (!id_attr || !file_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
SoundEffect effect;
|
||||
effect.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
|
||||
|
||||
// 可选属性:VOLUME_ADJUST
|
||||
if (auto attr = node->first_attribute("VOLUME_ADJUST"))
|
||||
{
|
||||
effect.volume_adjust = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
// 可选属性:PRIORITY
|
||||
if (auto attr = node->first_attribute("PRIORITY"))
|
||||
{
|
||||
effect.priority = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
m_effects[id_attr->value()] = effect;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:解析<RANDOM>节点
|
||||
void ParseRandomGroups(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("RANDOM");
|
||||
node; node = node->next_sibling("RANDOM"))
|
||||
{
|
||||
|
||||
// 必选属性:ID
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
if (!id_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
RandomSoundGroup group;
|
||||
|
||||
// 可选属性:延迟相关
|
||||
if (auto attr = node->first_attribute("DELAY"))
|
||||
{
|
||||
group.delay = std::stoi(attr->value());
|
||||
}
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY"))
|
||||
{
|
||||
group.loop_delay = std::stoi(attr->value());
|
||||
}
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY_RANGE"))
|
||||
{
|
||||
group.loop_delay_range = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
// 解析子节点<ITEM>
|
||||
for (rapidxml::xml_node<> *item_node = node->first_node("ITEM");
|
||||
item_node; item_node = item_node->next_sibling("ITEM"))
|
||||
{
|
||||
|
||||
rapidxml::xml_attribute<> *tag_attr = item_node->first_attribute("TAG");
|
||||
rapidxml::xml_attribute<> *prob_attr = item_node->first_attribute("PROB");
|
||||
if (!tag_attr || !prob_attr)
|
||||
{
|
||||
continue; // 跳过无效项
|
||||
}
|
||||
|
||||
group.items.push_back({tag_attr->value(),
|
||||
std::stoi(prob_attr->value())});
|
||||
}
|
||||
|
||||
m_random_groups[id_attr->value()] = group;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:解析<MUSIC>节点
|
||||
void ParseMusics(rapidxml::xml_node<> *root)
|
||||
{
|
||||
for (rapidxml::xml_node<> *node = root->first_node("MUSIC");
|
||||
node; node = node->next_sibling("MUSIC"))
|
||||
{
|
||||
|
||||
// 必选属性:ID和FILE
|
||||
rapidxml::xml_attribute<> *id_attr = node->first_attribute("ID");
|
||||
rapidxml::xml_attribute<> *file_attr = node->first_attribute("FILE");
|
||||
if (!id_attr || !file_attr)
|
||||
{
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
Music music;
|
||||
music.file_path = NormalizePath(file_attr->value()); // 统一路径分隔符
|
||||
|
||||
// 可选属性:LOOP_DELAY
|
||||
if (auto attr = node->first_attribute("LOOP_DELAY"))
|
||||
{
|
||||
music.loop_delay = std::stoi(attr->value());
|
||||
}
|
||||
|
||||
m_musics[id_attr->value()] = music;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:统一路径分隔符(将\转为/,兼容跨平台)
|
||||
std::string NormalizePath(const std::string &path)
|
||||
{
|
||||
std::string normalized = path;
|
||||
for (char &c : normalized)
|
||||
{
|
||||
if (c == '\\')
|
||||
{
|
||||
c = '/';
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// 辅助函数:获取哈希表中所有key
|
||||
template <typename Map>
|
||||
std::vector<std::string> GetAllKeys(const Map &map) const
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
keys.reserve(map.size());
|
||||
for (const auto &pair : map)
|
||||
{
|
||||
keys.push_back(pair.first);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private:
|
||||
// 存储解析后的数据
|
||||
std::unordered_map<std::string, SoundEffect> m_effects; // 音效映射(ID -> 音效)
|
||||
std::unordered_map<std::string, RandomSoundGroup> m_random_groups; // 随机组映射(ID -> 随机组)
|
||||
std::unordered_map<std::string, Music> m_musics; // 背景音乐映射(ID -> 音乐)
|
||||
};
|
||||
233
source/Asset/Asset_SoundPack.cpp
Normal file
233
source/Asset/Asset_SoundPack.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "Asset_SoundPack.h"
|
||||
Asset_SoundPack::Asset_SoundPack()
|
||||
{
|
||||
int device = -1; // 使用默认设备
|
||||
unsigned long freq = 44100; // 采样频率,PCM常用的采样率之一,可以按需调整
|
||||
|
||||
// 构造NPK信息
|
||||
InitNpkList();
|
||||
// 解析audio.xml
|
||||
XmlConfig.LoadFromFile("audio.xml");
|
||||
|
||||
// 初始化SDL_mixer,支持OGG格式
|
||||
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
|
||||
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 8192) < 0)
|
||||
{
|
||||
SDL_LogError(0, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
|
||||
}
|
||||
if (Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG) < 0)
|
||||
{
|
||||
SDL_LogError(0, "Mix_Init failed: %s\n", Mix_GetError());
|
||||
}
|
||||
// 分配通道
|
||||
ChannelCount = Mix_AllocateChannels(64);
|
||||
SetAllChannelVolume(0);
|
||||
}
|
||||
|
||||
Asset_SoundPack::~Asset_SoundPack()
|
||||
{
|
||||
}
|
||||
|
||||
void Asset_SoundPack::InitNpkList()
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
std::string path = "SoundPacks/";
|
||||
dir = opendir(path.c_str());
|
||||
|
||||
while ((ent = readdir(dir)))
|
||||
{
|
||||
// 跳过.和..目录
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
std::string RealPath = path + ent->d_name;
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(RealPath.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
std::string Header = Fs.ReadString();
|
||||
// 如果是NPK
|
||||
if (Header == "NeoplePack_Bill")
|
||||
{
|
||||
// 读取img数量
|
||||
int ImageCount = Fs.ReadInt();
|
||||
|
||||
for (int i = 0; i < ImageCount; ++i)
|
||||
{
|
||||
// 直接读取当前项的偏移、长度和路径
|
||||
auto offset = Fs.ReadUnsignedInt();
|
||||
auto length = Fs.ReadUnsignedInt();
|
||||
auto path = Fs.ReadInfo();
|
||||
|
||||
// 构造 WAV 并插入映射表
|
||||
lp_arr[path] = WAV{
|
||||
offset, // offset
|
||||
length, // size
|
||||
path, // lpWavName(直接复用读取的path)
|
||||
RealPath, // lpBelongsFile
|
||||
i // img_index
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void Asset_SoundPack::Reclaims()
|
||||
{
|
||||
}
|
||||
|
||||
Mix_Chunk *Asset_SoundPack::GetOgg(const std::string &lpWavName)
|
||||
{
|
||||
|
||||
if (map_sound.find(lpWavName) != map_sound.end())
|
||||
{
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return map_sound[lpWavName].lpMusic;
|
||||
}
|
||||
// 在NPK映射表中找到
|
||||
if (lp_arr.find(lpWavName) != lp_arr.end())
|
||||
{
|
||||
WAV &wav = lp_arr[lpWavName];
|
||||
if (wav.lpBelongsFile.empty())
|
||||
return nullptr;
|
||||
Ifstream_NPK Fs;
|
||||
Fs.open(wav.lpBelongsFile.c_str(), std::ios::in | std::ios::binary);
|
||||
if (Fs.is_open())
|
||||
{
|
||||
Fs.seekg(wav.offset, std::ios::beg);
|
||||
auto buffer = Fs.ReadCustomSize(wav.size);
|
||||
SDL_RWops *rw = SDL_RWFromConstMem(buffer, wav.size);
|
||||
if (!rw)
|
||||
{
|
||||
SDL_Log("创建内存流失败: %s\n", SDL_GetError());
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
Mix_Chunk *music = Mix_LoadWAV_RW(rw, 0);
|
||||
if (!music)
|
||||
{
|
||||
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
|
||||
SDL_RWclose(rw); // 手动关闭流
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
map_sound[lpWavName].lpMusic = music;
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return music;
|
||||
}
|
||||
}
|
||||
// 去Music文件夹中寻找
|
||||
else
|
||||
{
|
||||
Mix_Chunk *music = Mix_LoadWAV(lpWavName.c_str());
|
||||
if (!music)
|
||||
{
|
||||
SDL_Log("加载OGG失败: %s\n", Mix_GetError());
|
||||
Mix_CloseAudio();
|
||||
SDL_Quit();
|
||||
return nullptr;
|
||||
}
|
||||
map_sound[lpWavName].lpMusic = music;
|
||||
map_sound[lpWavName].LastUseTime = SDL_GetTicks64();
|
||||
return music;
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayAudio(const std::string Key)
|
||||
{
|
||||
std::string RealKey = Key;
|
||||
// 先判断是不是随机组 如果是随机组去里面调出真正要播放的Key
|
||||
if (XmlConfig.HasRandomGroup(Key))
|
||||
{
|
||||
auto Group = XmlConfig.GetRandomGroup(Key);
|
||||
int RandNum = rand() % 100;
|
||||
for (auto &item : Group.items)
|
||||
{
|
||||
if (RandNum <= item.prob)
|
||||
{
|
||||
RealKey = item.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是特效音频
|
||||
if (XmlConfig.HasEffect(Key))
|
||||
{
|
||||
std::string oggPath = XmlConfig.GetEffect(Key).file_path;
|
||||
int volume = XmlConfig.GetEffect(Key).volume_adjust;
|
||||
PlayEffect(oggPath, volume);
|
||||
}
|
||||
// 如果是背景音乐
|
||||
else if (XmlConfig.HasMusic(Key))
|
||||
{
|
||||
std::string oggPath = XmlConfig.GetMusic(Key).file_path;
|
||||
PlayMusic(Key, oggPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(0, "找不到音频: %s\n", Key.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::StopAudio(const std::string Key)
|
||||
{
|
||||
StopChannel(backgroud_music_map[Key]);
|
||||
backgroud_music_map.erase(Key);
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayMusic(const std::string Key, const std::string oggpath)
|
||||
{
|
||||
auto ogg = GetOgg(oggpath);
|
||||
if (ogg)
|
||||
{
|
||||
int channel = FindFreeChannelInRange(0, 4);
|
||||
backgroud_music_map[Key] = Mix_PlayChannel(channel, ogg, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::PlayEffect(const std::string Key, int Volume)
|
||||
{
|
||||
auto ogg = GetOgg(Key);
|
||||
if (ogg)
|
||||
{
|
||||
int channel = FindFreeChannelInRange(4, ChannelCount - 1);
|
||||
Mix_VolumeChunk(ogg, Volume);
|
||||
Mix_PlayChannel(channel, ogg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Asset_SoundPack::StopChannel(int Channel)
|
||||
{
|
||||
Mix_HaltChannel(Channel); // 停止指定通道的音效
|
||||
}
|
||||
|
||||
void Asset_SoundPack::SetAllChannelVolume(int Volume)
|
||||
{
|
||||
Mix_Volume(-1, Volume);
|
||||
}
|
||||
|
||||
std::map<std::string, int> Asset_SoundPack::GetBackgroudMusicVector()
|
||||
{
|
||||
return backgroud_music_map;
|
||||
}
|
||||
|
||||
int Asset_SoundPack::FindFreeChannelInRange(int startChannel, int endChannel)
|
||||
{
|
||||
// 遍历通道(若总通道数小于32,则只检查到最后一个通道)
|
||||
for (int channel = startChannel; channel <= endChannel; channel++)
|
||||
{
|
||||
// 检查通道是否空闲(Mix_Playing返回0表示空闲)
|
||||
if (Mix_Playing(channel) == 0)
|
||||
{
|
||||
return channel; // 返回第一个空闲通道
|
||||
}
|
||||
}
|
||||
|
||||
// 若所有通道都在使用中
|
||||
return -1;
|
||||
}
|
||||
88
source/Asset/Asset_SoundPack.h
Normal file
88
source/Asset/Asset_SoundPack.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include "Tool/Ifstream_NPK.h"
|
||||
#include "Asset/Asset_Audio.hpp"
|
||||
|
||||
class Asset_SoundPack
|
||||
{
|
||||
public:
|
||||
struct WAV
|
||||
{
|
||||
unsigned int offset; // 偏移
|
||||
unsigned int size; // 大小
|
||||
std::string lpWavName; // img文件的路径
|
||||
std::string lpBelongsFile; // 这个img属于哪个npk文件
|
||||
int img_index; // img文件在npk文件里的序号
|
||||
};
|
||||
|
||||
struct NpkInfo
|
||||
{
|
||||
int Offset;
|
||||
int Length;
|
||||
std::string Path;
|
||||
};
|
||||
|
||||
struct MusicInfo
|
||||
{
|
||||
/**上次使用时间 */
|
||||
Uint64 LastUseTime;
|
||||
/**音频指针 */
|
||||
Mix_Chunk *lpMusic;
|
||||
};
|
||||
|
||||
public:
|
||||
Asset_SoundPack(const Asset_SoundPack &) = delete;
|
||||
Asset_SoundPack &operator=(const Asset_SoundPack &) = delete;
|
||||
Asset_SoundPack(Asset_SoundPack &&) = delete;
|
||||
Asset_SoundPack &operator=(Asset_SoundPack &&) = delete;
|
||||
// 全局访问点
|
||||
static Asset_SoundPack &GetInstance()
|
||||
{
|
||||
static Asset_SoundPack instance; // 局部静态变量,保证只初始化一次
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**音频NPK信息表 */
|
||||
std::map<std::string, WAV> lp_arr;
|
||||
/**音频储存表 */
|
||||
std::map<std::string, MusicInfo> map_sound;
|
||||
/**audio信息表 */
|
||||
AudioConfigReader XmlConfig;
|
||||
/**正在播放的背景音乐表 */
|
||||
std::map<std::string, int> backgroud_music_map;
|
||||
/**总通道数 */
|
||||
int ChannelCount;
|
||||
|
||||
public:
|
||||
Asset_SoundPack(/* args */);
|
||||
~Asset_SoundPack();
|
||||
|
||||
void InitNpkList();
|
||||
|
||||
void Reclaims();
|
||||
|
||||
Mix_Chunk *GetOgg(const std::string &lpWavName);
|
||||
|
||||
/**播放音频 */
|
||||
void PlayAudio(const std::string Key);
|
||||
/**停止音频 */
|
||||
void StopAudio(const std::string Key);
|
||||
|
||||
void PlayMusic(const std::string Key, const std::string oggpath);
|
||||
void PlayEffect(const std::string Key, int Volume);
|
||||
|
||||
/**停止通道播放音频 */
|
||||
void StopChannel(int Channel);
|
||||
/**设置所有通道音量 */
|
||||
void SetAllChannelVolume(int Volume);
|
||||
/**获取正在播放的背景音乐 */
|
||||
std::map<std::string, int> GetBackgroudMusicVector();
|
||||
|
||||
/**获取空闲的通道 */
|
||||
int FindFreeChannelInRange(int Start, int End);
|
||||
};
|
||||
2596
source/Asset/rapidxml/rapidxml.hpp
Normal file
2596
source/Asset/rapidxml/rapidxml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
174
source/Asset/rapidxml/rapidxml_iterators.hpp
Normal file
174
source/Asset/rapidxml/rapidxml_iterators.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
421
source/Asset/rapidxml/rapidxml_print.hpp
Normal file
421
source/Asset/rapidxml/rapidxml_print.hpp
Normal file
@@ -0,0 +1,421 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
122
source/Asset/rapidxml/rapidxml_utils.hpp
Normal file
122
source/Asset/rapidxml/rapidxml_utils.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "Game.h"
|
||||
#include "squirrel/SquirrelEx.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include "Asset/Asset_SoundPack.h"
|
||||
|
||||
Game::Game()
|
||||
{
|
||||
@@ -25,6 +26,11 @@ void Game::Init(std::function<void()> CallBack)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // 双缓冲
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); // 24位深度缓冲(避免z-fighting)
|
||||
|
||||
// 启用多重采样(关键步骤)
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // 启用多重采样缓冲
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
||||
{
|
||||
@@ -39,6 +45,7 @@ void Game::Init(std::function<void()> CallBack)
|
||||
}
|
||||
// 关闭原生鼠标
|
||||
SDL_ShowCursor(0);
|
||||
|
||||
// 打开所有检测到的控制器
|
||||
int numControllers = SDL_NumJoysticks();
|
||||
for (int i = 0; i < numControllers; i++)
|
||||
@@ -61,13 +68,6 @@ void Game::Init(std::function<void()> CallBack)
|
||||
|
||||
IMG_Init(IMG_INIT_PNG);
|
||||
|
||||
// 初始化SDL_mixer,支持OGG格式
|
||||
// 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小
|
||||
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError());
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
||||
// 初始化 TTF
|
||||
if (TTF_Init() == -1)
|
||||
@@ -112,6 +112,7 @@ void Game::Run()
|
||||
// 延迟后,重新计算从帧开始到现在的总时间(包含可能的延迟误差)
|
||||
Uint64 actualFrameTime = SDL_GetTicks64() - frameStart;
|
||||
m_deltaTime = actualFrameTime / 1000.0f; // 用实际总时间更新deltaTime
|
||||
m_frameTime_ms = actualFrameTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,9 +151,16 @@ void Game::HandleEvents(SDL_Event *e)
|
||||
|
||||
void Game::Update(float deltaTime)
|
||||
{
|
||||
//调用松鼠的更新
|
||||
// 内存回收机制
|
||||
m_lastMemoryPrintTime += deltaTime;
|
||||
if (m_lastMemoryPrintTime >= m_memoryPrintInterval)
|
||||
{
|
||||
m_lastMemoryPrintTime = 0;
|
||||
MemoryReclaims();
|
||||
}
|
||||
// 调用松鼠的更新
|
||||
SquirrelEx::GetInstance().Update(deltaTime);
|
||||
if (m_scene != nullptr)
|
||||
if (m_scene != nullptr)
|
||||
m_scene->Update(deltaTime);
|
||||
if (m_uiScene != nullptr)
|
||||
m_uiScene->Update(deltaTime);
|
||||
@@ -160,9 +168,6 @@ void Game::Update(float deltaTime)
|
||||
|
||||
void Game::Render()
|
||||
{
|
||||
// 绘制调用次数清0
|
||||
m_RenderCount = 0;
|
||||
|
||||
// 调用预渲染
|
||||
if (m_scene != nullptr)
|
||||
m_scene->PreRender();
|
||||
@@ -172,9 +177,15 @@ void Game::Render()
|
||||
// 清空渲染器后渲染
|
||||
m_renderer->ClearScreen();
|
||||
if (m_scene != nullptr)
|
||||
{
|
||||
m_renderer->SetOrthoMatrixType(0);
|
||||
m_scene->Render();
|
||||
}
|
||||
if (m_uiScene != nullptr)
|
||||
{
|
||||
m_renderer->SetOrthoMatrixType(1);
|
||||
m_uiScene->Render();
|
||||
}
|
||||
m_renderer->SwapBuffer();
|
||||
}
|
||||
|
||||
@@ -195,6 +206,12 @@ void Game::Clear()
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Game::MemoryReclaims()
|
||||
{
|
||||
// 音频内存回收
|
||||
Asset_SoundPack::GetInstance().Reclaims();
|
||||
}
|
||||
|
||||
void Game::ChangeScene(RefPtr<Scene> scene)
|
||||
{
|
||||
if (m_scene != nullptr)
|
||||
@@ -215,6 +232,11 @@ void Game::ChangeUIScene(RefPtr<Scene> scene)
|
||||
m_uiScene->Enter();
|
||||
}
|
||||
|
||||
RefPtr<Scene> Game::GetScene()
|
||||
{
|
||||
return m_scene;
|
||||
}
|
||||
|
||||
RenderManager *Game::GetRenderer()
|
||||
{
|
||||
return m_renderer;
|
||||
|
||||
@@ -51,17 +51,16 @@ public:
|
||||
void Render();
|
||||
void Clear();
|
||||
|
||||
void MemoryReclaims();
|
||||
|
||||
// 切换场景
|
||||
void ChangeScene(RefPtr<Scene> scene);
|
||||
// 设定UI层场景对象
|
||||
void ChangeUIScene(RefPtr<Scene> scene);
|
||||
// 获取当前游戏层场景
|
||||
RefPtr<Scene> GetScene();
|
||||
|
||||
RenderManager* GetRenderer();
|
||||
|
||||
// 每秒帧率
|
||||
u32 m_fps;
|
||||
// 每帧绘制调用次数
|
||||
u32 m_RenderCount = 0;
|
||||
RenderManager *GetRenderer();
|
||||
|
||||
private:
|
||||
// 构造函数和析构函数设为私有,防止外部创建和销毁
|
||||
@@ -73,7 +72,7 @@ private:
|
||||
// 窗口
|
||||
SDL_Window *m_window;
|
||||
// 渲染器
|
||||
RenderManager* m_renderer;
|
||||
RenderManager *m_renderer;
|
||||
|
||||
// 游戏层场景
|
||||
RefPtr<Scene> m_scene;
|
||||
@@ -82,22 +81,31 @@ private:
|
||||
|
||||
// 帧数
|
||||
#ifdef __SWITCH__
|
||||
float m_Settingfps = 60.0;
|
||||
float m_Settingfps = 5000.0;
|
||||
#else
|
||||
float m_Settingfps = 144.0;
|
||||
#endif
|
||||
// 单帧时间
|
||||
float m_frameTime = 0.f;
|
||||
// 每秒内的帧数计数器
|
||||
u32 m_frameCounter;
|
||||
// 上一次输出帧率的时间
|
||||
u32 m_lastFpsPrintTime;
|
||||
|
||||
// 帧间隔
|
||||
float m_deltaTime = 0.f;
|
||||
// 每秒内的帧数计数器
|
||||
u32 m_frameCounter;
|
||||
u32 m_lastFpsPrintTime;
|
||||
// 内存回收计时器
|
||||
u32 m_lastMemoryPrintTime = 0;
|
||||
// 内存回收间隔
|
||||
u32 m_memoryPrintInterval = 5000;
|
||||
|
||||
public:
|
||||
// 屏幕宽高
|
||||
int Screen_W = 1280;
|
||||
int Screen_H = 720;
|
||||
|
||||
// 每秒帧率
|
||||
u32 m_fps;
|
||||
// 单帧时间
|
||||
u32 m_frameTime_ms;
|
||||
// 节点个数
|
||||
u32 m_nodeCount = 0;
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/BaseNode.h"
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
class Scene;
|
||||
/**
|
||||
* @brief Actor类,继承自Actor_base类
|
||||
*
|
||||
* Actor类是一个基础的游戏对象类,可以添加到场景中
|
||||
*/
|
||||
class Actor : public BaseNode
|
||||
{
|
||||
private:
|
||||
//裁切视口Flag
|
||||
bool _CropViewportFlag = false;
|
||||
//裁切视口
|
||||
SDL_Rect _CropViewport = {0, 0, 0, 0};
|
||||
|
||||
public:
|
||||
Actor();
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
void Render() override;
|
||||
void AddComponent(RefPtr<Component> Component);
|
||||
void RemoveComponent(RefPtr<Component> Component);
|
||||
|
||||
// 设置裁切视口(放在Actor里 他与他的子对象都会被裁切)
|
||||
void SetCropViewport(SDL_Rect CropViewport);
|
||||
// 获取裁切视口
|
||||
SDL_Rect GetCropViewport();
|
||||
};
|
||||
26
source/EngineFrame/Attribute/Bits.h
Normal file
26
source/EngineFrame/Attribute/Bits.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
namespace bits
|
||||
{
|
||||
template <typename _Ty>
|
||||
inline void Set(_Ty &old, _Ty flag)
|
||||
{
|
||||
static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
|
||||
old |= flag;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
inline void Unset(_Ty &old, _Ty flag)
|
||||
{
|
||||
static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
|
||||
old &= ~flag;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
inline bool Has(_Ty old, _Ty flag)
|
||||
{
|
||||
static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
|
||||
return !!(old & flag);
|
||||
}
|
||||
}
|
||||
57
source/EngineFrame/Attribute/Flag.h
Normal file
57
source/EngineFrame/Attribute/Flag.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include <cstdint> // uint8_t
|
||||
#include "Bits.h"
|
||||
template <typename _Ty>
|
||||
class Flag
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
|
||||
|
||||
typedef _Ty value_type;
|
||||
|
||||
_Ty value;
|
||||
|
||||
inline Flag()
|
||||
: value()
|
||||
{
|
||||
}
|
||||
|
||||
inline Flag(_Ty value)
|
||||
: value(value)
|
||||
{
|
||||
}
|
||||
|
||||
inline void Set(_Ty value)
|
||||
{
|
||||
bits::Set(this->value, value);
|
||||
}
|
||||
|
||||
inline void Unset(_Ty value)
|
||||
{
|
||||
bits::Unset(this->value, value);
|
||||
}
|
||||
|
||||
inline bool Has(_Ty value) const
|
||||
{
|
||||
return bits::Has(this->value, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
struct IsFlag : public std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
struct IsFlag<Flag<_Ty>> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
typedef Flag<uint8_t> FlagUint8;
|
||||
typedef Flag<uint16_t> FlagUint16;
|
||||
typedef Flag<uint32_t> FlagUint32;
|
||||
typedef Flag<uint64_t> FlagUint64;
|
||||
typedef Flag<int8_t> FlagInt8;
|
||||
typedef Flag<int16_t> FlagInt16;
|
||||
typedef Flag<int32_t> FlagInt32;
|
||||
typedef Flag<int64_t> FlagInt64;
|
||||
61
source/EngineFrame/Attribute/Y_Transform.cpp
Normal file
61
source/EngineFrame/Attribute/Y_Transform.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "Y_Transform.h"
|
||||
#include <cmath>
|
||||
Y_Transform::Y_Transform() : position(0.f, 0.f), scale(1.0f, 1.0f), skew(0.f, 0.f), rotation(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Matrix3x2 Y_Transform::ToMatrix() const
|
||||
{
|
||||
// 将角度转换为弧度
|
||||
float rotRad = glm::radians(rotation);
|
||||
float skewXRad = glm::radians(skew.x);
|
||||
float skewYRad = glm::radians(skew.y);
|
||||
|
||||
// 计算旋转的正弦和余弦
|
||||
float cosRot = std::cos(rotRad);
|
||||
float sinRot = std::sin(rotRad);
|
||||
|
||||
// 计算错切的正切值
|
||||
float tanSkewX = std::tan(skewXRad);
|
||||
float tanSkewY = std::tan(skewYRad);
|
||||
|
||||
// 构造基础变换矩阵(缩放 × 错切 × 旋转的组合)
|
||||
// 注意:矩阵乘法顺序为 旋转 × 错切 × 缩放(从右向左应用)
|
||||
float m00 = scale.x * (cosRot - sinRot * tanSkewY);
|
||||
float m01 = scale.y * (-sinRot + cosRot * tanSkewX);
|
||||
float m10 = scale.x * (sinRot + cosRot * tanSkewY);
|
||||
float m11 = scale.y * (cosRot + sinRot * tanSkewX);
|
||||
|
||||
// 平移分量
|
||||
float tx = position.x;
|
||||
float ty = position.y;
|
||||
|
||||
// 构造并返回 3x2 矩阵(假设 Matrix3x2 可通过此方式初始化)
|
||||
return Matrix3x2(m00, m01, m10, m11, tx, ty);
|
||||
}
|
||||
|
||||
glm::mat4 Y_Transform::GetTransformMatrix() const
|
||||
{
|
||||
// 缩放矩阵(Scale)
|
||||
glm::mat4 scaleMat = glm::mat4(1.0f); // 单位矩阵
|
||||
scaleMat[0][0] = scale.x; // x轴缩放
|
||||
scaleMat[1][1] = scale.y; // y轴缩放
|
||||
|
||||
// 错切矩阵(Skew):先将角度转为弧度
|
||||
float skewX = glm::radians(skew.x); // 沿y轴错切角度(x方向倾斜)
|
||||
float skewY = glm::radians(skew.y); // 沿x轴错切角度(y方向倾斜)
|
||||
glm::mat4 skewMat = glm::mat4(1.0f);
|
||||
skewMat[0][1] = tan(skewX); // x方向错切因子(影响y轴)
|
||||
skewMat[1][0] = tan(skewY); // y方向错切因子(影响x轴)
|
||||
|
||||
// 旋转矩阵(Rotation):绕z轴旋转,角度转弧度
|
||||
float rotRad = glm::radians(rotation);
|
||||
glm::mat4 rotMat = glm::rotate(glm::mat4(1.0f), rotRad, glm::vec3(0, 0, 1));
|
||||
|
||||
// 平移矩阵(Translation)
|
||||
glm::mat4 transMat = glm::translate(glm::mat4(1.0f), glm::vec3(position, 0.0f));
|
||||
|
||||
// 组合变换矩阵:平移 × 旋转 × 错切 × 缩放(注意乘法顺序,从右向左应用)
|
||||
return transMat * rotMat * skewMat * scaleMat;
|
||||
}
|
||||
26
source/EngineFrame/Attribute/Y_Transform.h
Normal file
26
source/EngineFrame/Attribute/Y_Transform.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "math/Math.h"
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
class Y_Transform
|
||||
{
|
||||
public:
|
||||
float rotation; ///< 旋转
|
||||
glm::vec2 position; ///< 坐标
|
||||
glm::vec2 scale; ///< 缩放
|
||||
glm::vec2 skew; ///< 错切角度
|
||||
|
||||
public:
|
||||
Y_Transform(/* args */);
|
||||
|
||||
bool IsFast() const
|
||||
{
|
||||
return skew.x == 0.f && skew.y == 0.f &&
|
||||
scale.x == 1.f && scale.y == 1.f &&
|
||||
rotation == 0.f;
|
||||
}
|
||||
|
||||
Matrix3x2 ToMatrix() const;
|
||||
glm::mat4 GetTransformMatrix() const;
|
||||
};
|
||||
@@ -1,21 +1,26 @@
|
||||
#include "Actor.h"
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "EngineFrame/Component/RenderBase.h"
|
||||
#include "EngineFrame/Render/RenderManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
Actor::Actor()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Actor::Init()
|
||||
{
|
||||
addTag(Tag::ACTOR);
|
||||
addTag(Tag::RENDER);
|
||||
addTag(Tag::TRANSFORM);
|
||||
addTag(Tag::UPDATE);
|
||||
}
|
||||
|
||||
void Actor::OnAdded(Actor *node)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Actor::SetBlendMode(LE_BlEND_MODE mode)
|
||||
{
|
||||
this->_BlendMode = mode;
|
||||
}
|
||||
|
||||
LE_BlEND_MODE Actor::GetBlendMode()
|
||||
{
|
||||
return this->_BlendMode;
|
||||
}
|
||||
|
||||
void Actor::Render()
|
||||
@@ -25,25 +30,15 @@ void Actor::Render()
|
||||
{
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
renderer->SetClipRect(&this->_CropViewport);
|
||||
BaseNode::Render();
|
||||
Node::Render();
|
||||
renderer->CloseClipRect();
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseNode::Render();
|
||||
Node::Render();
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::AddComponent(RefPtr<Component> Component)
|
||||
{
|
||||
BaseNode::AddChild(Component);
|
||||
}
|
||||
|
||||
void Actor::RemoveComponent(RefPtr<Component> Component)
|
||||
{
|
||||
BaseNode::RemoveChild(Component);
|
||||
}
|
||||
|
||||
void Actor::SetCropViewport(SDL_Rect CropViewport)
|
||||
{
|
||||
if (CropViewport.x == 0 && CropViewport.y == 0 && CropViewport.w == 0 && CropViewport.h == 0)
|
||||
37
source/EngineFrame/Base/Actor.h
Normal file
37
source/EngineFrame/Base/Actor.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/Node.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
class Scene;
|
||||
/**
|
||||
* @brief Actor类,继承自Actor_base类
|
||||
*
|
||||
* Actor类是一个基础的游戏对象类,可以添加到场景中
|
||||
*/
|
||||
class Actor : public Node
|
||||
{
|
||||
protected:
|
||||
/**裁切视口Flag */
|
||||
bool _CropViewportFlag = false;
|
||||
/**裁切视口 */
|
||||
SDL_Rect _CropViewport = {0, 0, 0, 0};
|
||||
/**混合模式 */
|
||||
LE_BlEND_MODE _BlendMode = NONE;
|
||||
|
||||
public:
|
||||
// 初始化
|
||||
virtual void Init();
|
||||
// 被添加时
|
||||
virtual void OnAdded(Actor *node);
|
||||
// 设置混合模式
|
||||
void SetBlendMode(LE_BlEND_MODE mode);
|
||||
// 获取混合模式
|
||||
LE_BlEND_MODE GetBlendMode();
|
||||
public:
|
||||
/**重载渲染函数 */
|
||||
void Render() override;
|
||||
|
||||
/**设置裁切视口(放在Actor里 他与他的子对象都会被裁切) */
|
||||
void SetCropViewport(SDL_Rect CropViewport);
|
||||
/**获取裁切视口 */
|
||||
SDL_Rect GetCropViewport();
|
||||
};
|
||||
@@ -1,341 +0,0 @@
|
||||
#include "BaseNode.h"
|
||||
|
||||
void BaseNode::Init()
|
||||
{
|
||||
}
|
||||
void BaseNode::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
// 如果有子节点并含有事件标签,则处理事件
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->hasTag(Tag::ACTOR) || child->hasTag(Tag::HANDEL_EVENT))
|
||||
child->HandleEvents(e);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::Update(float deltaTime)
|
||||
{
|
||||
// 如果有回调函数,则调用回调函数
|
||||
if (cb_update_)
|
||||
{
|
||||
cb_update_(deltaTime);
|
||||
}
|
||||
// 如果有子节点并含有刷新标签,则更新子节点
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->hasTag(Tag::UPDATE))
|
||||
child->Update(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::PreRender()
|
||||
{
|
||||
// 如果有子节点并含有渲染标签,则渲染子节点
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->hasTag(Tag::RENDER))
|
||||
child->PreRender();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::Render()
|
||||
{
|
||||
// 如果有子节点并含有渲染标签,则渲染子节点
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->hasTag(Tag::RENDER))
|
||||
child->Render();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseNode::SetCallbackOnUpdate(const UpdateCallback &cb)
|
||||
{
|
||||
cb_update_ = cb;
|
||||
}
|
||||
|
||||
void BaseNode::SetChildIterationTransform()
|
||||
{
|
||||
TransformT n_transform;
|
||||
n_transform.position = transform.position + transformIter.position;
|
||||
n_transform.scale = transform.scale * transformIter.scale;
|
||||
n_transform.rotation = transform.rotation + transformIter.rotation;
|
||||
|
||||
// 如果有子节点并含有transform标签,则设置其位置
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->hasTag(Tag::TRANSFORM))
|
||||
child->SetIterationTransform(n_transform);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::CalcRenderInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseNode::SetName(std::string name)
|
||||
{
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
std::string BaseNode::GetName()
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
int BaseNode::GetRenderZOrder()
|
||||
{
|
||||
return m_RenderZOrder;
|
||||
}
|
||||
|
||||
void BaseNode::SetRenderZOrder(int zOrder)
|
||||
{
|
||||
m_RenderZOrder = zOrder;
|
||||
Reorder();
|
||||
}
|
||||
|
||||
void BaseNode::Reorder()
|
||||
{
|
||||
if (m_Parent)
|
||||
{
|
||||
RefPtr<BaseNode> me = this;
|
||||
m_Parent->m_BaseNodes.Remove(me);
|
||||
RefPtr<BaseNode> sibling = m_Parent->m_BaseNodes.GetLast();
|
||||
if (sibling && sibling->GetRenderZOrder() > m_RenderZOrder)
|
||||
{
|
||||
sibling = sibling->GetPrev();
|
||||
while (sibling)
|
||||
{
|
||||
if (sibling->GetRenderZOrder() <= m_RenderZOrder)
|
||||
break;
|
||||
sibling = sibling->GetPrev();
|
||||
}
|
||||
}
|
||||
if (sibling)
|
||||
{
|
||||
m_Parent->m_BaseNodes.InsertAfter(me, sibling);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Parent->m_BaseNodes.PushFront(me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::AddChild(RefPtr<BaseNode> child)
|
||||
{
|
||||
m_BaseNodes.PushBack(child);
|
||||
child->OnAdded(this);
|
||||
// 如果是需要渲染的子对象
|
||||
if (child->hasTag(Tag::RENDER))
|
||||
{
|
||||
// 重新排序
|
||||
child->Reorder();
|
||||
// 如果组件有transform标签,则设置其位置
|
||||
if (child->hasTag(Tag::TRANSFORM))
|
||||
{
|
||||
TransformT n_transform;
|
||||
n_transform.position = transform.position + transformIter.position;
|
||||
n_transform.scale = transform.scale * transformIter.scale;
|
||||
n_transform.rotation = transform.rotation + transformIter.rotation;
|
||||
child->SetIterationTransform(n_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseNode::RemoveChild(RefPtr<BaseNode> child)
|
||||
{
|
||||
child->m_Parent = nullptr;
|
||||
m_BaseNodes.Remove(child);
|
||||
}
|
||||
|
||||
void BaseNode::RemoveAllChild()
|
||||
{
|
||||
m_BaseNodes.Clear();
|
||||
}
|
||||
|
||||
void BaseNode::OnAdded(BaseNode *node)
|
||||
{
|
||||
m_Parent = node;
|
||||
}
|
||||
|
||||
void BaseNode::SetIterationTransform(TransformT n_transform)
|
||||
{
|
||||
if (n_transform == transformIter)
|
||||
return;
|
||||
transformIter = n_transform;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
TransformT BaseNode::GetIterationTransform()
|
||||
{
|
||||
return transformIter;
|
||||
}
|
||||
|
||||
void BaseNode::SetTransform(TransformT n_transform)
|
||||
{
|
||||
if (n_transform == transform)
|
||||
return;
|
||||
transform = n_transform;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
TransformT BaseNode::GetTransform()
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
|
||||
void BaseNode::SetPos(VecFPos pos)
|
||||
{
|
||||
if (pos == this->transform.position)
|
||||
return;
|
||||
this->transform.position = pos;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetPos()
|
||||
{
|
||||
return this->transform.position;
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetWorldPos()
|
||||
{
|
||||
return this->transform.position + this->transformIter.position;
|
||||
}
|
||||
|
||||
void BaseNode::SetScale(VecFPos scale)
|
||||
{
|
||||
if (scale == this->transform.scale)
|
||||
return;
|
||||
this->transform.scale = scale;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetScale()
|
||||
{
|
||||
return this->transform.scale;
|
||||
}
|
||||
|
||||
void BaseNode::SetRotation(float angle)
|
||||
{
|
||||
if (angle == this->transform.rotation)
|
||||
return;
|
||||
this->transform.rotation = angle;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
float BaseNode::GetRotation()
|
||||
{
|
||||
return this->transform.rotation;
|
||||
}
|
||||
|
||||
void BaseNode::SetAnchor(VecFPos anchor)
|
||||
{
|
||||
if (anchor == this->Anchor)
|
||||
return;
|
||||
Anchor.x = anchor.x;
|
||||
Anchor.y = anchor.y;
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetAnchor()
|
||||
{
|
||||
VecFPos P;
|
||||
P.x = Anchor.x;
|
||||
P.y = Anchor.y;
|
||||
return P;
|
||||
}
|
||||
|
||||
void BaseNode::SetSize(VecSize size)
|
||||
{
|
||||
this->Size = size;
|
||||
}
|
||||
|
||||
VecSize BaseNode::GetSize()
|
||||
{
|
||||
return this->Size;
|
||||
}
|
||||
|
||||
void BaseNode::SetVisible(bool visible)
|
||||
{
|
||||
this->Visible = visible;
|
||||
}
|
||||
|
||||
bool BaseNode::GetVisible()
|
||||
{
|
||||
return this->Visible;
|
||||
}
|
||||
|
||||
void BaseNode::SetAlpha(float alpha)
|
||||
{
|
||||
this->Alpha = alpha;
|
||||
}
|
||||
|
||||
BaseNode *BaseNode::GetParent()
|
||||
{
|
||||
return this->m_Parent;
|
||||
}
|
||||
|
||||
float BaseNode::GetAlpha()
|
||||
{
|
||||
return this->Alpha;
|
||||
}
|
||||
|
||||
void BaseNode::SetIterationPos(VecFPos pos)
|
||||
{
|
||||
if (pos == this->transformIter.position)
|
||||
return;
|
||||
this->transformIter.position = pos;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetIterationPos()
|
||||
{
|
||||
return this->transformIter.position;
|
||||
}
|
||||
|
||||
void BaseNode::SetIterationScale(VecFPos scale)
|
||||
{
|
||||
if (scale == this->transformIter.scale)
|
||||
return;
|
||||
this->transformIter.scale = scale;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
VecFPos BaseNode::GetIterationScale()
|
||||
{
|
||||
return this->transformIter.scale;
|
||||
}
|
||||
|
||||
void BaseNode::SetIterationRotation(float angle)
|
||||
{
|
||||
if (angle == this->transformIter.rotation)
|
||||
return;
|
||||
this->transformIter.rotation = angle;
|
||||
CalcRenderInfo();
|
||||
SetChildIterationTransform();
|
||||
}
|
||||
|
||||
float BaseNode::GetIterationRotation()
|
||||
{
|
||||
return this->transformIter.rotation;
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <SDL.h>
|
||||
#include <string>
|
||||
#include "Tool/RefObject.h"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
#include "Tool/TagGed.h"
|
||||
#include "Tool/TransformT.h"
|
||||
class BaseNode : public RefObject, public TagGed, protected IntrusiveListValue<RefPtr<BaseNode>>
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::function<void(float deltaTime)> UpdateCallback;
|
||||
|
||||
using IntrusiveListValue<RefPtr<BaseNode>>::GetNext;
|
||||
using IntrusiveListValue<RefPtr<BaseNode>>::GetPrev;
|
||||
|
||||
public:
|
||||
// 更新时的回调函数
|
||||
UpdateCallback cb_update_;
|
||||
// 节点名称
|
||||
std::string m_Name;
|
||||
// 子节点列表
|
||||
IntrusiveList<RefPtr<BaseNode>> m_BaseNodes;
|
||||
// 指向父对象的指针
|
||||
BaseNode *m_Parent = nullptr;
|
||||
// 渲染层级
|
||||
int m_RenderZOrder = 0;
|
||||
// 二维仿射变换
|
||||
TransformT transform;
|
||||
// 迭代的二维仿射变换
|
||||
TransformT transformIter;
|
||||
// 锚点
|
||||
VecFPos Anchor = {0.f, 0.f};
|
||||
// 大小
|
||||
VecSize Size = {0, 0};
|
||||
// 透明度
|
||||
float Alpha = 1.f;
|
||||
// 是否显示
|
||||
bool Visible = true;
|
||||
// 计算渲染信息Flag (为了保证每帧只计算一次)
|
||||
bool CalcRenderInfoFlag = true;
|
||||
|
||||
public:
|
||||
BaseNode(/* args */) = default;
|
||||
~BaseNode() = default;
|
||||
|
||||
public:
|
||||
virtual void Init();
|
||||
virtual void HandleEvents(SDL_Event *e);
|
||||
virtual void Update(float deltaTime);
|
||||
virtual void PreRender();
|
||||
virtual void Render();
|
||||
virtual void Clear();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置更新时的回调函数
|
||||
void SetCallbackOnUpdate(const UpdateCallback &cb);
|
||||
|
||||
void SetChildIterationTransform();
|
||||
|
||||
// 计算渲染信息
|
||||
virtual void CalcRenderInfo();
|
||||
// 设置名字
|
||||
void SetName(std::string name);
|
||||
// 获取名字
|
||||
std::string GetName();
|
||||
// 设置渲染层级
|
||||
int GetRenderZOrder();
|
||||
// 获取渲染层级
|
||||
void SetRenderZOrder(int zOrder);
|
||||
// 重新排序
|
||||
void Reorder();
|
||||
// 添加子对象
|
||||
virtual void AddChild(RefPtr<BaseNode> child);
|
||||
// 移除子对象
|
||||
void RemoveChild(RefPtr<BaseNode> child);
|
||||
// 移除所有子对象
|
||||
void RemoveAllChild();
|
||||
// 被添加时
|
||||
virtual void OnAdded(BaseNode *node);
|
||||
// 设置迭代的二维仿射变换
|
||||
void SetIterationTransform(TransformT transform);
|
||||
// 获取迭代的二维仿射变换
|
||||
TransformT GetIterationTransform();
|
||||
// 设置二维仿射变换
|
||||
void SetTransform(TransformT transform);
|
||||
// 获取二维仿射变换
|
||||
TransformT GetTransform();
|
||||
|
||||
// 设置迭代的坐标
|
||||
virtual void SetIterationPos(VecFPos pos);
|
||||
// 获取迭代的坐标
|
||||
VecFPos GetIterationPos();
|
||||
// 设置迭代的缩放
|
||||
virtual void SetIterationScale(VecFPos scale);
|
||||
// 获取迭代的缩放
|
||||
VecFPos GetIterationScale();
|
||||
// 设置迭代的旋转角度
|
||||
virtual void SetIterationRotation(float angle);
|
||||
// 获取迭代的旋转角度
|
||||
float GetIterationRotation();
|
||||
|
||||
// 设置坐标
|
||||
virtual void SetPos(VecFPos pos);
|
||||
// 获取坐标
|
||||
VecFPos GetPos();
|
||||
// 获取世界坐标
|
||||
VecFPos GetWorldPos();
|
||||
// 设置缩放
|
||||
virtual void SetScale(VecFPos scale);
|
||||
// 获取缩放
|
||||
VecFPos GetScale();
|
||||
// 设置旋转角度
|
||||
virtual void SetRotation(float angle);
|
||||
// 获取旋转角度
|
||||
float GetRotation();
|
||||
// 设置中心点
|
||||
virtual void SetAnchor(VecFPos anchor);
|
||||
// 获取中心点
|
||||
VecFPos GetAnchor();
|
||||
// 设置大小
|
||||
virtual void SetSize(VecSize size);
|
||||
// 获取大小
|
||||
VecSize GetSize();
|
||||
// 设置是否显示
|
||||
virtual void SetVisible(bool visible);
|
||||
// 获取是否显示
|
||||
bool GetVisible();
|
||||
// 设置透明度
|
||||
virtual void SetAlpha(float alpha);
|
||||
// 获取透明度
|
||||
float GetAlpha();
|
||||
|
||||
//获取父对象
|
||||
BaseNode *GetParent();
|
||||
};
|
||||
421
source/EngineFrame/Base/Node.cpp
Normal file
421
source/EngineFrame/Base/Node.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
#include "Node.h"
|
||||
#include "EngineCore/Game.h"
|
||||
void Node::Init()
|
||||
{
|
||||
}
|
||||
void Node::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
RefPtr<Node> child = children_.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->HandleEvents(e);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
inline void Node::Update(float deltaTime)
|
||||
{
|
||||
if (children_.IsEmpty())
|
||||
{
|
||||
UpdateSelf(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Node> child = children_.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->GetZOrder() >= 0)
|
||||
break;
|
||||
|
||||
child->Update(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
UpdateSelf(deltaTime);
|
||||
|
||||
|
||||
while (child)
|
||||
{
|
||||
child->Update(deltaTime);
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
inline void Node::PreRender()
|
||||
{
|
||||
if (!visible_)
|
||||
return;
|
||||
UpdateTransform();
|
||||
UpdateOpacity();
|
||||
|
||||
if (children_.IsEmpty())
|
||||
{
|
||||
if (CheckVisibility())
|
||||
{
|
||||
OnPreRender();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RefPtr<Node> child = children_.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->GetZOrder() >= 0)
|
||||
break;
|
||||
|
||||
child->PreRender();
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
if (CheckVisibility())
|
||||
{
|
||||
OnPreRender();
|
||||
}
|
||||
|
||||
while (child)
|
||||
{
|
||||
child->PreRender();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void Node::Render()
|
||||
{
|
||||
if (!visible_)
|
||||
return;
|
||||
if (children_.IsEmpty())
|
||||
{
|
||||
if (visible_in_rt_)
|
||||
{
|
||||
PrepareToRender();
|
||||
OnRender();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RefPtr<Node> child = children_.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->GetZOrder() >= 0)
|
||||
break;
|
||||
|
||||
child->Render();
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
if (visible_in_rt_)
|
||||
{
|
||||
PrepareToRender();
|
||||
OnRender();
|
||||
}
|
||||
|
||||
while (child)
|
||||
{
|
||||
child->Render();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
void Node::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Node::OnPreRender()
|
||||
{
|
||||
}
|
||||
|
||||
void Node::OnRender()
|
||||
{
|
||||
}
|
||||
|
||||
void Node::OnUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Node::UpdateSelf(float deltaTime)
|
||||
{
|
||||
if (!update_pausing_)
|
||||
{
|
||||
OnUpdate(deltaTime);
|
||||
|
||||
// 如果有回调函数,则调用回调函数
|
||||
if (cb_update_.size() > 0)
|
||||
{
|
||||
for (auto &cb : cb_update_)
|
||||
{
|
||||
cb.second(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::PrepareToRender()
|
||||
{
|
||||
Game::GetInstance().GetRenderer()->SetMatrix(render_matrix_);
|
||||
Game::GetInstance().GetRenderer()->SetOpacity(displayed_opacity_);
|
||||
}
|
||||
|
||||
void Node::RemoveFromParent()
|
||||
{
|
||||
if (parent_)
|
||||
{
|
||||
parent_->RemoveChild(this);
|
||||
}
|
||||
}
|
||||
inline void Node::PauseUpdating()
|
||||
{
|
||||
update_pausing_ = true;
|
||||
}
|
||||
inline void Node::ResumeUpdating()
|
||||
{
|
||||
update_pausing_ = false;
|
||||
}
|
||||
inline bool Node::IsUpdatePausing() const
|
||||
{
|
||||
return update_pausing_;
|
||||
}
|
||||
|
||||
void Node::SetCallbackOnUpdate(std::string Key, const UpdateCallback &cb)
|
||||
{
|
||||
cb_update_[Key] = cb;
|
||||
}
|
||||
|
||||
void Node::RemoveCallbackOnUpdate(std::string Key)
|
||||
{
|
||||
cb_update_.erase(Key);
|
||||
}
|
||||
|
||||
bool Node::ContainsPoint(const glm::vec2 &point) const
|
||||
{
|
||||
// if (size_.x == 0.f || size_.y == 0.f)
|
||||
return false;
|
||||
// glm::vec2 local = ConvertToLocal(point);
|
||||
// return local.x >= 0 && local.y >= 0 && local.x <= size_.x && local.y <= size_.y;
|
||||
}
|
||||
|
||||
glm::vec2 Node::ConvertToLocal(const glm::vec2 &point) const
|
||||
{
|
||||
glm::vec2 local = GetTransformInverseMatrix().Transform(point);
|
||||
return local;
|
||||
}
|
||||
|
||||
glm::vec2 Node::ConvertToWorld(const glm::vec2 &point) const
|
||||
{
|
||||
glm::vec2 world = GetTransformMatrix().Transform(point);
|
||||
return world;
|
||||
}
|
||||
|
||||
void Node::ShowBorder(bool show)
|
||||
{
|
||||
show_border_ = show;
|
||||
}
|
||||
|
||||
Node::Node() : visible_(true), update_pausing_(false), show_border_(false), parent_(nullptr), anchor_(0.0f, 0.0f), z_order_(0), opacity_(1.f), name_("Node"), displayed_opacity_(1.f), cascade_opacity_(true)
|
||||
{
|
||||
Game::GetInstance().m_nodeCount++;
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
Game::GetInstance().m_nodeCount--;
|
||||
RemoveAllChildren();
|
||||
}
|
||||
|
||||
void Node::UpdateTransform() const
|
||||
{
|
||||
if (!dirty_flag_.Has(DirtyFlag::DirtyTransform))
|
||||
return;
|
||||
dirty_flag_.Unset(DirtyFlag::DirtyTransform);
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransformInverse);
|
||||
dirty_flag_.Set(DirtyFlag::DirtyVisibility);
|
||||
|
||||
if (transform_.IsFast())
|
||||
{
|
||||
transform_matrix_to_parent_ = Matrix3x2::Translation(transform_.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform_matrix_to_parent_ = transform_.ToMatrix();
|
||||
}
|
||||
|
||||
glm::vec2 anchor_offset(-size_.width * anchor_.x, -size_.height * anchor_.y);
|
||||
transform_matrix_to_parent_.Translate(anchor_offset);
|
||||
|
||||
transform_matrix_ = transform_matrix_to_parent_;
|
||||
if (parent_)
|
||||
{
|
||||
transform_matrix_ *= parent_->transform_matrix_;
|
||||
}
|
||||
|
||||
GenerateRenderMatrix();
|
||||
|
||||
for (const auto &child : children_)
|
||||
child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
void Node::UpdateTransformUpwards() const
|
||||
{
|
||||
if (parent_)
|
||||
{
|
||||
parent_->UpdateTransformUpwards();
|
||||
|
||||
if (parent_->dirty_flag_.Has(DirtyFlag::DirtyTransform))
|
||||
{
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
}
|
||||
|
||||
void Node::UpdateOpacity()
|
||||
{
|
||||
if (!dirty_flag_.Has(DirtyFlag::DirtyOpacity))
|
||||
return;
|
||||
|
||||
dirty_flag_.Unset(DirtyFlag::DirtyOpacity);
|
||||
|
||||
if (parent_ && parent_->IsCascadeOpacityEnabled())
|
||||
{
|
||||
displayed_opacity_ = opacity_ * parent_->displayed_opacity_;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayed_opacity_ = opacity_;
|
||||
}
|
||||
|
||||
for (const auto &child : children_)
|
||||
child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||||
}
|
||||
|
||||
const Matrix3x2 &Node::GetTransformMatrix() const
|
||||
{
|
||||
UpdateTransformUpwards();
|
||||
return transform_matrix_;
|
||||
}
|
||||
|
||||
const Matrix3x2 &Node::GetTransformInverseMatrix() const
|
||||
{
|
||||
UpdateTransformUpwards();
|
||||
if (dirty_flag_.Has(DirtyFlag::DirtyTransformInverse))
|
||||
{
|
||||
dirty_flag_.Unset(DirtyFlag::DirtyTransformInverse);
|
||||
transform_matrix_inverse_ = transform_matrix_.Invert();
|
||||
}
|
||||
return transform_matrix_inverse_;
|
||||
}
|
||||
|
||||
const Matrix3x2 &Node::GetTransformMatrixToParent() const
|
||||
{
|
||||
UpdateTransformUpwards();
|
||||
return transform_matrix_to_parent_;
|
||||
}
|
||||
|
||||
void Node::GenerateRenderMatrix() const
|
||||
{
|
||||
// 构造OpenGl渲染矩阵
|
||||
render_matrix_ = glm::mat4(1.0f);
|
||||
// 填充旋转+缩放分量(2D 变换核心,对应 4x4 矩阵左上 2x2 区域)
|
||||
render_matrix_[0][0] = transform_matrix_[0]; // _11 → x轴缩放+旋转
|
||||
render_matrix_[0][1] = transform_matrix_[1]; // _12 → 影响y轴方向的旋转分量
|
||||
render_matrix_[1][0] = transform_matrix_[2]; // _21 → 影响x轴方向的旋转分量
|
||||
render_matrix_[1][1] = transform_matrix_[3]; // _22 → y轴缩放+旋转
|
||||
// 填充平移分量(对应 4x4 矩阵最后一行前两列,z轴平移为0)
|
||||
render_matrix_[3][0] = transform_matrix_[4]; // _31 → x方向平移(世界坐标)
|
||||
render_matrix_[3][1] = transform_matrix_[5]; // _32 → y方向平移(世界坐标)
|
||||
}
|
||||
|
||||
void Node::Reorder()
|
||||
{
|
||||
if (parent_)
|
||||
{
|
||||
RefPtr<Node> me = this;
|
||||
|
||||
parent_->children_.Remove(me);
|
||||
|
||||
RefPtr<Node> sibling = parent_->children_.GetLast();
|
||||
|
||||
if (sibling && sibling->GetZOrder() > z_order_)
|
||||
{
|
||||
sibling = sibling->GetPrev();
|
||||
while (sibling)
|
||||
{
|
||||
if (sibling->GetZOrder() <= z_order_)
|
||||
break;
|
||||
sibling = sibling->GetPrev();
|
||||
}
|
||||
}
|
||||
|
||||
if (sibling)
|
||||
{
|
||||
parent_->children_.InsertAfter(me, sibling);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent_->children_.PushFront(me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Node::CheckVisibility() const
|
||||
{
|
||||
if (dirty_flag_.Has(DirtyFlag::DirtyVisibility))
|
||||
{
|
||||
dirty_flag_.Unset(DirtyFlag::DirtyVisibility);
|
||||
|
||||
if (size_.width == 0.f && size_.height == 0.f)
|
||||
{
|
||||
visible_in_rt_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
// visible_in_rt_ = ctx.CheckVisibility(GetBounds(), transform_matrix_ /* GetTransformMatrix() */);
|
||||
visible_in_rt_ = true;
|
||||
}
|
||||
}
|
||||
return visible_in_rt_;
|
||||
}
|
||||
|
||||
void Node::AddChild(RefPtr<Node> child)
|
||||
{
|
||||
if (child)
|
||||
{
|
||||
assert(!child->parent_ && "Actor::AddChild failed, the actor to be added already has a parent");
|
||||
|
||||
children_.PushBack(child);
|
||||
child->parent_ = this;
|
||||
|
||||
child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||||
child->Reorder();
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(0, "Actor::AddChild failed, NULL pointer exception");
|
||||
}
|
||||
}
|
||||
|
||||
Node::NodeList &Node::GetAllChildren()
|
||||
{
|
||||
return children_;
|
||||
}
|
||||
|
||||
const Node::NodeList &Node::GetAllChildren() const
|
||||
{
|
||||
return children_;
|
||||
}
|
||||
|
||||
void Node::RemoveChild(RefPtr<Node> child)
|
||||
{
|
||||
if (children_.IsEmpty())
|
||||
return;
|
||||
|
||||
if (child)
|
||||
{
|
||||
child->parent_ = nullptr;
|
||||
children_.Remove(child);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_LogError(0, "Actor::RemoveChild failed, NULL pointer exception");
|
||||
}
|
||||
}
|
||||
704
source/EngineFrame/Base/Node.h
Normal file
704
source/EngineFrame/Base/Node.h
Normal file
@@ -0,0 +1,704 @@
|
||||
#pragma once
|
||||
#include <SDL.h>
|
||||
#include "EngineFrame/Attribute/Y_Transform.h"
|
||||
#include "EngineFrame/Attribute/Flag.h"
|
||||
#include "math/Math.h"
|
||||
#include "Tool/RefObject.h"
|
||||
#include "Tool/RefPtr.h"
|
||||
#include "Tool/IntrusiveList.hpp"
|
||||
|
||||
class Node : public RefObject, protected IntrusiveListValue<RefPtr<Node>>
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(float deltaTime)> UpdateCallback;
|
||||
typedef IntrusiveList<RefPtr<Node>> NodeList;
|
||||
|
||||
using IntrusiveListValue<RefPtr<Node>>::GetNext;
|
||||
using IntrusiveListValue<RefPtr<Node>>::GetPrev;
|
||||
|
||||
protected:
|
||||
/**渲染矩阵 */
|
||||
mutable glm::mat4 render_matrix_;
|
||||
/**变换属性 */
|
||||
Y_Transform transform_;
|
||||
/**变换矩阵 */
|
||||
mutable Matrix3x2 transform_matrix_;
|
||||
mutable Matrix3x2 transform_matrix_inverse_;
|
||||
mutable Matrix3x2 transform_matrix_to_parent_;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/**更新时的回调函数 */
|
||||
std::map<std::string, UpdateCallback> cb_update_;
|
||||
/**锚点 */
|
||||
glm::vec2 anchor_;
|
||||
/**Z轴显示层级 */
|
||||
int z_order_;
|
||||
/**大小 */
|
||||
VecSize size_;
|
||||
/**透明度 */
|
||||
float opacity_;
|
||||
/**显示透明度 */
|
||||
float displayed_opacity_;
|
||||
|
||||
/**是否可见 */
|
||||
bool visible_;
|
||||
/**是否暂停更新 */
|
||||
bool update_pausing_;
|
||||
/**是否显示边界 */
|
||||
bool show_border_;
|
||||
/**是否在渲染区域中 */
|
||||
mutable bool visible_in_rt_;
|
||||
/**联级透明度 */
|
||||
bool cascade_opacity_;
|
||||
/**名称 */
|
||||
std::string name_;
|
||||
|
||||
/**父对象 */
|
||||
Node *parent_;
|
||||
/**子对象链表 */
|
||||
NodeList children_;
|
||||
/**标志 */
|
||||
mutable Flag<uint8_t> dirty_flag_;
|
||||
|
||||
public:
|
||||
virtual void Init();
|
||||
virtual void HandleEvents(SDL_Event *e);
|
||||
virtual void Update(float deltaTime);
|
||||
virtual void PreRender();
|
||||
virtual void Render();
|
||||
virtual void Clear();
|
||||
|
||||
virtual void OnPreRender();
|
||||
virtual void OnRender();
|
||||
virtual void OnUpdate(float deltaTime);
|
||||
|
||||
void UpdateSelf(float dt);
|
||||
void PrepareToRender();
|
||||
|
||||
public:
|
||||
/// \~chinese
|
||||
/// @brief 获取显示状态
|
||||
bool IsVisible() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 是否启用级联透明度
|
||||
bool IsCascadeOpacityEnabled() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 Z 轴顺序
|
||||
int GetZOrder() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取坐标
|
||||
glm::vec2 GetPosition() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 坐标
|
||||
float GetPositionX() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 y 坐标
|
||||
float GetPositionY() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取大小
|
||||
virtual VecSize GetSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取宽度
|
||||
float GetWidth() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取高度
|
||||
float GetHeight() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的宽度
|
||||
float GetScaledWidth() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的高度
|
||||
float GetScaledHeight() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的大小
|
||||
VecSize GetScaledSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取锚点
|
||||
glm::vec2 GetAnchor() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 方向锚点
|
||||
float GetAnchorX() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 y 方向锚点
|
||||
float GetAnchorY() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取透明度
|
||||
float GetOpacity() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取旋转角度
|
||||
float GetRotation() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放比例
|
||||
glm::vec2 GetScale() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取横向缩放比例
|
||||
float GetScaleX() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取纵向缩放比例
|
||||
float GetScaleY() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取错切角度
|
||||
glm::vec2 GetSkew() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取横向错切角度
|
||||
float GetSkewX() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取纵向错切角度
|
||||
float GetSkewY() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取变换
|
||||
Y_Transform GetTransform() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取父角色
|
||||
Node *GetParent() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置角色是否可见
|
||||
virtual void SetVisible(bool val);
|
||||
|
||||
virtual void OnSetPosition();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置名称
|
||||
void SetName(std::string name);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取名称
|
||||
std::string GetName() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置坐标
|
||||
void SetPosition(const glm::vec2 &pos);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置坐标
|
||||
void SetPosition(float x, float y);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置横坐标
|
||||
void SetPositionX(float x);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置纵坐标
|
||||
void SetPositionY(float y);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移动至坐标
|
||||
void MoveTo(const glm::vec2 &p);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移动至坐标
|
||||
void MoveTo(float x, float y);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移动相对坐标
|
||||
void MoveBy(const glm::vec2 &trans);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移动相对坐标
|
||||
void MoveBy(float trans_x, float trans_y);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
|
||||
void SetScale(const glm::vec2 &scale);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
|
||||
void SetScale(float scalex, float scaley);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置错切角度,默认为 (0, 0)
|
||||
void SetSkew(const glm::vec2 &skew);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置错切角度,默认为 (0, 0)
|
||||
void SetSkew(float skewx, float skewy);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置旋转角度,默认为 0
|
||||
void SetRotation(float rotation);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
|
||||
void SetAnchor(const glm::vec2 &anchor);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
|
||||
void SetAnchor(float anchorx, float anchory);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改大小
|
||||
void SetSize(const VecSize &size);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改大小
|
||||
void SetSize(float width, float height);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改宽度
|
||||
void SetWidth(float width);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改高度
|
||||
void SetHeight(float height);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
|
||||
void SetOpacity(float opacity);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 启用或禁用级联透明度
|
||||
void SetCascadeOpacityEnabled(bool enabled);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置二维仿射变换
|
||||
void SetTransform(const Y_Transform &transform);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置 Z 轴顺序,默认为 0
|
||||
void SetZOrder(int zorder);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 添加子角色
|
||||
void AddChild(RefPtr<Node> child);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取全部子角色
|
||||
NodeList &GetAllChildren();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取全部子角色
|
||||
const NodeList &GetAllChildren() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移除子角色
|
||||
void RemoveChild(RefPtr<Node> child);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移除所有节点
|
||||
void RemoveAllChildren();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 从父角色移除
|
||||
void RemoveFromParent();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 暂停角色更新
|
||||
void PauseUpdating();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 继续角色更新
|
||||
void ResumeUpdating();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 角色更新是否暂停
|
||||
bool IsUpdatePausing() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置更新时的回调函数
|
||||
void SetCallbackOnUpdate(std::string Key, const UpdateCallback &cb);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移除更新时的回调函数
|
||||
void RemoveCallbackOnUpdate(std::string Key);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 判断点是否在角色内
|
||||
virtual bool ContainsPoint(const glm::vec2 &point) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将世界坐标系点转换为局部坐标系点
|
||||
glm::vec2 ConvertToLocal(const glm::vec2 &point) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将局部坐标系点转换为世界坐标系点
|
||||
glm::vec2 ConvertToWorld(const glm::vec2 &point) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 渲染角色边界
|
||||
void ShowBorder(bool show);
|
||||
|
||||
|
||||
public:
|
||||
Node(/* args */);
|
||||
~Node();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新自己的二维变换,并通知所有子角色
|
||||
void UpdateTransform() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 向上追溯更新
|
||||
/// @details 对于节点树 A->B(dirty)->C->D,当对 D 执行 UpdateTransformUpwards 时会对 B、C、D 从上到下依次更新
|
||||
void UpdateTransformUpwards() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新自己和所有子角色的透明度
|
||||
void UpdateOpacity();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换矩阵
|
||||
const Matrix3x2 &GetTransformMatrix() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换的逆矩阵
|
||||
const Matrix3x2 &GetTransformInverseMatrix() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取变换到父角色的二维变换矩阵
|
||||
const Matrix3x2 &GetTransformMatrixToParent() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 生成用于OpenGL渲染的矩阵
|
||||
virtual void GenerateRenderMatrix() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 将所有子角色按Z轴顺序排序
|
||||
void Reorder();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 检查是否在渲染上下文的视区内
|
||||
virtual bool CheckVisibility() const;
|
||||
|
||||
enum DirtyFlag : uint8_t
|
||||
{
|
||||
Clean = 0,
|
||||
DirtyTransform = 1,
|
||||
DirtyTransformInverse = 1 << 1,
|
||||
DirtyOpacity = 1 << 2,
|
||||
DirtyVisibility = 1 << 3
|
||||
};
|
||||
};
|
||||
|
||||
inline void Node::RemoveAllChildren()
|
||||
{
|
||||
RefPtr<Node> next;
|
||||
for (RefPtr<Node> child = children_.GetFirst(); child; child = next)
|
||||
{
|
||||
next = child->GetNext();
|
||||
RemoveChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Node::IsVisible() const
|
||||
{
|
||||
return visible_;
|
||||
}
|
||||
|
||||
inline bool Node::IsCascadeOpacityEnabled() const
|
||||
{
|
||||
return cascade_opacity_;
|
||||
}
|
||||
|
||||
inline int Node::GetZOrder() const
|
||||
{
|
||||
return z_order_;
|
||||
}
|
||||
|
||||
inline glm::vec2 Node::GetPosition() const
|
||||
{
|
||||
return transform_.position;
|
||||
}
|
||||
|
||||
inline float Node::GetPositionX() const
|
||||
{
|
||||
return GetPosition().x;
|
||||
}
|
||||
|
||||
inline float Node::GetPositionY() const
|
||||
{
|
||||
return GetPosition().y;
|
||||
}
|
||||
|
||||
inline VecSize Node::GetSize() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
inline float Node::GetWidth() const
|
||||
{
|
||||
return GetSize().width;
|
||||
}
|
||||
|
||||
inline float Node::GetHeight() const
|
||||
{
|
||||
return GetSize().height;
|
||||
}
|
||||
|
||||
inline float Node::GetScaledWidth() const
|
||||
{
|
||||
return GetWidth() * GetScaleX();
|
||||
}
|
||||
|
||||
inline float Node::GetScaledHeight() const
|
||||
{
|
||||
return GetHeight() * GetScaleY();
|
||||
}
|
||||
|
||||
inline VecSize Node::GetScaledSize() const
|
||||
{
|
||||
return VecSize{GetScaledWidth(), GetScaledHeight()};
|
||||
}
|
||||
|
||||
inline glm::vec2 Node::GetAnchor() const
|
||||
{
|
||||
return anchor_;
|
||||
}
|
||||
|
||||
inline float Node::GetAnchorX() const
|
||||
{
|
||||
return GetAnchor().x;
|
||||
}
|
||||
|
||||
inline float Node::GetAnchorY() const
|
||||
{
|
||||
return GetAnchor().y;
|
||||
}
|
||||
|
||||
inline float Node::GetOpacity() const
|
||||
{
|
||||
return opacity_;
|
||||
}
|
||||
|
||||
inline float Node::GetRotation() const
|
||||
{
|
||||
return transform_.rotation;
|
||||
}
|
||||
|
||||
inline glm::vec2 Node::GetScale() const
|
||||
{
|
||||
return transform_.scale;
|
||||
}
|
||||
|
||||
inline float Node::GetScaleX() const
|
||||
{
|
||||
return GetScale().x;
|
||||
}
|
||||
|
||||
inline float Node::GetScaleY() const
|
||||
{
|
||||
return GetScale().y;
|
||||
}
|
||||
|
||||
inline glm::vec2 Node::GetSkew() const
|
||||
{
|
||||
return transform_.skew;
|
||||
}
|
||||
|
||||
inline float Node::GetSkewX() const
|
||||
{
|
||||
return GetSkew().x;
|
||||
}
|
||||
|
||||
inline float Node::GetSkewY() const
|
||||
{
|
||||
return GetSkew().y;
|
||||
}
|
||||
|
||||
inline Y_Transform Node::GetTransform() const
|
||||
{
|
||||
return transform_;
|
||||
}
|
||||
|
||||
inline Node *Node::GetParent() const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
inline void Node::SetVisible(bool val)
|
||||
{
|
||||
visible_ = val;
|
||||
}
|
||||
|
||||
inline void Node::OnSetPosition()
|
||||
{
|
||||
}
|
||||
|
||||
inline void Node::SetName(std::string name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
inline std::string Node::GetName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
inline void Node::SetPosition(const glm::vec2 &pos)
|
||||
{
|
||||
if (transform_.position == pos)
|
||||
return;
|
||||
|
||||
transform_.position = pos;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
OnSetPosition();
|
||||
}
|
||||
|
||||
inline void Node::SetPosition(float x, float y)
|
||||
{
|
||||
this->SetPosition(glm::vec2(x, y));
|
||||
}
|
||||
|
||||
inline void Node::SetPositionX(float x)
|
||||
{
|
||||
this->SetPosition(glm::vec2(x, GetPosition().y));
|
||||
}
|
||||
|
||||
inline void Node::SetPositionY(float y)
|
||||
{
|
||||
this->SetPosition(glm::vec2(GetPosition().x, y));
|
||||
}
|
||||
|
||||
inline void Node::MoveTo(const glm::vec2 &p)
|
||||
{
|
||||
this->SetPosition(p);
|
||||
}
|
||||
|
||||
inline void Node::MoveTo(float x, float y)
|
||||
{
|
||||
this->SetPosition(glm::vec2(x, y));
|
||||
}
|
||||
|
||||
inline void Node::MoveBy(const glm::vec2 &trans)
|
||||
{
|
||||
this->SetPosition(transform_.position.x + trans.x, transform_.position.y + trans.y);
|
||||
}
|
||||
|
||||
inline void Node::MoveBy(float trans_x, float trans_y)
|
||||
{
|
||||
this->MoveBy(glm::vec2(trans_x, trans_y));
|
||||
}
|
||||
|
||||
inline void Node::SetScale(const glm::vec2 &scale)
|
||||
{
|
||||
if (transform_.scale == scale)
|
||||
return;
|
||||
|
||||
transform_.scale = scale;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetScale(float scalex, float scaley)
|
||||
{
|
||||
this->SetScale(glm::vec2(scalex, scaley));
|
||||
}
|
||||
|
||||
inline void Node::SetSkew(const glm::vec2 &skew)
|
||||
{
|
||||
if (transform_.skew == skew)
|
||||
return;
|
||||
|
||||
transform_.skew = skew;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetSkew(float skewx, float skewy)
|
||||
{
|
||||
this->SetSkew(glm::vec2(skewx, skewy));
|
||||
}
|
||||
|
||||
inline void Node::SetRotation(float rotation)
|
||||
{
|
||||
if (transform_.rotation == rotation)
|
||||
return;
|
||||
|
||||
transform_.rotation = rotation;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetAnchor(const glm::vec2 &anchor)
|
||||
{
|
||||
if (anchor_ == anchor)
|
||||
return;
|
||||
|
||||
anchor_ = anchor;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetAnchor(float anchorx, float anchory)
|
||||
{
|
||||
this->SetAnchor(glm::vec2(anchorx, anchory));
|
||||
}
|
||||
|
||||
inline void Node::SetSize(const VecSize &size)
|
||||
{
|
||||
if (size_ == size)
|
||||
return;
|
||||
|
||||
size_ = size;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetSize(float width, float height)
|
||||
{
|
||||
this->SetSize(VecSize{width, height});
|
||||
}
|
||||
|
||||
inline void Node::SetWidth(float width)
|
||||
{
|
||||
this->SetSize(width, GetHeight());
|
||||
}
|
||||
|
||||
inline void Node::SetHeight(float height)
|
||||
{
|
||||
this->SetSize(GetWidth(), height);
|
||||
}
|
||||
|
||||
inline void Node::SetOpacity(float opacity)
|
||||
{
|
||||
if (opacity_ == opacity)
|
||||
return;
|
||||
|
||||
opacity_ = std::min(std::max(opacity, 0.f), 1.f);
|
||||
dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||||
}
|
||||
|
||||
inline void Node::SetCascadeOpacityEnabled(bool enabled)
|
||||
{
|
||||
if (cascade_opacity_ == enabled)
|
||||
return;
|
||||
|
||||
cascade_opacity_ = enabled;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||||
}
|
||||
|
||||
inline void Node::SetTransform(const Y_Transform &transform)
|
||||
{
|
||||
transform_ = transform;
|
||||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||||
}
|
||||
|
||||
inline void Node::SetZOrder(int zorder)
|
||||
{
|
||||
if (z_order_ != zorder)
|
||||
{
|
||||
z_order_ = zorder;
|
||||
Reorder();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "Asset/AssetManager.h"
|
||||
#include "Asset/Asset_Script.h"
|
||||
#include "Tool/Math.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
Animation::Animation()
|
||||
@@ -27,8 +27,6 @@ Animation::~Animation()
|
||||
|
||||
void Animation::Init(std::string AniPath)
|
||||
{
|
||||
Actor::Init();
|
||||
|
||||
AniScriptParser::AniInfo Info = AssetManager::GetInstance().StructAniInfo(AniPath);
|
||||
this->AniPath = AniPath;
|
||||
this->AnimationFlag = Info.Flag;
|
||||
@@ -45,17 +43,19 @@ void Animation::Init(std::string AniPath)
|
||||
FrameObj.Img_Path = AdditionalOptions(FrameObj.Img_Path, this->AdditionalOptionsData);
|
||||
}
|
||||
SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index);
|
||||
SpriteObj->SetAnchor(VecFPos(0.5f, 0.5f));
|
||||
SpriteObj->SetPos(VecFPos(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y));
|
||||
SpriteObj->SetPosition(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y);
|
||||
SpriteObj->SetVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpriteObj = new Sprite();
|
||||
SpriteObj->SetVisible(false);
|
||||
SDL_Log("Animation::Init() SpriteObj is nullptr");
|
||||
}
|
||||
SpriteArr.push_back(SpriteObj);
|
||||
//记录最大帧宽高
|
||||
auto SpriteSize = SpriteObj->GetSize();
|
||||
if(this->MaxSize.width < SpriteSize.width)this->MaxSize.width = SpriteSize.width;
|
||||
if(this->MaxSize.height < SpriteSize.height)this->MaxSize.height = SpriteSize.height;
|
||||
AddChild(SpriteObj);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ void Animation::Init(std::string AniPath)
|
||||
for (auto &Ani : Info.AniList)
|
||||
{
|
||||
RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
|
||||
AlsAniObj->SetRenderZOrder(Ani.second.layer[1]);
|
||||
AlsAniObj->SetZOrder(Ani.second.layer[1]);
|
||||
AddChild(AlsAniObj);
|
||||
}
|
||||
}
|
||||
@@ -84,20 +84,16 @@ void Animation::Init(std::string AniPath)
|
||||
FlushFrame(0);
|
||||
}
|
||||
|
||||
void Animation::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Animation::Update(float deltaTime)
|
||||
void Animation::OnUpdate(float deltaTime)
|
||||
{
|
||||
// 可用性检查
|
||||
if (IsUsability && Visible)
|
||||
if (IsUsability && IsVisible())
|
||||
{
|
||||
float dt_ms = deltaTime * 1000.0f;
|
||||
// 累加当前帧时间
|
||||
CurrentIndexT += dt_ms;
|
||||
// 插值模式判断
|
||||
InterpolationLogic();
|
||||
// InterpolationLogic();
|
||||
|
||||
// 循环处理:只要当前时间超过帧延迟,就切换帧(支持一次跳过多帧)
|
||||
while (CurrentIndexT >= NextFrameDelay)
|
||||
@@ -127,32 +123,26 @@ void Animation::Update(float deltaTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
Actor::Update(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &Sp : SpriteArr)
|
||||
{
|
||||
Sp->SetVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::Render()
|
||||
void Animation::OnAdded(Actor *node)
|
||||
{
|
||||
Actor::Render();
|
||||
}
|
||||
|
||||
void Animation::OnAdded(BaseNode *node)
|
||||
{
|
||||
Actor::OnAdded(node);
|
||||
FlushFrame(0);
|
||||
}
|
||||
|
||||
void Animation::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Animation::SetVisible(bool visible)
|
||||
{
|
||||
// 设置启用的时候要更新一下当前帧的渲染信息 避免因为延迟造成的坐标闪烁
|
||||
if (visible)
|
||||
{
|
||||
CurrentFrame->CalcRenderInfoLogic();
|
||||
CurrentFrame->CalcRenderInfo();
|
||||
CurrentFrame->SetVisible(true);
|
||||
}
|
||||
Actor::SetVisible(visible);
|
||||
}
|
||||
@@ -191,8 +181,9 @@ void Animation::FlushFrame(int Index)
|
||||
// 缩放
|
||||
if (FlagBuf.count("IMAGE_RATE"))
|
||||
{
|
||||
VecFPos Rate = std::get<VecFPos>(FlagBuf["IMAGE_RATE"]);
|
||||
CurrentFrame->SetScale(VecFPos{Rate.x, Rate.y});
|
||||
Vec2 Rate = std::get<Vec2>(FlagBuf["IMAGE_RATE"]);
|
||||
CurrentFrame->SetScale(Rate.x, Rate.y);
|
||||
CurrentFrame->SetPosition(FrameInfo.Img_Pos.x * Rate.x, FrameInfo.Img_Pos.y * Rate.y);
|
||||
}
|
||||
// 线性减淡
|
||||
if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE"))
|
||||
@@ -202,7 +193,7 @@ void Animation::FlushFrame(int Index)
|
||||
// 旋转
|
||||
if (FlagBuf.count("IMAGE_ROTATE"))
|
||||
{
|
||||
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
|
||||
// CurrentFrame->SetAnchor(0.5f, 0.5f);
|
||||
CurrentFrame->SetRotation(std::get<float>(FlagBuf["IMAGE_ROTATE"]));
|
||||
}
|
||||
// 染色
|
||||
@@ -277,27 +268,26 @@ void Animation::InterpolationLogic()
|
||||
}
|
||||
// 坐标
|
||||
{
|
||||
VecFPos PosData = {
|
||||
glm::vec2 PosData = {
|
||||
(OldData.Img_Pos.x + (NewData.Img_Pos.x - OldData.Img_Pos.x) * InterRate),
|
||||
(OldData.Img_Pos.y + (NewData.Img_Pos.y - OldData.Img_Pos.y) * InterRate)};
|
||||
CurrentFrame->SetPos(PosData);
|
||||
CurrentFrame->SetPosition(PosData);
|
||||
}
|
||||
// 缩放
|
||||
{
|
||||
VecFPos OldRateData = {1.0f, 1.0f};
|
||||
VecFPos NewRateData = {1.0f, 1.0f};
|
||||
Vec2 OldRateData = {1.0f, 1.0f};
|
||||
Vec2 NewRateData = {1.0f, 1.0f};
|
||||
if (OldData.Flag.count("IMAGE_RATE"))
|
||||
{
|
||||
OldRateData = std::get<VecFPos>(OldData.Flag["IMAGE_RATE"]);
|
||||
OldRateData = std::get<Vec2>(OldData.Flag["IMAGE_RATE"]);
|
||||
}
|
||||
if (NewData.Flag.count("IMAGE_RATE"))
|
||||
{
|
||||
NewRateData = std::get<VecFPos>(NewData.Flag["IMAGE_RATE"]);
|
||||
NewRateData = std::get<Vec2>(NewData.Flag["IMAGE_RATE"]);
|
||||
}
|
||||
VecFPos RateData = {
|
||||
glm::vec2 RateData = {
|
||||
OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate,
|
||||
OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate};
|
||||
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
|
||||
CurrentFrame->SetScale(RateData);
|
||||
}
|
||||
// 旋转
|
||||
@@ -315,3 +305,8 @@ void Animation::InterpolationLogic()
|
||||
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate);
|
||||
}
|
||||
}
|
||||
|
||||
VecSize Animation::GetMaxSize()
|
||||
{
|
||||
return MaxSize;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
#include "Asset/AnimationStruct.h"
|
||||
#include <functional>
|
||||
@@ -24,24 +24,26 @@ public:
|
||||
Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData);
|
||||
~Animation();
|
||||
|
||||
/**初始化 */
|
||||
void Init(std::string AniPath);
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render() override;
|
||||
void OnAdded(BaseNode *node) override;
|
||||
void Clear() override;
|
||||
|
||||
void OnUpdate(float deltaTime) override;
|
||||
void OnAdded(Actor *node) override;
|
||||
void SetVisible(bool visible) override;
|
||||
|
||||
public:
|
||||
/**刷新帧 */
|
||||
void FlushFrame(int Index);
|
||||
/**重置Ani */
|
||||
void Reset();
|
||||
/**获取当前帧信息 */
|
||||
AniScriptParser::AniFrame GetCurrentFrameInfo();
|
||||
// 设置帧索引
|
||||
void SetFrameIndex(int Index);
|
||||
void InterpolationLogic();
|
||||
// TODO SetOutline
|
||||
// TODO SetDye
|
||||
// TODO SetCrop
|
||||
|
||||
/**获取最大尺寸 */
|
||||
VecSize GetMaxSize();
|
||||
|
||||
public:
|
||||
// Ani是否可用
|
||||
@@ -76,20 +78,11 @@ public:
|
||||
std::string AniPath;
|
||||
// 是否描边
|
||||
bool IsOutline = false;
|
||||
// // 描边颜色
|
||||
// OutlineColor = null;
|
||||
// // 描边对象List
|
||||
// OutlineList = null;
|
||||
// // 当前描边对象
|
||||
// CurrentOutline = null;
|
||||
// // 染色颜色
|
||||
// DyeColor = null;
|
||||
// // 染色帧List
|
||||
// DyeFrameList = null;
|
||||
// // 整体染色
|
||||
// DyeAllFlag = false;
|
||||
|
||||
// 附加选项
|
||||
std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;
|
||||
Animation::ReplaceData AdditionalOptionsData;
|
||||
/**最大尺寸
|
||||
* 所有子精灵最大的尺寸
|
||||
*/
|
||||
VecSize MaxSize = {0, 0};
|
||||
};
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#include "AnimationManager.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
AnimationManager::AnimationManager()
|
||||
{
|
||||
}
|
||||
|
||||
void AnimationManager::PreRender()
|
||||
{
|
||||
Actor::PreRender();
|
||||
// 标记是否是第一个子对象(用于初始化min/max值)
|
||||
bool isFirst = true;
|
||||
float minX = 0.0f, minY = 0.0f; // 所有子对象的最小X、Y坐标
|
||||
float maxX = 0.0f, maxY = 0.0f; // 所有子对象的最大X、Y坐标(右下角)
|
||||
|
||||
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
// 转换为Animation对象
|
||||
Animation *ani = static_cast<Animation *>(child.Get());
|
||||
|
||||
float width = ani->CurrentFrame->_RenderGuidanceInfo.rect.w;
|
||||
float height = ani->CurrentFrame->_RenderGuidanceInfo.rect.h;
|
||||
float x = ani->CurrentFrame->_RenderGuidanceInfo.rect.x;
|
||||
float y = ani->CurrentFrame->_RenderGuidanceInfo.rect.y;
|
||||
|
||||
// 计算子对象的右下角坐标(左上角 + 宽高)
|
||||
float currentMaxX = x + width;
|
||||
float currentMaxY = y + height;
|
||||
// 初始化或更新min/max值
|
||||
if (isFirst)
|
||||
{
|
||||
minX = x;
|
||||
minY = y;
|
||||
maxX = currentMaxX;
|
||||
maxY = currentMaxY;
|
||||
isFirst = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
minX = std::min(minX, x);
|
||||
minY = std::min(minY, y);
|
||||
maxX = std::max(maxX, currentMaxX);
|
||||
maxY = std::max(maxY, currentMaxY);
|
||||
}
|
||||
|
||||
child = child->GetNext();
|
||||
}
|
||||
// 计算最终的包围盒矩形
|
||||
if (!isFirst) // 至少有一个子对象时才计算
|
||||
{
|
||||
m_RenderRect.x = minX; // 矩形左上角X
|
||||
m_RenderRect.y = minY; // 矩形左上角Y
|
||||
m_RenderRect.w = maxX - minX; // 矩形宽度(右下角X - 左上角X)
|
||||
m_RenderRect.h = maxY - minY; // 矩形高度(右下角Y - 左上角Y)
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationManager::Render()
|
||||
{
|
||||
Actor::Render();
|
||||
}
|
||||
|
||||
void AnimationManager::AddAnimation(RefPtr<Animation> ani)
|
||||
{
|
||||
this->AddChild(ani);
|
||||
}
|
||||
|
||||
void AnimationManager::Clear()
|
||||
{
|
||||
this->RemoveAllChild();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Animation.h"
|
||||
#include <vector>
|
||||
class AnimationManager : public Actor
|
||||
{
|
||||
private:
|
||||
SDL_Texture *m_Texture = nullptr;
|
||||
SDL_FRect m_RenderRect = {0, 0, 0, 0};
|
||||
|
||||
public:
|
||||
AnimationManager();
|
||||
// void Update(float deltaTime) override;
|
||||
void PreRender() override;
|
||||
void Render() override;
|
||||
|
||||
public:
|
||||
// 添加Ani
|
||||
void AddAnimation(RefPtr<Animation> ani);
|
||||
// 清空Ani
|
||||
void Clear();
|
||||
};
|
||||
132
source/EngineFrame/Component/AnimationMap.cpp
Normal file
132
source/EngineFrame/Component/AnimationMap.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "AnimationMap.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "EngineFrame/Render/RenderManager.h"
|
||||
AnimationMap::~AnimationMap()
|
||||
{
|
||||
}
|
||||
|
||||
void AnimationMap::CompleteConstruction()
|
||||
{
|
||||
m_size = {800, 600};
|
||||
// 遍历自己的所持有的所有Ani 取最大的尺寸
|
||||
auto &ac = this->GetAllChildren();
|
||||
RefPtr<Node> child = ac.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
Animation *anim = static_cast<Animation *>(child.Get());
|
||||
auto size = anim->GetMaxSize();
|
||||
if (size.width > m_size.width)
|
||||
m_size.width = size.width;
|
||||
if (size.height > m_size.height)
|
||||
m_size.height = size.height;
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
SetSize(m_size);
|
||||
// 创建指定大小的纹理
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(m_size);
|
||||
|
||||
// 构造FBO
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
// 将目标纹理附加到FBO的颜色附着点
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, // 帧缓冲类型
|
||||
GL_COLOR_ATTACHMENT0, // 颜色附着点(可多个,这里用第一个)
|
||||
GL_TEXTURE_2D, // 纹理类型
|
||||
m_texture->getID(), // 目标纹理ID
|
||||
0 // 多级渐远纹理级别
|
||||
);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
|
||||
}
|
||||
|
||||
void AnimationMap::AddAnimation(RefPtr<Animation> animation)
|
||||
{
|
||||
this->AddChild(animation);
|
||||
}
|
||||
|
||||
void AnimationMap::Reset()
|
||||
{
|
||||
auto &ac = this->GetAllChildren();
|
||||
RefPtr<Node> child = ac.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
Animation *anim = static_cast<Animation *>(child.Get());
|
||||
anim->Reset();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationMap::Render()
|
||||
{
|
||||
Actor::PreRender();
|
||||
Actor::PrepareToRender();
|
||||
Actor::OnRender();
|
||||
}
|
||||
|
||||
void AnimationMap::OnRender()
|
||||
{
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
renderer->DrawTexture(m_texture);
|
||||
}
|
||||
|
||||
void AnimationMap::OnUpdate(float deltaTime)
|
||||
{
|
||||
Actor::OnUpdate(deltaTime);
|
||||
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
// 绑定FBO
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
// 清屏
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// 保存原始的正交矩阵 设置纹理对应的正交矩阵 和 视口
|
||||
Oom = renderer->GetOrthoMatrix();
|
||||
renderer->SetOrthoMatrix(glm::ortho(0.0f, (float)m_size.width, 0.0f, (float)m_size.height, -1.0f, 1.0f));
|
||||
Oviewport = renderer->GetViewport();
|
||||
renderer->SetViewport({0, 0, m_size.width, m_size.height});
|
||||
// 以上步骤将渲染目标调整至AniMap的纹理上
|
||||
|
||||
SDL_Rect buf;
|
||||
buf.x = 0;
|
||||
buf.y = 0;
|
||||
buf.w = m_size.width;
|
||||
buf.h = m_size.height;
|
||||
glm::vec4 red = {0.0f, 0.0f, 1.0f, 0.4f}; // RGBA:红色,不透明基础色
|
||||
Game::GetInstance().GetRenderer()->DrawRect(&buf, red);
|
||||
|
||||
auto &ac = this->GetAllChildren();
|
||||
RefPtr<Node> child = ac.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
child->Render();
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
// 渲染完毕后,将渲染目标恢复为默认
|
||||
// 解绑FBO
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
// 恢复原始的正交矩阵 和 视口
|
||||
renderer->SetOrthoMatrix(Oom);
|
||||
renderer->SetViewport(Oviewport);
|
||||
|
||||
Actor::OnUpdate(deltaTime);
|
||||
}
|
||||
|
||||
// void AnimationMap::SetVisible(bool visible)
|
||||
// {
|
||||
// if (this->IsVisible() == visible)
|
||||
// return;
|
||||
// Actor::SetVisible(visible);
|
||||
// auto ac = this->GetAllChildren();
|
||||
// RefPtr<Node> next;
|
||||
// for (RefPtr<Node> child = ac.GetFirst(); child; child = next)
|
||||
// {
|
||||
// next = child->GetNext();
|
||||
// child->SetVisible(visible);
|
||||
// }
|
||||
// }
|
||||
|
||||
AnimationMap::AnimationMap()
|
||||
{
|
||||
}
|
||||
36
source/EngineFrame/Component/AnimationMap.h
Normal file
36
source/EngineFrame/Component/AnimationMap.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "Animation.h"
|
||||
class AnimationMap : public Actor
|
||||
{
|
||||
private:
|
||||
/**纹理 */
|
||||
RefPtr<Texture> m_texture = nullptr;
|
||||
/**FBO */
|
||||
GLuint m_fbo = 0;
|
||||
/**大小 */
|
||||
VecSize m_size;
|
||||
/**原始的正交矩阵 */
|
||||
glm::mat4 Oom;
|
||||
/**原始的视口 */
|
||||
SDL_Rect Oviewport;
|
||||
|
||||
public:
|
||||
AnimationMap(/* args */);
|
||||
~AnimationMap();
|
||||
|
||||
/**完成构造
|
||||
* 必须调用完成构造以创建足够大小的画布和各项初始化
|
||||
*/
|
||||
void CompleteConstruction();
|
||||
/**添加动画 */
|
||||
void AddAnimation(RefPtr<Animation> animation);
|
||||
|
||||
/**重置动画组 */
|
||||
void Reset();
|
||||
|
||||
void Render() override;
|
||||
void OnRender() override;
|
||||
void OnUpdate(float deltaTime) override;
|
||||
// void SetVisible(bool visible) override;
|
||||
};
|
||||
@@ -1,15 +1,29 @@
|
||||
#include "Canvas.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "EngineFrame/Render/RenderManager.h"
|
||||
Canvas::Canvas()
|
||||
{
|
||||
|
||||
}
|
||||
Canvas::Canvas(VecSize size)
|
||||
{
|
||||
Init(size);
|
||||
}
|
||||
|
||||
Canvas::Canvas(int width, int height)
|
||||
{
|
||||
Init({width, height});
|
||||
}
|
||||
|
||||
void Canvas::Init(VecSize size)
|
||||
{
|
||||
m_size = size;
|
||||
SetSize(size);
|
||||
// 创建指定大小的纹理
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(size);
|
||||
m_sprite = new Sprite();
|
||||
m_sprite->SetTexture(m_texture);
|
||||
|
||||
Actor::Init();
|
||||
m_texture->Init(m_size);
|
||||
|
||||
// 构造FBO
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
// 将目标纹理附加到FBO的颜色附着点
|
||||
@@ -23,40 +37,86 @@ Canvas::Canvas(VecSize size)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
|
||||
}
|
||||
|
||||
void Canvas::PreRender()
|
||||
void Canvas::BeginDraw()
|
||||
{
|
||||
if (m_dirty)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // 绑定FBO
|
||||
// glViewport(0, 0, m_texture->getSize().width, m_texture->getSize().height);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 全透明黑色
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
Actor::PreRender();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sprite->PreRender();
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::Render()
|
||||
{
|
||||
if (m_dirty)
|
||||
{
|
||||
|
||||
Actor::Render();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
|
||||
// glViewport(0, 0, Game::GetInstance().Screen_W, Game::GetInstance().Screen_H);
|
||||
m_dirty = false;
|
||||
}
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
renderer->SetCurrentShaderProgram("flip_y");
|
||||
m_sprite->Render();
|
||||
renderer->SetCurrentShaderProgram("normal");
|
||||
// 绑定FBO
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
// 清屏
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// 保存原始的正交矩阵 设置纹理对应的正交矩阵 和 视口
|
||||
Oom = renderer->GetOrthoMatrix();
|
||||
renderer->SetOrthoMatrix(glm::ortho(0.0f, (float)m_size.width, 0.0f, (float)m_size.height, -1.0f, 1.0f));
|
||||
Oviewport = renderer->GetViewport();
|
||||
renderer->SetViewport({0, 0, m_size.width, m_size.height});
|
||||
|
||||
}
|
||||
|
||||
void Canvas::AddChild(RefPtr<BaseNode> child)
|
||||
void Canvas::EndDraw()
|
||||
{
|
||||
m_dirty = true;
|
||||
Actor::AddChild(child);
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
// 解绑FBO
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
// 恢复原始的正交矩阵 和 视口
|
||||
renderer->SetOrthoMatrix(Oom);
|
||||
renderer->SetViewport(Oviewport);
|
||||
}
|
||||
|
||||
void Canvas::DrawActor(RefPtr<Actor> actor)
|
||||
{
|
||||
// 计算矩阵
|
||||
actor->PreRender();
|
||||
// 设定矩阵并渲染(Render中会调用OnRender)
|
||||
actor->Render();
|
||||
}
|
||||
|
||||
void Canvas::Clear()
|
||||
{
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(m_size);
|
||||
}
|
||||
|
||||
void Canvas::OnRender()
|
||||
{
|
||||
if (!m_texture || !IsVisible())
|
||||
return;
|
||||
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
if (this->_BlendMode != NONE)
|
||||
{
|
||||
renderer->SetBlendMode(this->_BlendMode);
|
||||
}
|
||||
renderer->DrawTexture(m_texture);
|
||||
if (this->_BlendMode != NONE)
|
||||
{
|
||||
renderer->SetBlendMode(NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// void Canvas::Render()
|
||||
// {
|
||||
// RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
// SDL_FPoint AnchorPos = {0, 0};
|
||||
// if (m_dirty)
|
||||
// {
|
||||
// glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // 绑定FBO
|
||||
// glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// glClear(GL_COLOR_BUFFER_BIT);
|
||||
// for (auto &info : m_drawQueue)
|
||||
// {
|
||||
// renderer->DrawTexture(m_imgMap[info.texture], nullptr, &info.rect, 0.f, &AnchorPos, SDL_FLIP_NONE);
|
||||
// }
|
||||
// glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
|
||||
// m_dirty = false;
|
||||
// }
|
||||
|
||||
// renderer->SetCurrentShaderProgram("flip_y");
|
||||
// // 混合
|
||||
// if (this->_BlendMode != NONE)
|
||||
// Blend();
|
||||
// renderer->DrawTexture(m_texture, &m_renderRect, &m_rect, 0.f, &AnchorPos, SDL_FLIP_NONE);
|
||||
// // 还原混合
|
||||
// if (this->_BlendMode != NONE)
|
||||
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// renderer->SetCurrentShaderProgram("normal");
|
||||
// }
|
||||
|
||||
@@ -1,23 +1,54 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "EngineFrame/Render/Texture.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
class Canvas : public Actor
|
||||
{
|
||||
struct ImgKey
|
||||
{
|
||||
std::string img;
|
||||
int index;
|
||||
|
||||
bool operator<(const ImgKey &other) const
|
||||
{
|
||||
if (img != other.img)
|
||||
{
|
||||
return img < other.img; // 字符串按字典序比较
|
||||
}
|
||||
return index < other.index; // 字符串相同则比较index
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/**纹理 */
|
||||
RefPtr<Texture> m_texture = nullptr;
|
||||
/**精灵 */
|
||||
RefPtr<Sprite> m_sprite = nullptr;
|
||||
/**脏标记 */
|
||||
bool m_dirty = true;
|
||||
/**大小 */
|
||||
VecSize m_size;
|
||||
/**FBO */
|
||||
GLuint m_fbo = 0;
|
||||
|
||||
public:
|
||||
Canvas(VecSize size);
|
||||
/**原始的正交矩阵 */
|
||||
glm::mat4 Oom;
|
||||
/**原始的视口 */
|
||||
SDL_Rect Oviewport;
|
||||
|
||||
void PreRender() override;
|
||||
void Render() override;
|
||||
void AddChild(RefPtr<BaseNode> child) override;
|
||||
public:
|
||||
Canvas();
|
||||
Canvas(VecSize size);
|
||||
Canvas(int width, int height);
|
||||
|
||||
/**初始化 */
|
||||
void Init(VecSize size);
|
||||
|
||||
/**开始绘制 */
|
||||
void BeginDraw();
|
||||
/**结束绘制 */
|
||||
void EndDraw();
|
||||
/**绘制角色 */
|
||||
void DrawActor(RefPtr<Actor> actor);
|
||||
/**清空画布 */
|
||||
void Clear();
|
||||
|
||||
/**重载OnRender函数 */
|
||||
void OnRender() override;
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "Component.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
|
||||
void Component::Init()
|
||||
{
|
||||
addTag(Tag::COMPONENT);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/BaseNode.h"
|
||||
|
||||
#include <SDL.h>
|
||||
class Actor;
|
||||
class Component : public BaseNode
|
||||
{
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
};
|
||||
104
source/EngineFrame/Component/NumberText.cpp
Normal file
104
source/EngineFrame/Component/NumberText.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "NumberText.h"
|
||||
|
||||
void NumberText::PreloadDigits()
|
||||
{
|
||||
// 需要支持的字符:0-9和负号
|
||||
const std::string digits = "0123456789-";
|
||||
for (char c : digits)
|
||||
{
|
||||
std::string charStr(1, c);
|
||||
// 渲染单个字符为纹理
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended(m_font, charStr.c_str(), m_color);
|
||||
if (!surface)
|
||||
{
|
||||
SDL_LogError(0, "数字字符渲染数字字符失败:%s", TTF_GetError());
|
||||
continue;
|
||||
}
|
||||
// 转换为RGBA格式
|
||||
SDL_Surface *rgbaSurface = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
|
||||
SDL_FreeSurface(surface);
|
||||
// 创建纹理并缓存
|
||||
Texture *tex = new Texture();
|
||||
tex->Init(rgbaSurface);
|
||||
SDL_FreeSurface(rgbaSurface);
|
||||
m_digitTextures[c] = tex;
|
||||
}
|
||||
}
|
||||
|
||||
void NumberText::UpdateDigitSprites(const std::string &numStr)
|
||||
{
|
||||
// // 先释放旧的精灵
|
||||
// for (auto *sprite : m_digitSprites)
|
||||
// {
|
||||
// if (sprite)
|
||||
// {
|
||||
// delete sprite;
|
||||
// }
|
||||
// }
|
||||
// m_digitSprites.clear();
|
||||
|
||||
// // 计算总宽度(用于居中或左对齐)
|
||||
// int totalWidth = 0;
|
||||
// std::vector<int> charWidths; // 记录每个字符的宽度
|
||||
// for (char c : numStr)
|
||||
// {
|
||||
// auto it = m_digitTextures.find(c);
|
||||
// if (it == m_digitTextures.end())
|
||||
// continue; // 跳过不支持的字符
|
||||
// int w = it->second->getSize().width;
|
||||
// totalWidth += w;
|
||||
// charWidths.push_back(w);
|
||||
// }
|
||||
|
||||
// // 绘制每个字符(从左到右排列)
|
||||
// float currentX = GetWorldPos().x; // 基于当前位置排列
|
||||
// float currentY = GetWorldPos().y;
|
||||
// int index = 0;
|
||||
// for (char c : numStr)
|
||||
// {
|
||||
// auto it = m_digitTextures.find(c);
|
||||
// if (it == m_digitTextures.end())
|
||||
// continue;
|
||||
|
||||
// // 创建字符精灵
|
||||
// Sprite *sprite = new Sprite();
|
||||
// sprite->SetTexture(it->second);
|
||||
// sprite->SetPosition(Vec2(currentX, currentY));
|
||||
// sprite->SetSize(it->second->getSize());
|
||||
|
||||
// m_digitSprites.push_back(sprite);
|
||||
|
||||
// // 移动到下一个字符的位置(预留1px间距)
|
||||
// currentX += charWidths[index] + 1;
|
||||
// index++;
|
||||
// }
|
||||
}
|
||||
|
||||
NumberText::NumberText(TTF_Font *font, SDL_Color color) : m_font(font), m_color(color)
|
||||
{
|
||||
PreloadDigits();
|
||||
}
|
||||
|
||||
NumberText::~NumberText()
|
||||
{
|
||||
}
|
||||
|
||||
void NumberText::SetNumber(int number)
|
||||
{
|
||||
if (number == m_currentNumber)
|
||||
return; // 数字未变化则跳过
|
||||
m_currentNumber = number;
|
||||
|
||||
// 转换数字为字符串(处理负数)
|
||||
std::string numStr = std::to_string(number);
|
||||
UpdateDigitSprites(numStr); // 更新数字精灵布局
|
||||
}
|
||||
|
||||
void NumberText::Render()
|
||||
{
|
||||
// for (auto *sprite : m_digitSprites)
|
||||
// {
|
||||
// if (sprite)
|
||||
// sprite->Render();
|
||||
// }
|
||||
}
|
||||
44
source/EngineFrame/Component/NumberText.h
Normal file
44
source/EngineFrame/Component/NumberText.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "EngineFrame/Render/RenderManager.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// 数字文本类,高效处理数字更新
|
||||
class NumberText : public Text
|
||||
{
|
||||
private:
|
||||
// 字体
|
||||
TTF_Font *m_font;
|
||||
// 文本颜色
|
||||
SDL_Color m_color;
|
||||
|
||||
// 当前数字
|
||||
int m_currentNumber = 0;
|
||||
// 数字字符纹理缓存('0'-'9'和'-')
|
||||
std::unordered_map<char, RefPtr<Texture>> m_digitTextures;
|
||||
// 当前数字的字符精灵列表
|
||||
std::vector<Sprite *> m_digitSprites;
|
||||
|
||||
// 预加载0-9和负号的纹理
|
||||
void PreloadDigits();
|
||||
|
||||
// 更新数字精灵(根据新数字字符串重新排列字符)
|
||||
void UpdateDigitSprites(const std::string &numStr);
|
||||
|
||||
public:
|
||||
// 构造函数:指定字体、颜色和字符尺寸
|
||||
NumberText(TTF_Font *font, SDL_Color color);
|
||||
|
||||
~NumberText();
|
||||
|
||||
// 设置数字(核心方法:仅更新变化的数字部分)
|
||||
void SetNumber(int number);
|
||||
|
||||
int GetNumber() const { return m_currentNumber; }
|
||||
|
||||
// 重写Render,绘制所有数字字符
|
||||
void Render() override;
|
||||
};
|
||||
@@ -1,86 +0,0 @@
|
||||
#include "RenderBase.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
|
||||
RenderBase::RenderBase()
|
||||
{
|
||||
}
|
||||
|
||||
RenderBase::~RenderBase()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderBase::CalcRenderInfo()
|
||||
{
|
||||
this->CalcRenderInfoFlag = true;
|
||||
}
|
||||
|
||||
void RenderBase::Init()
|
||||
{
|
||||
Component::Init();
|
||||
// 标记该组件需要渲染和更新
|
||||
addTag(Tag::RENDER);
|
||||
addTag(Tag::UPDATE);
|
||||
addTag(Tag::TRANSFORM);
|
||||
// 计算渲染信息
|
||||
CalcRenderInfo();
|
||||
}
|
||||
|
||||
void RenderBase::Update(float deltaTime)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::Update(deltaTime);
|
||||
|
||||
}
|
||||
|
||||
void RenderBase::Render()
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::Render();
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationPos(VecFPos pos)
|
||||
{
|
||||
Component::SetIterationPos(pos);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationScale(VecFPos scale)
|
||||
{
|
||||
Component::SetIterationScale(scale);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationRotation(float angle)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::SetIterationRotation(angle);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetPos(VecFPos pos)
|
||||
{
|
||||
Component::SetPos(pos);
|
||||
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetScale(VecFPos scale)
|
||||
{
|
||||
Component::SetScale(scale);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetRotation(float angle)
|
||||
{
|
||||
Component::SetRotation(angle);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetAnchor(VecFPos anchor)
|
||||
{
|
||||
Component::SetAnchor(anchor);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Tool/TransformT.h"
|
||||
|
||||
class RenderBase : public Component
|
||||
{
|
||||
|
||||
public:
|
||||
struct RenderGuidanceInfo
|
||||
{
|
||||
SDL_FRect rect;
|
||||
// 旋转角度
|
||||
float rotation;
|
||||
// 翻转Flag
|
||||
SDL_RendererFlip flip = SDL_FLIP_NONE;
|
||||
// 锚点坐标
|
||||
VecFPos AnchorPos;
|
||||
// 是否显示
|
||||
bool Visible = true;
|
||||
// 是否在屏幕内
|
||||
bool IsInScreen = false;
|
||||
};
|
||||
|
||||
public:
|
||||
RenderBase(/* args */);
|
||||
~RenderBase();
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Render() override;
|
||||
|
||||
public:
|
||||
public:
|
||||
// 设置迭代的坐标
|
||||
void SetIterationPos(VecFPos pos) override;
|
||||
// 设置迭代的缩放
|
||||
void SetIterationScale(VecFPos scale) override;
|
||||
// 设置迭代的旋转角度
|
||||
void SetIterationRotation(float angle) override;
|
||||
|
||||
// 设置坐标
|
||||
void SetPos(VecFPos pos) override;
|
||||
// 设置缩放
|
||||
void SetScale(VecFPos scale) override;
|
||||
// 设置旋转角度
|
||||
void SetRotation(float angle) override;
|
||||
// 设置中心点
|
||||
void SetAnchor(VecFPos anchor) override;
|
||||
|
||||
// 计算渲染信息
|
||||
void CalcRenderInfo() override;
|
||||
};
|
||||
@@ -3,17 +3,31 @@
|
||||
#include "Text.h"
|
||||
#include "EngineFrame/Render/RenderManager.h"
|
||||
|
||||
void Sprite::GenerateRenderMatrix() const
|
||||
{
|
||||
Matrix3x2 RenderBuffer = Matrix3x2::Translation(glm::vec2(m_texture->getPos().x, m_texture->getPos().y)) * GetTransformMatrix();
|
||||
|
||||
// 构造OpenGl渲染矩阵
|
||||
render_matrix_ = glm::mat4(1.0f);
|
||||
// 填充旋转+缩放分量(2D 变换核心,对应 4x4 矩阵左上 2x2 区域)
|
||||
render_matrix_[0][0] = RenderBuffer[0]; // _11 → x轴缩放+旋转
|
||||
render_matrix_[0][1] = RenderBuffer[1]; // _12 → 影响y轴方向的旋转分量
|
||||
render_matrix_[1][0] = RenderBuffer[2]; // _21 → 影响x轴方向的旋转分量
|
||||
render_matrix_[1][1] = RenderBuffer[3]; // _22 → y轴缩放+旋转
|
||||
// 填充平移分量(对应 4x4 矩阵最后一行前两列,z轴平移为0)
|
||||
render_matrix_[3][0] = RenderBuffer[4]; // _31 → x方向平移(世界坐标)
|
||||
render_matrix_[3][1] = RenderBuffer[5]; // _32 → y方向平移(世界坐标)
|
||||
}
|
||||
|
||||
void Sprite::Init()
|
||||
{
|
||||
this->Size = m_texture->getSize();
|
||||
RenderBase::Init();
|
||||
SetSize(m_texture->getSize());
|
||||
}
|
||||
|
||||
void Sprite::SetTexture(RefPtr<Texture> texture)
|
||||
{
|
||||
m_texture = texture;
|
||||
Init();
|
||||
CalcRenderInfoLogic(); // 第一次计算
|
||||
}
|
||||
|
||||
Sprite::Sprite(std::string imgPath, int Index)
|
||||
@@ -23,7 +37,6 @@ Sprite::Sprite(std::string imgPath, int Index)
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(imgPath, Index);
|
||||
Init();
|
||||
CalcRenderInfoLogic(); // 第一次计算
|
||||
}
|
||||
|
||||
Sprite::Sprite(std::string PngPath)
|
||||
@@ -31,7 +44,6 @@ Sprite::Sprite(std::string PngPath)
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(PngPath);
|
||||
Init();
|
||||
CalcRenderInfoLogic(); // 第一次计算
|
||||
}
|
||||
|
||||
Sprite::~Sprite()
|
||||
@@ -43,151 +55,19 @@ RefPtr<Texture> Sprite::GetTexture()
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
void Sprite::CalcRenderInfoLogic()
|
||||
void Sprite::OnRender()
|
||||
{
|
||||
// 获取至在最终的父对象检查是否显示
|
||||
BaseNode *parentNode = this->GetParent();
|
||||
while (parentNode != nullptr)
|
||||
{
|
||||
if (parentNode->Visible == false)
|
||||
{
|
||||
_RenderGuidanceInfo.Visible = false;
|
||||
return;
|
||||
}
|
||||
parentNode = parentNode->GetParent();
|
||||
}
|
||||
_RenderGuidanceInfo.Visible = true;
|
||||
|
||||
// 计算缩放因子和翻转状态
|
||||
float scaleX = transformIter.scale.x * transform.scale.x;
|
||||
float scaleY = transformIter.scale.y * transform.scale.y;
|
||||
|
||||
// X轴和Y轴上是否翻转的标志
|
||||
bool flipX = scaleX < 0;
|
||||
bool flipY = scaleY < 0;
|
||||
|
||||
_RenderGuidanceInfo.flip = SDL_FLIP_NONE;
|
||||
// 更新翻转状态
|
||||
if (flipX)
|
||||
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip);
|
||||
if (flipY)
|
||||
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
|
||||
|
||||
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
|
||||
auto T_Size = m_texture->getSize();
|
||||
auto T_Pos = m_texture->getPos();
|
||||
float texturePosX = flipX ? -(T_Size.width + T_Pos.x) + SDL_abs(transform.position.x * 2) : T_Pos.x;
|
||||
float texturePosY = flipY ? -(T_Size.height + T_Pos.y) + SDL_abs(transform.position.y * 2) : T_Pos.y;
|
||||
|
||||
// 先计算Img坐标与精灵坐标合成后的真实坐标
|
||||
float RealPosX = transform.position.x + texturePosX;
|
||||
float RealPosY = transform.position.y + texturePosY;
|
||||
|
||||
// 计算在世界中的位置
|
||||
float baseX = transformIter.position.x + RealPosX;
|
||||
float baseY = transformIter.position.y + RealPosY;
|
||||
|
||||
// 获取当前帧的原始尺寸
|
||||
int frameWidth = Size.width;
|
||||
int frameHeight = Size.height;
|
||||
|
||||
// 原始锚点偏移(基于帧尺寸)
|
||||
float origAnchorOffsetX = int(frameWidth * Anchor.x);
|
||||
float origAnchorOffsetY = int(frameHeight * Anchor.y);
|
||||
|
||||
// 缩放的绝对值
|
||||
float absScaleX = SDL_fabs(scaleX);
|
||||
float absScaleY = SDL_fabs(scaleY);
|
||||
// 缩放后的尺寸
|
||||
float scaledWidth = frameWidth * absScaleX;
|
||||
float scaledHeight = frameHeight * absScaleY;
|
||||
// 缩放后的锚点偏移
|
||||
float scaledAnchorOffsetX = int(origAnchorOffsetX * absScaleX);
|
||||
float scaledAnchorOffsetY = int(origAnchorOffsetY * absScaleY);
|
||||
|
||||
// 计算缩放后的锚点偏移与原锚点偏移的差值
|
||||
float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
|
||||
float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
|
||||
|
||||
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
|
||||
float Xpos = baseX - scaleOffsetX;
|
||||
float Ypos = baseY - scaleOffsetY;
|
||||
|
||||
Xpos = (int)Xpos; // 强制转换为整数
|
||||
Ypos = (int)Ypos; // 强制转换为整数
|
||||
|
||||
// 更新渲染信息
|
||||
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
|
||||
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
|
||||
// 设置纹理透明度
|
||||
m_texture->setAlpha(this->Alpha);
|
||||
|
||||
// 屏幕内检测
|
||||
int screenWidth = Game::GetInstance().Screen_W;
|
||||
int screenHeight = Game::GetInstance().Screen_H;
|
||||
bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
|
||||
_RenderGuidanceInfo.IsInScreen = isInScreen;
|
||||
|
||||
// this->Size = {scaledWidth, scaledHeight};
|
||||
_RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;
|
||||
|
||||
CalcRenderInfoFlag = false;
|
||||
}
|
||||
|
||||
void Sprite::PreRender()
|
||||
{
|
||||
if (CalcRenderInfoFlag && Visible)
|
||||
CalcRenderInfoLogic();
|
||||
}
|
||||
|
||||
void Sprite::Render()
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
if (!m_texture)
|
||||
if (!m_texture || !IsVisible())
|
||||
return;
|
||||
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
|
||||
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
|
||||
if (this->_BlendMode != NONE)
|
||||
{
|
||||
SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
|
||||
|
||||
// 混合
|
||||
if (this->_BlendMode != NONE)
|
||||
Blend();
|
||||
|
||||
SDL_Rect srcrect = {0, 0, this->Size.width, this->Size.height};
|
||||
renderer->DrawTexture(m_texture, &srcrect, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
|
||||
|
||||
// 还原混合
|
||||
if (this->_BlendMode != NONE)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Game::GetInstance().m_RenderCount++;
|
||||
renderer->SetBlendMode(this->_BlendMode);
|
||||
}
|
||||
renderer->DrawTexture(m_texture);
|
||||
if (this->_BlendMode != NONE)
|
||||
{
|
||||
renderer->SetBlendMode(NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::SetBlendMode(LE_BlEND_MODE mode)
|
||||
{
|
||||
this->_BlendMode = mode;
|
||||
}
|
||||
|
||||
void Sprite::Blend()
|
||||
{
|
||||
switch (this->_BlendMode)
|
||||
{
|
||||
case LINEARDODGE:
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LE_BlEND_MODE Sprite::GetBlendMode()
|
||||
{
|
||||
return this->_BlendMode;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "Asset/Asset_ImagePack.h"
|
||||
#include "EngineFrame/Component/RenderBase.h"
|
||||
#include "EngineFrame/Render/Texture.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
|
||||
class Game;
|
||||
/**
|
||||
* @brief Sprite类,继承自Component类,用于表示游戏中的精灵组件
|
||||
*/
|
||||
class Sprite : public RenderBase
|
||||
class Sprite : public Actor
|
||||
{
|
||||
protected:
|
||||
RefPtr<Texture> m_texture = nullptr;
|
||||
@@ -18,30 +18,18 @@ public:
|
||||
Sprite(std::string imgPath, int Index);
|
||||
Sprite(std::string PngPath);
|
||||
~Sprite();
|
||||
void Render() override;
|
||||
void PreRender() override;
|
||||
void Clear() override;
|
||||
void Init() override;
|
||||
void SetTexture(RefPtr<Texture> texture);
|
||||
|
||||
void SetTexture(RefPtr<Texture> texture);
|
||||
RefPtr<Texture> GetTexture();
|
||||
|
||||
public:
|
||||
// 渲染信息
|
||||
RenderGuidanceInfo _RenderGuidanceInfo;
|
||||
// 混合模式
|
||||
LE_BlEND_MODE _BlendMode = NONE;
|
||||
/**重载生成渲染矩阵函数 */
|
||||
void GenerateRenderMatrix() const override;
|
||||
/**重载初始化函数 */
|
||||
void Init() override;
|
||||
/**重载渲染函数 */
|
||||
void OnRender() override;
|
||||
|
||||
public:
|
||||
std::string imgPath;
|
||||
int Index;
|
||||
|
||||
public:
|
||||
// 计算渲染信息
|
||||
void CalcRenderInfoLogic();
|
||||
// 设置混合模式
|
||||
void SetBlendMode(LE_BlEND_MODE mode);
|
||||
// 混合
|
||||
void Blend();
|
||||
// 获取混合模式
|
||||
LE_BlEND_MODE GetBlendMode();
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
~Text();
|
||||
|
||||
// 显式引入基类的Init方法,避免隐藏
|
||||
using Component::Init;
|
||||
using Actor::Init;
|
||||
void Init(std::string Str, TTF_Font *font, SDL_Color color);
|
||||
void Render() override;
|
||||
|
||||
|
||||
@@ -22,17 +22,21 @@ RenderManager::RenderManager(SDL_Window *window)
|
||||
int width, height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
// 设置视口
|
||||
glViewport(0, 0, width, height);
|
||||
SetViewport(SDL_Rect{0, 0, width, height});
|
||||
// 设置窗口尺寸
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
// 设置正交投影矩阵
|
||||
_orthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
|
||||
|
||||
// 游戏的初始正交投影矩阵
|
||||
_GameOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
|
||||
// UI的初始正交投影矩阵
|
||||
_UIOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
|
||||
|
||||
// 设置清屏颜色
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// 启用混合模式
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
// 默认设置标准alpha混合
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
@@ -40,6 +44,8 @@ RenderManager::RenderManager(SDL_Window *window)
|
||||
InitShaderProgram();
|
||||
// 初始化绘制2D纹理缓冲程序
|
||||
Init2DTextureProgram();
|
||||
// 初始化绘制矩形缓冲程序
|
||||
InitRectProgram();
|
||||
|
||||
// 设定默认使用的着色器程序和缓冲程序
|
||||
SetCurrentShaderProgram("normal");
|
||||
@@ -75,17 +81,17 @@ void RenderManager::InitShaderProgram()
|
||||
{
|
||||
if (!groupData.is_object())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误,跳过\n", groupName.c_str());
|
||||
SDL_LogError(0, "着色器组 %s 格式错误,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
if (!groupData.contains("vertex") || !groupData["vertex"].is_string())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 vertex 路径,跳过\n", groupName.c_str());
|
||||
SDL_LogError(0, "组 %s 缺少 vertex 路径,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
if (!groupData.contains("fragment") || !groupData["fragment"].is_string())
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 fragment 路径,跳过\n", groupName.c_str());
|
||||
SDL_LogError(0, "组 %s 缺少 fragment 路径,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
std::string vertPath = groupData["vertex"].get<std::string>();
|
||||
@@ -95,7 +101,7 @@ void RenderManager::InitShaderProgram()
|
||||
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath);
|
||||
if (vertexShader == 0 || fragmentShader == 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器编译失败,跳过\n", groupName.c_str());
|
||||
SDL_LogError(0, "组 %s 着色器编译失败,跳过\n", groupName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -109,7 +115,7 @@ void RenderManager::InitShaderProgram()
|
||||
{
|
||||
char infoLog[512];
|
||||
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器链接失败,失败原因: %s\n", groupName.c_str(), infoLog);
|
||||
SDL_LogError(0, "组 %s 着色器链接失败,失败原因: %s\n", groupName.c_str(), infoLog);
|
||||
}
|
||||
|
||||
_shaderProgramMap[groupName] = program;
|
||||
@@ -138,10 +144,10 @@ void RenderManager::Init2DTextureProgram()
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
@@ -154,126 +160,71 @@ void RenderManager::Init2DTextureProgram()
|
||||
glUseProgram(_currentShaderProgram);
|
||||
|
||||
// 获取uniform变量位置
|
||||
GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
|
||||
GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
|
||||
GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
|
||||
if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1)
|
||||
GLint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
|
||||
GLint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
|
||||
GLint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
|
||||
GLint _uOpacityLoc = glGetUniformLocation(_currentShaderProgram, "uOpacity");
|
||||
|
||||
if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1 || _uOpacityLoc == -1)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无法获取着色器 uniform 变量位置\n");
|
||||
SDL_LogError(0, "无法获取着色器 uniform 变量位置\n");
|
||||
}
|
||||
std::vector<GLuint> uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc};
|
||||
std::vector<GLint> uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc, _uOpacityLoc};
|
||||
|
||||
DrawLogicFunc drawFunc = [this](
|
||||
RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
|
||||
{
|
||||
GLuint texture = textureObj->getID();
|
||||
if (!texture || !dstrect)
|
||||
return;
|
||||
|
||||
glUseProgram(_currentShaderProgram);
|
||||
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
|
||||
// 平移
|
||||
model = glm::translate(model, glm::vec3(dstrect->x, dstrect->y, 0.0f));
|
||||
|
||||
// 计算旋转中心
|
||||
float centerX = center ? center->x : dstrect->w * 0.5f;
|
||||
float centerY = center ? center->y : dstrect->h * 0.5f;
|
||||
|
||||
// 旋转中心平移
|
||||
model = glm::translate(model, glm::vec3(centerX, centerY, 0.0f));
|
||||
|
||||
// 旋转
|
||||
if (angle != 0.0)
|
||||
{
|
||||
model = glm::rotate(model, glm::radians(static_cast<float>(angle)), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
// 旋转中心平移
|
||||
model = glm::translate(model, glm::vec3(-centerX, -centerY, 0.0f));
|
||||
|
||||
// 缩放和翻转
|
||||
float scaleX = dstrect->w;
|
||||
float scaleY = dstrect->h;
|
||||
|
||||
// 应用翻转(通过负缩放实现)
|
||||
if (flip & SDL_FLIP_HORIZONTAL)
|
||||
scaleX = -scaleX;
|
||||
if (flip & SDL_FLIP_VERTICAL)
|
||||
scaleY = -scaleY;
|
||||
|
||||
model = glm::scale(model, glm::vec3(scaleX, scaleY, 1.0f));
|
||||
|
||||
// 翻转后的位置补偿
|
||||
if (flip & SDL_FLIP_HORIZONTAL)
|
||||
{
|
||||
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
if (flip & SDL_FLIP_VERTICAL)
|
||||
{
|
||||
model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0f));
|
||||
}
|
||||
|
||||
// 设置着色器 uniforms
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model));
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_orthoMatrix));
|
||||
|
||||
// 绑定纹理并设置采样器
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glUniform1i(_currentRenderParams.UnimLocs[2], 0);
|
||||
|
||||
// 处理纹理裁剪
|
||||
int texWidth = textureObj->getSize().width;
|
||||
int texHeight = textureObj->getSize().height;
|
||||
|
||||
// 计算纹理坐标
|
||||
float minu, minv, maxu, maxv;
|
||||
if (srcrect)
|
||||
{
|
||||
minu = (float)srcrect->x / texWidth;
|
||||
minv = (float)srcrect->y / texHeight;
|
||||
maxu = (float)(srcrect->x + srcrect->w) / texWidth;
|
||||
maxv = (float)(srcrect->y + srcrect->h) / texHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
minu = 0.0f;
|
||||
minv = 0.0f;
|
||||
maxu = 1.0f;
|
||||
maxv = 1.0f;
|
||||
}
|
||||
|
||||
// 计算顶点位置(单位矩形,通过模型变换进行缩放和平移)
|
||||
float minx = 0.0f;
|
||||
float miny = 0.0f;
|
||||
float maxx = 1.0f;
|
||||
float maxy = 1.0f;
|
||||
|
||||
// 创建顶点数据(位置 + 纹理坐标)
|
||||
float vertices[] = {
|
||||
// 位置 // 纹理坐标
|
||||
minx, miny, minu, minv, // 左上
|
||||
maxx, miny, maxu, minv, // 右上
|
||||
maxx, maxy, maxu, maxv, // 右下
|
||||
minx, maxy, minu, maxv // 左下
|
||||
};
|
||||
|
||||
// 更新VBO数据
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
// 绘制纹理
|
||||
glBindVertexArray(_currentRenderParams.VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
};
|
||||
|
||||
GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, drawFunc};
|
||||
GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, nullptr};
|
||||
AddBufferObject("2DTexture", bufferObject);
|
||||
}
|
||||
|
||||
void RenderManager::InitRectProgram()
|
||||
{
|
||||
// 单位矩形顶点(仅位置,左下角(0,0),右上角(1,1))
|
||||
float vertices[] = {
|
||||
0.0f, 0.0f, // 左下
|
||||
1.0f, 0.0f, // 右下
|
||||
1.0f, 1.0f, // 右上
|
||||
0.0f, 1.0f // 左上
|
||||
};
|
||||
unsigned int indices[] = {0, 1, 2, 2, 3, 0}; // 固定索引
|
||||
|
||||
GLuint VAO, VBO, EBO;
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenBuffers(1, &EBO);
|
||||
|
||||
// 绑定并上传数据(GL_STATIC_DRAW:数据仅初始化一次,后续不修改)
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 静态数据
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 静态数据
|
||||
|
||||
// 配置顶点属性(仅位置,2个float,步长2*sizeof(float))
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// 解绑(恢复默认状态)
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
// 获取矩形着色器的Uniform位置(需提前准备矩形专用着色器)
|
||||
SetCurrentShaderProgram("rect"); // 假设着色器配置中“rect”为矩形专用着色器
|
||||
glUseProgram(_currentShaderProgram);
|
||||
GLint uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
|
||||
GLint uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
|
||||
GLint uColorLoc = glGetUniformLocation(_currentShaderProgram, "uColor");
|
||||
if (uModelLoc == -1 || uViewProjLoc == -1 || uColorLoc == -1)
|
||||
{
|
||||
SDL_LogError(0, "矩形着色器Uniform变量获取失败\n uModelLoc: %d, uViewProjLoc: %d, uColorLoc: %d\n", uModelLoc, uViewProjLoc, uColorLoc);
|
||||
return;
|
||||
}
|
||||
std::vector<GLint> uniformLocs = {uModelLoc, uViewProjLoc, uColorLoc};
|
||||
|
||||
// 将矩形渲染参数加入管理器
|
||||
GL_RenderParams rectBuffer = {VAO, VBO, EBO, uniformLocs, nullptr};
|
||||
AddBufferObject("Rect", rectBuffer);
|
||||
}
|
||||
|
||||
void RenderManager::SetCurrentShaderProgram(std::string name)
|
||||
{
|
||||
if (_shaderProgramMap.find(name) != _shaderProgramMap.end())
|
||||
@@ -281,7 +232,7 @@ void RenderManager::SetCurrentShaderProgram(std::string name)
|
||||
this->_currentShaderProgram = _shaderProgramMap[name];
|
||||
}
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到着色器程序: %s\n", name.c_str());
|
||||
SDL_LogError(0, "找不到着色器程序: %s\n", name.c_str());
|
||||
}
|
||||
|
||||
void RenderManager::SetCurrentBufferObject(std::string name)
|
||||
@@ -290,13 +241,14 @@ void RenderManager::SetCurrentBufferObject(std::string name)
|
||||
{
|
||||
this->_currentRenderParams = _RenderParamsMap[name];
|
||||
}
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str());
|
||||
// else
|
||||
// SDL_LogError(0, "找不到渲染参数: %s\n", name.c_str());
|
||||
}
|
||||
|
||||
void RenderManager::ClearScreen()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_frameRenderCount = 0;
|
||||
}
|
||||
|
||||
void RenderManager::SwapBuffer()
|
||||
@@ -315,12 +267,176 @@ void RenderManager::CloseClipRect()
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void RenderManager::DrawTexture(RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
|
||||
void RenderManager::SetOpacity(float opacity)
|
||||
{
|
||||
if (_currentRenderParams.DrawFunc != nullptr)
|
||||
_currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata);
|
||||
this->opacity_ = opacity;
|
||||
}
|
||||
|
||||
float RenderManager::GetOpacity()
|
||||
{
|
||||
return this->opacity_;
|
||||
}
|
||||
|
||||
void RenderManager::SetMatrix(glm::mat4 matrix)
|
||||
{
|
||||
this->_currentMatrix = matrix;
|
||||
}
|
||||
|
||||
glm::mat4 RenderManager::GetMatrix()
|
||||
{
|
||||
return this->_currentMatrix;
|
||||
}
|
||||
|
||||
void RenderManager::SetBlendMode(LE_BlEND_MODE blendMode)
|
||||
{
|
||||
switch (blendMode)
|
||||
{
|
||||
/**常规混合 */
|
||||
case NONE:
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
/**线性减淡 */
|
||||
case LINEARDODGE:
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderManager::DrawTexture(RefPtr<Texture> textureObj)
|
||||
{
|
||||
_frameRenderCount++; // 统计渲染次数
|
||||
glUseProgram(_currentShaderProgram);
|
||||
|
||||
GLuint texture = textureObj->getID();
|
||||
float texWidth = (float)textureObj->getSize().width;
|
||||
float texHeight = (float)textureObj->getSize().height;
|
||||
|
||||
glm::mat4 modelMat = _currentMatrix;
|
||||
|
||||
modelMat = glm::scale(modelMat, glm::vec3(texWidth, texHeight, 1.0f));
|
||||
|
||||
// 设置着色器 uniforms
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(modelMat));
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_OrthoMatrix));
|
||||
|
||||
// 绑定纹理并设置采样器
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glUniform1i(_currentRenderParams.UnimLocs[2], 0);
|
||||
glUniform1f(_currentRenderParams.UnimLocs[3], opacity_);
|
||||
|
||||
// 计算纹理坐标
|
||||
float minu, minv, maxu, maxv;
|
||||
if (false)
|
||||
{
|
||||
// minu = (float)srcrect->x / texWidth;
|
||||
// minv = (float)srcrect->y / texHeight;
|
||||
// maxu = (float)(srcrect->x + srcrect->w) / texWidth;
|
||||
// maxv = (float)(srcrect->y + srcrect->h) / texHeight;
|
||||
}
|
||||
else
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染逻辑函数\n");
|
||||
{
|
||||
minu = 0.0f;
|
||||
minv = 0.0f;
|
||||
maxu = 1.0f;
|
||||
maxv = 1.0f;
|
||||
}
|
||||
|
||||
// 计算顶点位置(单位矩形,通过模型变换进行缩放和平移)
|
||||
float minx = 0.0f;
|
||||
float miny = 0.0f;
|
||||
float maxx = 1.0f;
|
||||
float maxy = 1.0f;
|
||||
|
||||
// 创建顶点数据(位置 + 纹理坐标)
|
||||
float vertices[] = {
|
||||
// 位置 // 纹理坐标
|
||||
minx, miny, minu, minv, // 左上
|
||||
maxx, miny, maxu, minv, // 右上
|
||||
maxx, maxy, maxu, maxv, // 右下
|
||||
minx, maxy, minu, maxv // 左下
|
||||
};
|
||||
|
||||
// 更新VBO数据
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
|
||||
|
||||
// 绘制纹理
|
||||
glBindVertexArray(_currentRenderParams.VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理
|
||||
}
|
||||
|
||||
void RenderManager::DrawRect(const SDL_Rect *rect, glm::vec4 color)
|
||||
{
|
||||
// 1. 合法性检查(补充VAO/EBO存在性检查)
|
||||
if (!rect || _currentShaderProgram == 0 || _currentRenderParams.VAO == 0 || _currentRenderParams.EBO == 0)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "DrawRect:参数无效或缓冲未初始化\n");
|
||||
return;
|
||||
}
|
||||
SetCurrentShaderProgram("rect");
|
||||
SetCurrentBufferObject("Rect");
|
||||
_frameRenderCount++;
|
||||
|
||||
// 绑定VAO和EBO(GPU获取顶点数据和格式的关键)
|
||||
glBindVertexArray(_currentRenderParams.VAO);
|
||||
|
||||
// 3. 计算模型矩阵(通过缩放+平移,将单位矩形变换到目标位置和大小)
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
// 先平移到rect的左上角(OpenGL正交投影下Y轴向下,与SDL_Rect一致)
|
||||
model = glm::translate(model, glm::vec3((float)rect->x, (float)rect->y, 0.0f));
|
||||
// 再缩放到rect的宽高
|
||||
model = glm::scale(model, glm::vec3((float)rect->w, (float)rect->h, 1.0f));
|
||||
|
||||
// 4. 激活着色器并设置Uniform
|
||||
glUseProgram(_currentShaderProgram);
|
||||
// 4.1 模型矩阵(传递变换后的矩阵)
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model));
|
||||
// 4.2 投影矩阵(复用当前正交矩阵)
|
||||
glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_OrthoMatrix));
|
||||
// 4.3 颜色
|
||||
glUniform4fv(_currentRenderParams.UnimLocs[2], 1, glm::value_ptr(color));
|
||||
|
||||
// 5. 绘制矩形(6个索引对应2个三角形)
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// 6. 解绑资源(避免影响后续绘制)
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
SetCurrentShaderProgram("normal");
|
||||
SetCurrentBufferObject("2DTexture");
|
||||
}
|
||||
|
||||
void RenderManager::SetOrthoMatrixType(int type)
|
||||
{
|
||||
if (type == 0)
|
||||
_OrthoMatrix = _GameOrthoMatrix;
|
||||
else
|
||||
_OrthoMatrix = _UIOrthoMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 RenderManager::GetOrthoMatrix()
|
||||
{
|
||||
return _OrthoMatrix;
|
||||
}
|
||||
|
||||
void RenderManager::SetOrthoMatrix(glm::mat4 matrix)
|
||||
{
|
||||
_OrthoMatrix = matrix;
|
||||
}
|
||||
|
||||
void RenderManager::SetViewport(SDL_Rect viewport)
|
||||
{
|
||||
_viewport = viewport;
|
||||
glViewport(viewport.x, viewport.y, viewport.w, viewport.h);
|
||||
}
|
||||
|
||||
SDL_Rect RenderManager::GetViewport()
|
||||
{
|
||||
return _viewport;
|
||||
}
|
||||
|
||||
GLuint RenderManager::CompileShader(GLenum type, std::string Path)
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
GLuint VAO;
|
||||
GLuint VBO;
|
||||
GLuint EBO;
|
||||
std::vector<GLuint> UnimLocs;
|
||||
std::vector<GLint> UnimLocs;
|
||||
DrawLogicFunc DrawFunc = nullptr;
|
||||
};
|
||||
|
||||
@@ -31,8 +31,14 @@ private:
|
||||
// 窗口尺寸
|
||||
int _windowWidth;
|
||||
int _windowHeight;
|
||||
// 正交投影矩阵
|
||||
glm::mat4 _orthoMatrix;
|
||||
// 游戏正交投影矩阵
|
||||
glm::mat4 _GameOrthoMatrix;
|
||||
// UI的正交投影矩阵
|
||||
glm::mat4 _UIOrthoMatrix;
|
||||
// 渲染的正交投影矩阵
|
||||
glm::mat4 _OrthoMatrix;
|
||||
/**视口 */
|
||||
SDL_Rect _viewport;
|
||||
|
||||
// 渲染器上下文
|
||||
SDL_GLContext _ctx;
|
||||
@@ -46,29 +52,64 @@ private:
|
||||
// 当前使用渲染参数
|
||||
GL_RenderParams _currentRenderParams;
|
||||
|
||||
// 渲染透明度
|
||||
float opacity_ = 1.0f;
|
||||
// 渲染矩阵
|
||||
glm::mat4 _currentMatrix;
|
||||
|
||||
public:
|
||||
// 单帧渲染调用次数
|
||||
int _frameRenderCount = 0;
|
||||
|
||||
public:
|
||||
RenderManager(SDL_Window *window);
|
||||
~RenderManager();
|
||||
|
||||
// 初始化着色器程序
|
||||
/**初始化着色器程序 */
|
||||
void InitShaderProgram();
|
||||
// 初始化绘制2D纹理缓冲程序
|
||||
/**初始化绘制2D纹理缓冲程序 */
|
||||
void Init2DTextureProgram();
|
||||
// 设定当前使用的着色器程序
|
||||
/**初始化绘制矩形缓冲程序 */
|
||||
void InitRectProgram();
|
||||
/**设定当前使用的着色器程序 */
|
||||
void SetCurrentShaderProgram(std::string name);
|
||||
// 设定当前使用的缓冲对象
|
||||
/**设定当前使用的缓冲对象 */
|
||||
void SetCurrentBufferObject(std::string name);
|
||||
|
||||
// 清空屏幕
|
||||
/**清空屏幕 */
|
||||
void ClearScreen();
|
||||
// 交换缓冲区
|
||||
/**交换缓冲区 */
|
||||
void SwapBuffer();
|
||||
// 设置裁切区域
|
||||
/**设置裁切区域 */
|
||||
void SetClipRect(const SDL_Rect *rect);
|
||||
// 关闭裁切区域
|
||||
/**关闭裁切区域 */
|
||||
void CloseClipRect();
|
||||
// 绘制纹理
|
||||
void DrawTexture(RefPtr<Texture> texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata = nullptr);
|
||||
/**设置渲染透明度 */
|
||||
void SetOpacity(float opacity);
|
||||
/**获取渲染透明度 */
|
||||
float GetOpacity();
|
||||
/**设置渲染矩阵 */
|
||||
void SetMatrix(glm::mat4 matrix);
|
||||
/**获取渲染矩阵 */
|
||||
glm::mat4 GetMatrix();
|
||||
/**设置混合模式 */
|
||||
void SetBlendMode(LE_BlEND_MODE blendMode);
|
||||
|
||||
/**绘制纹理 */
|
||||
void DrawTexture(RefPtr<Texture> texture);
|
||||
/**绘制矩形 */
|
||||
void DrawRect(const SDL_Rect *rect, glm::vec4 color);
|
||||
|
||||
/**设置正交投影矩阵类型 */
|
||||
void SetOrthoMatrixType(int type);
|
||||
/**获取渲染的正交投影矩阵 */
|
||||
glm::mat4 GetOrthoMatrix();
|
||||
/**设置渲染的正交投影矩阵 */
|
||||
void SetOrthoMatrix(glm::mat4 matrix);
|
||||
/**设置视口 */
|
||||
void SetViewport(SDL_Rect viewport);
|
||||
/**获取视口 */
|
||||
SDL_Rect GetViewport();
|
||||
|
||||
private:
|
||||
// 编译着色器
|
||||
|
||||
@@ -32,12 +32,13 @@ bool Texture::Init(std::string PngPath)
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 对2D纹理设置环绕模式(S=X轴,T=Y轴)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// 放大过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// 处理像素对齐(确保SDL的像素行对齐与OpenGL兼容)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
@@ -100,8 +101,9 @@ bool Texture::Init(std::string ImgPath, int Index)
|
||||
|
||||
// 设置纹理参数(保持与原有SDL纹理相同的采样模式)
|
||||
// 环绕方式:重复
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 对2D纹理设置环绕模式(S=X轴,T=Y轴)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// 过滤方式:最近邻(与SDL_ScaleModeNearest对应)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@@ -139,8 +141,9 @@ bool Texture::Init(SDL_Surface *rgbaSurface)
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 对2D纹理设置环绕模式(S=X轴,T=Y轴)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// 放大过滤:使用最近邻采样
|
||||
@@ -192,8 +195,9 @@ bool Texture::Init(VecSize size)
|
||||
m_FrameSize = size;
|
||||
|
||||
// 环绕方式
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// 对2D纹理设置环绕模式(S=X轴,T=Y轴)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
// 缩小过滤:使用最近邻采样
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// 放大过滤:使用最近邻采样
|
||||
|
||||
@@ -13,15 +13,14 @@ void Scene::Enter()
|
||||
|
||||
void Scene::Init()
|
||||
{
|
||||
BaseNode::Init();
|
||||
addTag(Tag::SCENE);
|
||||
|
||||
}
|
||||
|
||||
void Scene::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<BaseNode> Scene::GetCamera()
|
||||
RefPtr<Node> Scene::GetCamera()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/BaseNode.h"
|
||||
class Scene : public BaseNode
|
||||
#include "EngineFrame/Base/Node.h"
|
||||
class Scene : public Node
|
||||
{
|
||||
public:
|
||||
Scene();
|
||||
virtual void Enter();
|
||||
virtual void Exit();
|
||||
virtual RefPtr<BaseNode> GetCamera();
|
||||
virtual RefPtr<Node> GetCamera();
|
||||
void Init();
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
#include "math/Math.h"
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 不可拷贝对象
|
||||
class Noncopyable
|
||||
@@ -30,134 +32,6 @@ private:
|
||||
Noncopyable &operator=(const Noncopyable &) = delete;
|
||||
};
|
||||
|
||||
// 整数坐标向量
|
||||
typedef struct VecPos
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
// 构造函数,方便初始化
|
||||
VecPos(int x_ = 0, int y_ = 0) : x(x_), y(y_) {}
|
||||
|
||||
// 定义到 SDL_Point 的转换运算符
|
||||
operator SDL_Point() const
|
||||
{
|
||||
return {x, y}; // 直接返回包含 x、y 的 SDL_Point
|
||||
}
|
||||
// 转换为SDL_Point指针的运算符(用于指针场景)
|
||||
operator const SDL_Point *() const
|
||||
{
|
||||
// 注意:这里返回的是指向当前对象的指针,需确保对象生命周期有效
|
||||
return reinterpret_cast<const SDL_Point *>(this);
|
||||
}
|
||||
|
||||
// 加法运算符重载:两个 VecPos 相加
|
||||
VecPos operator+(const VecPos &other) const
|
||||
{
|
||||
return VecPos(x + other.x, y + other.y);
|
||||
}
|
||||
|
||||
// 减法运算符重载:两个 VecPos 相减
|
||||
VecPos operator-(const VecPos &other) const
|
||||
{
|
||||
return VecPos(x - other.x, y - other.y);
|
||||
}
|
||||
|
||||
// 等于运算符重载:判断两个 VecPos 是否相等
|
||||
bool operator==(const VecPos &other) const
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
// 复合赋值加法:当前对象加上另一个 VecPos
|
||||
VecPos &operator+=(const VecPos &other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 复合赋值减法:当前对象减去另一个 VecPos
|
||||
VecPos &operator-=(const VecPos &other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 乘法
|
||||
VecPos operator*(float value) const
|
||||
{
|
||||
return VecPos(x * value, y * value);
|
||||
}
|
||||
} VecPos;
|
||||
|
||||
// 浮点数坐标向量
|
||||
typedef struct VecFPos
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
// 构造函数,方便初始化
|
||||
VecFPos(float x_ = 0.0f, float y_ = 0.0f) : x(x_), y(y_) {}
|
||||
VecFPos(int x_, int y_ = 0) : x(static_cast<float>(x_)), y(static_cast<float>(y_)) {}
|
||||
|
||||
// 定义到 SDL_FPoint 的转换运算符
|
||||
operator SDL_FPoint() const
|
||||
{
|
||||
return {x, y}; // 直接返回包含 x、y 的 SDL_Point
|
||||
}
|
||||
|
||||
// 加法运算符重载:两个 VecFPos 相加
|
||||
VecFPos operator+(const VecFPos &other) const
|
||||
{
|
||||
return VecFPos(x + other.x, y + other.y);
|
||||
}
|
||||
|
||||
// 减法运算符重载:两个 VecFPos 相减
|
||||
VecFPos operator-(const VecFPos &other) const
|
||||
{
|
||||
return VecFPos(x - other.x, y - other.y);
|
||||
}
|
||||
|
||||
// 乘法运算符重载:两个 VecFPos 相乘
|
||||
VecFPos operator*(const VecFPos &other) const
|
||||
{
|
||||
return VecFPos(x * other.x, y * other.y);
|
||||
}
|
||||
|
||||
// 除法运算符重载:除以一个 float 值
|
||||
VecFPos operator/(float value) const
|
||||
{
|
||||
return VecFPos(x / value, y / value);
|
||||
}
|
||||
|
||||
// 等于运算符重载:判断两个 VecFPos 是否相等
|
||||
// 注意:浮点数比较需要考虑精度问题
|
||||
bool operator==(const VecFPos &other) const
|
||||
{
|
||||
// 使用一个小的epsilon值来比较浮点数
|
||||
const float epsilon = 0.0001f;
|
||||
return (fabs(x - other.x) < epsilon) && (fabs(y - other.y) < epsilon);
|
||||
}
|
||||
|
||||
// 复合赋值加法:当前对象加上另一个 VecFPos
|
||||
VecFPos &operator+=(const VecFPos &other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 复合赋值减法:当前对象减去另一个 VecFPos
|
||||
VecFPos &operator-=(const VecFPos &other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
return *this;
|
||||
}
|
||||
} VecFPos;
|
||||
|
||||
// 尺寸向量
|
||||
typedef struct VecSize
|
||||
{
|
||||
@@ -237,12 +111,41 @@ typedef struct VecPos3
|
||||
|
||||
} VecPos3;
|
||||
|
||||
typedef struct VecFPos3
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
VecFPos3(float x_ = 0, float y_ = 0, float z_ = 0) : x(x_), y(y_), z(z_) {}
|
||||
|
||||
VecFPos3 operator+(const VecFPos3 &other) const
|
||||
{
|
||||
return VecFPos3(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
VecFPos3 operator-(const VecFPos3 &other) const
|
||||
{
|
||||
return VecFPos3(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
bool operator==(const VecFPos3 &other) const
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
|
||||
bool operator!=(const VecFPos3 &other) const
|
||||
{
|
||||
return x != other.x || y != other.y || z != other.z;
|
||||
}
|
||||
|
||||
} VecFPos3;
|
||||
|
||||
typedef struct VecSpeed3
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
VecSpeed3(int x_ = 0, int y_ = 0, int z_ = 0) : x(x_), y(y_), z(z_) {}
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
VecSpeed3(float x_ = 0, float y_ = 0, float z_ = 0) : x(x_), y(y_), z(z_) {}
|
||||
|
||||
VecSpeed3 operator+(const VecSpeed3 &other) const
|
||||
{
|
||||
|
||||
@@ -31,6 +31,18 @@ int Ifstream_NPK::ReadInt()
|
||||
return Count;
|
||||
}
|
||||
|
||||
unsigned int Ifstream_NPK::ReadUnsignedInt()
|
||||
{
|
||||
char *CountBuffer = new char[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this->get(CountBuffer[i]);
|
||||
}
|
||||
unsigned int Count = *(unsigned int *)CountBuffer;
|
||||
delete[] CountBuffer;
|
||||
return Count;
|
||||
}
|
||||
|
||||
// 读字符串
|
||||
std::string Ifstream_NPK::ReadString()
|
||||
{
|
||||
@@ -60,7 +72,7 @@ std::string Ifstream_NPK::ReadInfo()
|
||||
}
|
||||
|
||||
// 读LONG
|
||||
int Ifstream_NPK::ReadLong()
|
||||
long Ifstream_NPK::ReadLong()
|
||||
{
|
||||
char *CountBuffer = new char[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -72,6 +84,18 @@ int Ifstream_NPK::ReadLong()
|
||||
return Count;
|
||||
}
|
||||
|
||||
unsigned long Ifstream_NPK::ReadUnsignedLong()
|
||||
{
|
||||
char *CountBuffer = new char[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
this->get(CountBuffer[i]);
|
||||
}
|
||||
unsigned long Count = *(unsigned long *)CountBuffer;
|
||||
delete[] CountBuffer;
|
||||
return Count;
|
||||
}
|
||||
|
||||
// 读指定长度数据
|
||||
BYTE *Ifstream_NPK::ReadCustomSize(int Size)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,9 @@ public:
|
||||
// 读整数
|
||||
int ReadInt();
|
||||
|
||||
// 读无符号整数
|
||||
unsigned int ReadUnsignedInt();
|
||||
|
||||
// 读字符串
|
||||
std::string ReadString();
|
||||
|
||||
@@ -29,7 +32,9 @@ public:
|
||||
std::string ReadInfo();
|
||||
|
||||
// 读LONG
|
||||
int ReadLong();
|
||||
long ReadLong();
|
||||
// 读取无符号long
|
||||
unsigned long ReadUnsignedLong();
|
||||
|
||||
// 读指定长度数据
|
||||
BYTE *ReadCustomSize(int Size);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -249,7 +249,7 @@ inline bool operator<(const RefBasePtr<_Ty, _RefPolicy> &lhs, const RefBasePtr<_
|
||||
}
|
||||
|
||||
// template class cannot specialize std::swap,
|
||||
// so implement a swap function in kiwano namespace
|
||||
// so implement a swap function in ember namespace
|
||||
template <class _Ty, class _RefPolicy>
|
||||
inline void swap(RefBasePtr<_Ty, _RefPolicy> &lhs, RefBasePtr<_Ty, _RefPolicy> &rhs) noexcept
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2018 Kiwano - Nomango
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#include "TransformT.h"
|
||||
|
||||
TransformT::TransformT()
|
||||
: rotation(0.f), position(), scale(1.f, 1.f)
|
||||
{
|
||||
}
|
||||
|
||||
bool TransformT::IsFast() const
|
||||
{
|
||||
return scale.x == 1.f && scale.y == 1.f && rotation == 0.f;
|
||||
}
|
||||
|
||||
bool TransformT::operator==(const TransformT &rhs) const
|
||||
{
|
||||
return position == rhs.position && rotation == rhs.rotation && scale == rhs.scale;
|
||||
}
|
||||
|
||||
// -------------------------- 加法运算符实现 --------------------------
|
||||
TransformT TransformT::operator+(const TransformT &rhs) const
|
||||
{
|
||||
TransformT result;
|
||||
result.rotation = this->rotation + rhs.rotation;
|
||||
result.position = this->position + rhs.position;
|
||||
result.scale = this->scale + rhs.scale;
|
||||
return result;
|
||||
}
|
||||
|
||||
TransformT TransformT::operator-(const TransformT &rhs) const
|
||||
{
|
||||
TransformT result;
|
||||
result.rotation = this->rotation - rhs.rotation;
|
||||
result.position = this->position - rhs.position;
|
||||
result.scale = this->scale - rhs.scale;
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------- 复合赋值运算符实现 --------------------------
|
||||
TransformT &TransformT::operator+=(const TransformT &rhs)
|
||||
{
|
||||
this->rotation += rhs.rotation;
|
||||
this->position += rhs.position;
|
||||
this->scale += rhs.scale;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TransformT &TransformT::operator-=(const TransformT &rhs)
|
||||
{
|
||||
this->rotation -= rhs.rotation;
|
||||
this->position -= rhs.position;
|
||||
this->scale -= rhs.scale;
|
||||
return *this;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
#include "Tool/Common.h"
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 二维放射变换
|
||||
*/
|
||||
class TransformT
|
||||
{
|
||||
public:
|
||||
float rotation; ///< 旋转
|
||||
VecFPos position; ///< 坐标
|
||||
VecFPos scale; ///< 缩放
|
||||
|
||||
public:
|
||||
TransformT();
|
||||
|
||||
bool IsFast() const;
|
||||
|
||||
bool operator==(const TransformT &rhs) const;
|
||||
|
||||
TransformT operator+(const TransformT &rhs) const;
|
||||
TransformT operator-(const TransformT &rhs) const;
|
||||
TransformT &operator+=(const TransformT &rhs);
|
||||
TransformT &operator-=(const TransformT &rhs);
|
||||
};
|
||||
40
source/math/Constants.h
Normal file
40
source/math/Constants.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
constexpr auto PI_F = 3.141592653589793f;
|
||||
constexpr auto PI_F_2 = 1.570796326794896f;
|
||||
constexpr auto PI_F_X_2 = 6.283185307179586f;
|
||||
|
||||
constexpr auto PI_D = 3.14159265358979323846;
|
||||
constexpr auto PI_D_2 = 1.57079632679489661923;
|
||||
constexpr auto PI_D_X_2 = 6.28318530717958647692;
|
||||
|
||||
constexpr auto FLOAT_MAX = 3.402823466e+38F;
|
||||
constexpr auto FLOAT_MIN = 1.175494351e-38F;
|
||||
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
278
source/math/EaseFunctions.h
Normal file
278
source/math/EaseFunctions.h
Normal file
@@ -0,0 +1,278 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <math/Scalar.h>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
inline float Linear(float step)
|
||||
{
|
||||
return step;
|
||||
}
|
||||
|
||||
// Ease
|
||||
|
||||
inline float EaseIn(float step, float rate)
|
||||
{
|
||||
return math::Pow(step, rate);
|
||||
}
|
||||
|
||||
inline float EaseOut(float step, float rate)
|
||||
{
|
||||
return math::Pow(step, 1.f / rate);
|
||||
}
|
||||
|
||||
inline float EaseInOut(float step, float rate)
|
||||
{
|
||||
if (step < .5f)
|
||||
return .5f * math::Pow(2 * step, rate);
|
||||
return 1.f - .5f * math::Pow(2.f - 2 * step, rate);
|
||||
}
|
||||
|
||||
// Exponential Ease
|
||||
|
||||
inline float EaseExponentialIn(float step)
|
||||
{
|
||||
return math::Pow(2.f, 10 * (step - 1));
|
||||
}
|
||||
|
||||
inline float EaseExponentialOut(float step)
|
||||
{
|
||||
return 1.f - math::Pow(2.f, -10 * step);
|
||||
}
|
||||
|
||||
inline float EaseExponentialInOut(float step)
|
||||
{
|
||||
if (step < .5f)
|
||||
return .5f * math::Pow(2.f, 10 * (2 * step - 1));
|
||||
return 0.5f * (2 - math::Pow(2, -10 * (step * 2 - 1)));
|
||||
}
|
||||
|
||||
// Bounce Ease
|
||||
|
||||
inline float EaseBounceOut(float step)
|
||||
{
|
||||
if (step < 1 / 2.75f)
|
||||
{
|
||||
return 7.5625f * step * step;
|
||||
}
|
||||
else if (step < 2 / 2.75f)
|
||||
{
|
||||
step -= 1.5f / 2.75f;
|
||||
return 7.5625f * step * step + 0.75f;
|
||||
}
|
||||
else if (step < 2.5f / 2.75f)
|
||||
{
|
||||
step -= 2.25f / 2.75f;
|
||||
return 7.5625f * step * step + 0.9375f;
|
||||
}
|
||||
|
||||
step -= 2.625f / 2.75f;
|
||||
return 7.5625f * step * step + 0.984375f;
|
||||
}
|
||||
|
||||
inline float EaseBounceIn(float step)
|
||||
{
|
||||
return 1 - EaseBounceOut(1 - step);
|
||||
}
|
||||
|
||||
inline float EaseBounceInOut(float step)
|
||||
{
|
||||
if (step < 0.5f)
|
||||
{
|
||||
return EaseBounceIn(step * 2) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EaseBounceOut(step * 2 - 1) * 0.5f + 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Elastic Ease
|
||||
|
||||
inline float EaseElasticIn(float step, float period)
|
||||
{
|
||||
if (step == 0 || step == 1)
|
||||
return step;
|
||||
|
||||
step = step - 1;
|
||||
return -math::Pow(2, 10 * step) * math::Sin((step - period / 4) * 360.f / period);
|
||||
}
|
||||
|
||||
inline float EaseElasticOut(float step, float period)
|
||||
{
|
||||
if (step == 0 || step == 1)
|
||||
return step;
|
||||
|
||||
return math::Pow(2, -10 * step) * math::Sin((step - period / 4) * 360.f / period) + 1;
|
||||
}
|
||||
|
||||
inline float EaseElasticInOut(float step, float period)
|
||||
{
|
||||
if (step == 0 || step == 1)
|
||||
return step;
|
||||
|
||||
step = step * 2 - 1;
|
||||
if (step < 0)
|
||||
{
|
||||
return -0.5f * math::Pow(2, 10 * step) * math::Sin((step - period / 4) * 360.f / period);
|
||||
}
|
||||
return math::Pow(2, -10 * step) * math::Sin((step - period / 4) * 360.f / period) * 0.5f + 1;
|
||||
}
|
||||
|
||||
// Back Ease
|
||||
|
||||
inline float EaseBackIn(float step)
|
||||
{
|
||||
const float overshoot = 1.70158f;
|
||||
return step * step * ((overshoot + 1) * step - overshoot);
|
||||
}
|
||||
|
||||
inline float EaseBackOut(float step)
|
||||
{
|
||||
const float overshoot = 1.70158f;
|
||||
step = step - 1;
|
||||
return step * step * ((overshoot + 1) * step + overshoot) + 1;
|
||||
}
|
||||
|
||||
inline float EaseBackInOut(float step)
|
||||
{
|
||||
const float overshoot = 1.70158f * 1.525f;
|
||||
|
||||
step = step * 2;
|
||||
if (step < 1)
|
||||
{
|
||||
return (step * step * ((overshoot + 1) * step - overshoot)) / 2;
|
||||
}
|
||||
|
||||
step = step - 2;
|
||||
return (step * step * ((overshoot + 1) * step + overshoot)) / 2 + 1;
|
||||
}
|
||||
|
||||
// Sine Ease
|
||||
|
||||
inline float EaseSineIn(float step)
|
||||
{
|
||||
return 1.f - math::Cos(step * 90);
|
||||
}
|
||||
|
||||
inline float EaseSineOut(float step)
|
||||
{
|
||||
return math::Sin(step * 90);
|
||||
}
|
||||
|
||||
inline float EaseSineInOut(float step)
|
||||
{
|
||||
return -0.5f * (math::Cos(step * 180) - 1);
|
||||
}
|
||||
|
||||
// Quad Ease
|
||||
|
||||
inline float EaseQuadIn(float step)
|
||||
{
|
||||
return step * step;
|
||||
}
|
||||
|
||||
inline float EaseQuadOut(float step)
|
||||
{
|
||||
return -1 * step * (step - 2);
|
||||
}
|
||||
|
||||
inline float EaseQuadInOut(float step)
|
||||
{
|
||||
step = step * 2;
|
||||
if (step < 1)
|
||||
return 0.5f * step * step;
|
||||
--step;
|
||||
return -0.5f * (step * (step - 2) - 1);
|
||||
}
|
||||
|
||||
// Cubic Ease
|
||||
|
||||
inline float EaseCubicIn(float step)
|
||||
{
|
||||
return step * step * step;
|
||||
}
|
||||
|
||||
inline float EaseCubicOut(float step)
|
||||
{
|
||||
step -= 1;
|
||||
return (step * step * step + 1);
|
||||
}
|
||||
|
||||
inline float EaseCubicInOut(float step)
|
||||
{
|
||||
step = step * 2;
|
||||
if (step < 1)
|
||||
return 0.5f * step * step * step;
|
||||
step -= 2;
|
||||
return 0.5f * (step * step * step + 2);
|
||||
}
|
||||
|
||||
// Quart Ease
|
||||
|
||||
inline float EaseQuartIn(float step)
|
||||
{
|
||||
return step * step * step * step;
|
||||
}
|
||||
|
||||
inline float EaseQuartOut(float step)
|
||||
{
|
||||
step -= 1;
|
||||
return -(step * step * step * step - 1);
|
||||
}
|
||||
|
||||
inline float EaseQuartInOut(float step)
|
||||
{
|
||||
step = step * 2;
|
||||
if (step < 1)
|
||||
return 0.5f * step * step * step * step;
|
||||
step -= 2;
|
||||
return -0.5f * (step * step * step * step - 2);
|
||||
}
|
||||
|
||||
// Quint Ease
|
||||
|
||||
inline float EaseQuintIn(float step)
|
||||
{
|
||||
return step * step * step * step * step;
|
||||
}
|
||||
|
||||
inline float EaseQuintOut(float step)
|
||||
{
|
||||
step -= 1;
|
||||
return (step * step * step * step * step + 1);
|
||||
}
|
||||
|
||||
inline float EaseQuintInOut(float step)
|
||||
{
|
||||
step = step * 2;
|
||||
if (step < 1)
|
||||
return 0.5f * step * step * step * step * step;
|
||||
step -= 2;
|
||||
return 0.5f * (step * step * step * step * step + 2);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
153
source/math/Interpolator.h
Normal file
153
source/math/Interpolator.h
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <core/Function.h>
|
||||
#include <math/Vec2.hpp>
|
||||
#include <math/Rect.hpp>
|
||||
#include <math/Transform.hpp>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
template <typename _Method = void>
|
||||
struct InterpolateMethod;
|
||||
|
||||
template <>
|
||||
struct InterpolateMethod<void>
|
||||
{
|
||||
inline float operator()(float frac) const noexcept
|
||||
{
|
||||
return frac;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct InterpolateMethod<float (*)(float)>
|
||||
{
|
||||
float (*method)(float);
|
||||
|
||||
InterpolateMethod(float (*method)(float)) noexcept
|
||||
: method(method)
|
||||
{
|
||||
}
|
||||
|
||||
inline float operator()(float frac) const noexcept
|
||||
{
|
||||
if (method)
|
||||
return method(frac);
|
||||
return frac;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct InterpolateMethod<Function<float(float)>>
|
||||
{
|
||||
Function<float(float)> method;
|
||||
|
||||
InterpolateMethod(const Function<float(float)> &method) noexcept
|
||||
: method(method)
|
||||
{
|
||||
}
|
||||
|
||||
inline float operator()(float frac) const noexcept
|
||||
{
|
||||
if (method)
|
||||
return method(frac);
|
||||
return frac;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
class Interpolator;
|
||||
|
||||
template <typename _Ty>
|
||||
class Interpolator
|
||||
{
|
||||
public:
|
||||
template <typename _Method = void>
|
||||
inline _Ty Interpolate(_Ty start, _Ty end, float frac, const InterpolateMethod<_Method> &method = {})
|
||||
{
|
||||
if (frac >= 1)
|
||||
return end;
|
||||
return start + static_cast<_Ty>(static_cast<float>(end - start) * method(frac));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
class Interpolator<Vec2T<_Ty>>
|
||||
{
|
||||
public:
|
||||
template <typename _Method = void>
|
||||
inline Vec2T<_Ty> Interpolate(const Vec2T<_Ty> &start, const Vec2T<_Ty> &end, float frac,
|
||||
const InterpolateMethod<_Method> &method = {})
|
||||
{
|
||||
if (frac >= 1)
|
||||
return end;
|
||||
|
||||
Interpolator<_Ty> fi;
|
||||
return Vec2T<_Ty>{fi.Interpolate(start.x, end.x, frac, method), fi.Interpolate(start.y, end.y, frac, method)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
class Interpolator<RectT<_Ty>>
|
||||
{
|
||||
public:
|
||||
template <typename _Method = void>
|
||||
inline RectT<_Ty> Interpolate(const RectT<_Ty> &start, const RectT<_Ty> &end, float frac,
|
||||
const InterpolateMethod<_Method> &method = {})
|
||||
{
|
||||
if (frac >= 1)
|
||||
return end;
|
||||
|
||||
Interpolator<Vec2T<_Ty>> vi;
|
||||
return RectT<_Ty>{vi.Interpolate(start.left_top, end.left_top, frac, method),
|
||||
vi.Interpolate(start.right_bottom, end.right_bottom, frac, method)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
class Interpolator<TransformT<_Ty>>
|
||||
{
|
||||
public:
|
||||
template <typename _Method = void>
|
||||
inline TransformT<_Ty> Interpolate(const TransformT<_Ty> &start, const TransformT<_Ty> &end, float frac,
|
||||
const InterpolateMethod<_Method> &method = {})
|
||||
{
|
||||
if (frac >= 1)
|
||||
return end;
|
||||
|
||||
Interpolator<_Ty> fi;
|
||||
Interpolator<Vec2T<_Ty>> vi;
|
||||
|
||||
TransformT<_Ty> transform;
|
||||
transform.rotation = fi.Interpolate(start.rotation, end.rotation, frac, method);
|
||||
transform.position = vi.Interpolate(start.position, end.position, frac, method);
|
||||
transform.scale = vi.Interpolate(start.scale, end.scale, frac, method);
|
||||
transform.skew = vi.Interpolate(start.skew, end.skew, frac, method);
|
||||
return transform;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
39
source/math/Math.h
Normal file
39
source/math/Math.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <math/Vec2.hpp>
|
||||
#include <math/Rect.hpp>
|
||||
#include <math/Matrix.hpp>
|
||||
#include <math/Transform.hpp>
|
||||
#include <math/Constants.h>
|
||||
#include <math/EaseFunctions.h>
|
||||
#include <math/Scalar.h>
|
||||
|
||||
|
||||
using Vec2 = ember::math::Vec2T<float>;
|
||||
using VecPos = ember::math::Vec2T<int>;
|
||||
using Rect = ember::math::RectT<float>;
|
||||
using Matrix3x2 = ember::math::Matrix3x2T<float>;
|
||||
using Transform = ember::math::TransformT<float>;
|
||||
|
||||
|
||||
using Point = Vec2;
|
||||
using Size = Vec2;
|
||||
272
source/math/Matrix.hpp
Normal file
272
source/math/Matrix.hpp
Normal file
@@ -0,0 +1,272 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <math/Rect.hpp>
|
||||
#include <math/Vec2.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
template <typename _Ty, typename _Lty, typename _Rty>
|
||||
struct MatrixMultiply;
|
||||
|
||||
template <typename _Ty>
|
||||
struct Matrix3x2T
|
||||
{
|
||||
using ValueType = _Ty;
|
||||
using Vec2Type = glm::vec2;
|
||||
using RectType = RectT<ValueType>;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
_Ty m[6]; // m[3][2]
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
_Ty _11, _12, _21, _22, _31, _32;
|
||||
};
|
||||
};
|
||||
|
||||
Matrix3x2T()
|
||||
: _11(1.f), _12(0.f), _21(0.f), _22(1.f), _31(0.f), _32(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
Matrix3x2T(ValueType _11, ValueType _12, ValueType _21, ValueType _22, ValueType _31, ValueType _32)
|
||||
: _11(_11), _12(_12), _21(_21), _22(_22), _31(_31), _32(_32)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Matrix3x2T(const ValueType *p)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
m[i] = p[i];
|
||||
}
|
||||
|
||||
Matrix3x2T(const Matrix3x2T &other)
|
||||
: _11(other._11), _12(other._12), _21(other._21), _22(other._22), _31(other._31), _32(other._32)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename _MTy>
|
||||
Matrix3x2T(const _MTy &other)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
m[i] = other[i];
|
||||
}
|
||||
|
||||
inline ValueType operator[](uint32_t index) const
|
||||
{
|
||||
return m[index];
|
||||
}
|
||||
|
||||
inline ValueType &operator[](uint32_t index)
|
||||
{
|
||||
return m[index];
|
||||
}
|
||||
|
||||
inline Matrix3x2T &operator=(const Matrix3x2T &other)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
m[i] = other[i];
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template <typename _Lty, typename _Rty>
|
||||
inline Matrix3x2T &operator=(const MatrixMultiply<ValueType, _Lty, _Rty> &other)
|
||||
{
|
||||
Matrix3x2T result(other);
|
||||
(*this) = result;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Matrix3x2T &operator*=(const Matrix3x2T &other)
|
||||
{
|
||||
return operator=((*this) * other);
|
||||
}
|
||||
|
||||
inline void Identity()
|
||||
{
|
||||
_11 = 1.f;
|
||||
_12 = 0.f;
|
||||
_21 = 0.f;
|
||||
_22 = 1.f;
|
||||
_31 = 0.f;
|
||||
_32 = 0.f;
|
||||
}
|
||||
|
||||
inline bool IsIdentity() const
|
||||
{
|
||||
return _11 == 1.f && _12 == 0.f && _21 == 0.f && _22 == 1.f && _31 == 0.f && _32 == 0.f;
|
||||
}
|
||||
|
||||
inline Matrix3x2T Invert() const
|
||||
{
|
||||
ValueType det = 1.f / Determinant();
|
||||
return Matrix3x2T(det * _22, -det * _12, -det * _21, det * _11, det * (_21 * _32 - _22 * _31),
|
||||
det * (_12 * _31 - _11 * _32));
|
||||
}
|
||||
|
||||
inline bool IsInvertible() const
|
||||
{
|
||||
return 0 != Determinant();
|
||||
}
|
||||
|
||||
inline ValueType Determinant() const
|
||||
{
|
||||
return (_11 * _22) - (_12 * _21);
|
||||
}
|
||||
|
||||
inline Vec2Type Transform(const Vec2Type &v) const
|
||||
{
|
||||
return Vec2Type(v.x * _11 + v.y * _21 + _31, v.x * _12 + v.y * _22 + _32);
|
||||
}
|
||||
|
||||
RectType Transform(const RectType &rect) const
|
||||
{
|
||||
Vec2Type top_left = Transform(rect.GetLeftTop());
|
||||
Vec2Type top_right = Transform(rect.GetRightTop());
|
||||
Vec2Type bottom_left = Transform(rect.GetLeftBottom());
|
||||
Vec2Type bottom_right = Transform(rect.GetRightBottom());
|
||||
|
||||
ValueType left = (std::min)((std::min)(top_left.x, top_right.x), (std::min)(bottom_left.x, bottom_right.x));
|
||||
ValueType right = (std::max)((std::max)(top_left.x, top_right.x), (std::max)(bottom_left.x, bottom_right.x));
|
||||
ValueType top = (std::min)((std::min)(top_left.y, top_right.y), (std::min)(bottom_left.y, bottom_right.y));
|
||||
ValueType bottom = (std::max)((std::max)(top_left.y, top_right.y), (std::max)(bottom_left.y, bottom_right.y));
|
||||
|
||||
return RectType{left, top, right, bottom};
|
||||
}
|
||||
|
||||
inline void Translate(const glm::vec2 &v)
|
||||
{
|
||||
_31 += _11 * v.x + _21 * v.y;
|
||||
_32 += _12 * v.x + _22 * v.y;
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Translation(const glm::vec2 &v)
|
||||
{
|
||||
return Matrix3x2T(1.f, 0.f, 0.f, 1.f, v.x, v.y);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Scaling(const Vec2Type &v)
|
||||
{
|
||||
return Matrix3x2T(v.x, 0.f, 0.f, v.y, 0.f, 0.f);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Scaling(const Vec2Type &v, const Vec2Type ¢er)
|
||||
{
|
||||
return Matrix3x2T(v.x, 0.f, 0.f, v.y, center.x - v.x * center.x, center.y - v.y * center.y);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Rotation(ValueType angle)
|
||||
{
|
||||
ValueType s = math::Sin(angle);
|
||||
ValueType c = math::Cos(angle);
|
||||
return Matrix3x2T(c, s, -s, c, 0.f, 0.f);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Rotation(ValueType angle, const Vec2Type ¢er)
|
||||
{
|
||||
ValueType s = math::Sin(angle);
|
||||
ValueType c = math::Cos(angle);
|
||||
return Matrix3x2T(c, s, -s, c, center.x * (1 - c) + center.y * s, center.y * (1 - c) - center.x * s);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T SRT(const Vec2Type &trans, const Vec2Type &scale, ValueType angle)
|
||||
{
|
||||
ValueType s = math::Sin(angle);
|
||||
ValueType c = math::Cos(angle);
|
||||
return Matrix3x2T(c * scale.x, s * scale.x, -s * scale.y, c * scale.y, trans.x, trans.y);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Skewing(const Vec2Type &angle)
|
||||
{
|
||||
ValueType tx = math::Tan(angle.x);
|
||||
ValueType ty = math::Tan(angle.y);
|
||||
return Matrix3x2T(1.f, -ty, -tx, 1.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
static inline Matrix3x2T Skewing(const Vec2Type &angle, const Vec2Type ¢er)
|
||||
{
|
||||
ValueType tx = math::Tan(angle.x);
|
||||
ValueType ty = math::Tan(angle.y);
|
||||
return Matrix3x2T(1.f, -ty, -tx, 1.f, center.y * tx, center.x * ty);
|
||||
}
|
||||
};
|
||||
|
||||
// Use template expression to optimize matrix multiply
|
||||
template <typename _Ty, typename _Lty, typename _Rty>
|
||||
struct MatrixMultiply
|
||||
{
|
||||
const _Lty &lhs;
|
||||
const _Rty &rhs;
|
||||
|
||||
MatrixMultiply(const _Lty &lhs, const _Rty &rhs)
|
||||
: lhs(lhs), rhs(rhs)
|
||||
{
|
||||
}
|
||||
|
||||
inline _Ty operator[](uint32_t index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return lhs[0] * rhs[0] + lhs[1] * rhs[2];
|
||||
case 1:
|
||||
return lhs[0] * rhs[1] + lhs[1] * rhs[3];
|
||||
case 2:
|
||||
return lhs[2] * rhs[0] + lhs[3] * rhs[2];
|
||||
case 3:
|
||||
return lhs[2] * rhs[1] + lhs[3] * rhs[3];
|
||||
case 4:
|
||||
return lhs[4] * rhs[0] + lhs[5] * rhs[2] + rhs[4];
|
||||
case 5:
|
||||
return lhs[4] * rhs[1] + lhs[5] * rhs[3] + rhs[5];
|
||||
default:
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
inline MatrixMultiply<_Ty, Matrix3x2T<_Ty>, Matrix3x2T<_Ty>> operator*(const Matrix3x2T<_Ty> &lhs,
|
||||
const Matrix3x2T<_Ty> &rhs)
|
||||
{
|
||||
return MatrixMultiply<_Ty, Matrix3x2T<_Ty>, Matrix3x2T<_Ty>>(lhs, rhs);
|
||||
}
|
||||
|
||||
template <typename _Ty, typename _Lty, typename _Rty>
|
||||
inline MatrixMultiply<_Ty, MatrixMultiply<_Ty, _Lty, _Rty>, Matrix3x2T<_Ty>>
|
||||
operator*(const MatrixMultiply<_Ty, _Lty, _Rty> &lhs, const Matrix3x2T<_Ty> &rhs)
|
||||
{
|
||||
return MatrixMultiply<_Ty, MatrixMultiply<_Ty, _Lty, _Rty>, Matrix3x2T<_Ty>>(lhs, rhs);
|
||||
}
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
114
source/math/Random.h
Normal file
114
source/math/Random.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <random>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
//
|
||||
// 随机数
|
||||
//
|
||||
// 获取指定范围内的一个随机数, 如:
|
||||
// int n = math::Random(1, 5); // 获取 1~5 内的随机整数, 包含 1 和 5
|
||||
// 产生的随机数类型取决于参数的类型, 如获取随机浮点数:
|
||||
// float d = math::Random(1.2f, 1.5f);
|
||||
//
|
||||
|
||||
int Random(int min, int max);
|
||||
|
||||
unsigned int Random(unsigned int min, unsigned int max);
|
||||
|
||||
long Random(long min, long max);
|
||||
|
||||
unsigned long Random(unsigned long min, unsigned long max);
|
||||
|
||||
char Random(char min, char max);
|
||||
|
||||
float Random(float min, float max);
|
||||
|
||||
double Random(double min, double max);
|
||||
|
||||
//
|
||||
// Details of math::Rand
|
||||
//
|
||||
|
||||
namespace __rand_detail
|
||||
{
|
||||
inline std::default_random_engine &GetRandomEngine()
|
||||
{
|
||||
static std::random_device device;
|
||||
static std::default_random_engine engine(device());
|
||||
return engine;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T RandomInt(T min, T max)
|
||||
{
|
||||
std::uniform_int_distribution<T> dist(min, max);
|
||||
return dist(GetRandomEngine());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T RandomReal(T min, T max)
|
||||
{
|
||||
std::uniform_real_distribution<T> dist(min, max);
|
||||
return dist(GetRandomEngine());
|
||||
}
|
||||
} // namespace __rand_detail
|
||||
|
||||
inline int Random(int min, int max)
|
||||
{
|
||||
return __rand_detail::RandomInt(min, max);
|
||||
}
|
||||
|
||||
inline unsigned int Random(unsigned int min, unsigned int max)
|
||||
{
|
||||
return __rand_detail::RandomInt(min, max);
|
||||
}
|
||||
|
||||
inline long Random(long min, long max)
|
||||
{
|
||||
return __rand_detail::RandomInt(min, max);
|
||||
}
|
||||
|
||||
inline unsigned long Random(unsigned long min, unsigned long max)
|
||||
{
|
||||
return __rand_detail::RandomInt(min, max);
|
||||
}
|
||||
|
||||
inline char Random(char min, char max)
|
||||
{
|
||||
return static_cast<char>(__rand_detail::RandomInt(static_cast<int>(min), static_cast<int>(max)));
|
||||
}
|
||||
|
||||
inline float Random(float min, float max)
|
||||
{
|
||||
return __rand_detail::RandomReal(min, max);
|
||||
}
|
||||
|
||||
inline double Random(double min, double max)
|
||||
{
|
||||
return __rand_detail::RandomReal(min, max);
|
||||
}
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
154
source/math/Rect.hpp
Normal file
154
source/math/Rect.hpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <math/Vec2.hpp>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
template <typename _Ty>
|
||||
struct RectT
|
||||
{
|
||||
public:
|
||||
using ValueType = _Ty;
|
||||
|
||||
Vec2T<ValueType> left_top;
|
||||
Vec2T<ValueType> right_bottom;
|
||||
|
||||
public:
|
||||
RectT() {}
|
||||
|
||||
RectT(ValueType left, ValueType top, ValueType right, ValueType bottom)
|
||||
: left_top(left, top), right_bottom(right, bottom)
|
||||
{
|
||||
}
|
||||
|
||||
RectT(const Vec2T<ValueType> &left_top, const Vec2T<ValueType> &right_bottom)
|
||||
: left_top(left_top), right_bottom(right_bottom)
|
||||
{
|
||||
}
|
||||
|
||||
RectT(const RectT &other)
|
||||
: left_top(other.left_top), right_bottom(other.right_bottom)
|
||||
{
|
||||
}
|
||||
|
||||
RectT &operator=(const RectT &other)
|
||||
{
|
||||
left_top = other.left_top;
|
||||
right_bottom = other.right_bottom;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator==(const RectT &rect) const
|
||||
{
|
||||
return (left_top == rect.left_top) && (right_bottom == rect.right_bottom);
|
||||
}
|
||||
|
||||
inline void Set(ValueType left, ValueType top, ValueType right, ValueType bottom)
|
||||
{
|
||||
left_top = Vec2T<ValueType>{left, top};
|
||||
right_bottom = Vec2T<ValueType>{right, bottom};
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetCenter() const
|
||||
{
|
||||
return Vec2T<ValueType>{(left_top.x + right_bottom.x) / 2, (left_top.y + right_bottom.y) / 2};
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetLeftTop() const
|
||||
{
|
||||
return left_top;
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetRightBottom() const
|
||||
{
|
||||
return right_bottom;
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetRightTop() const
|
||||
{
|
||||
return Vec2T<ValueType>{right_bottom.x, left_top.y};
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetLeftBottom() const
|
||||
{
|
||||
return Vec2T<ValueType>{left_top.x, right_bottom.y};
|
||||
}
|
||||
|
||||
inline ValueType GetLeft() const
|
||||
{
|
||||
return left_top.x;
|
||||
}
|
||||
|
||||
inline ValueType GetTop() const
|
||||
{
|
||||
return left_top.y;
|
||||
}
|
||||
|
||||
inline ValueType GetRight() const
|
||||
{
|
||||
return right_bottom.x;
|
||||
}
|
||||
|
||||
inline ValueType GetBottom() const
|
||||
{
|
||||
return right_bottom.y;
|
||||
}
|
||||
|
||||
inline ValueType GetWidth() const
|
||||
{
|
||||
return right_bottom.x - left_top.x;
|
||||
}
|
||||
|
||||
inline ValueType GetHeight() const
|
||||
{
|
||||
return right_bottom.y - left_top.y;
|
||||
}
|
||||
|
||||
inline Vec2T<ValueType> GetSize() const
|
||||
{
|
||||
return Vec2T<ValueType>{GetWidth(), GetHeight()};
|
||||
}
|
||||
|
||||
inline bool IsEmpty() const
|
||||
{
|
||||
return left_top.IsOrigin() && right_bottom.IsOrigin();
|
||||
}
|
||||
|
||||
inline bool ContainsPoint(const Vec2T<ValueType> &point) const
|
||||
{
|
||||
return point.x >= left_top.x && point.x <= right_bottom.x && point.y >= left_top.y && point.y <= right_bottom.y;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectT &rect) const
|
||||
{
|
||||
return !(right_bottom.x < rect.left_top.x || rect.right_bottom.x < left_top.x || right_bottom.y < rect.left_top.y || rect.right_bottom.y < left_top.y);
|
||||
}
|
||||
|
||||
static inline RectT Infinite()
|
||||
{
|
||||
return RectT{-math::FLOAT_MAX, -math::FLOAT_MAX, math::FLOAT_MAX, math::FLOAT_MAX};
|
||||
}
|
||||
};
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
165
source/math/Scalar.h
Normal file
165
source/math/Scalar.h
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <math/Constants.h>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
inline int Abs(int val)
|
||||
{
|
||||
return ::abs(val);
|
||||
}
|
||||
inline float Abs(float val)
|
||||
{
|
||||
return ::fabsf(val);
|
||||
}
|
||||
inline double Abs(double val)
|
||||
{
|
||||
return ::fabs(val);
|
||||
}
|
||||
|
||||
inline float Sqrt(float val)
|
||||
{
|
||||
return ::sqrtf(val);
|
||||
}
|
||||
inline double Sqrt(double val)
|
||||
{
|
||||
return ::sqrt(val);
|
||||
}
|
||||
|
||||
inline float Pow(float core, float exponent)
|
||||
{
|
||||
return ::powf(core, exponent);
|
||||
}
|
||||
inline double Pow(double core, double exponent)
|
||||
{
|
||||
return ::pow(core, exponent);
|
||||
}
|
||||
|
||||
inline int Sign(int val)
|
||||
{
|
||||
return val < 0 ? -1 : 1;
|
||||
}
|
||||
inline float Sign(float val)
|
||||
{
|
||||
return val < 0 ? -1.f : 1.f;
|
||||
}
|
||||
inline double Sign(double val)
|
||||
{
|
||||
return val < 0 ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
inline float Degree2Radian(float angle)
|
||||
{
|
||||
return angle * math::PI_F / 180.f;
|
||||
}
|
||||
inline double Degree2Radian(double angle)
|
||||
{
|
||||
return angle * math::PI_D / 180.0;
|
||||
}
|
||||
|
||||
inline float Radian2Degree(float radian)
|
||||
{
|
||||
return radian * 180.f / math::PI_F;
|
||||
}
|
||||
inline double Radian2Degree(double radian)
|
||||
{
|
||||
return radian * 180.0 / math::PI_D;
|
||||
}
|
||||
|
||||
inline float Sin(float val)
|
||||
{
|
||||
return ::sinf(Degree2Radian(val));
|
||||
}
|
||||
inline double Sin(double val)
|
||||
{
|
||||
return ::sin(Degree2Radian(val));
|
||||
}
|
||||
|
||||
inline float Cos(float val)
|
||||
{
|
||||
return ::cosf(Degree2Radian(val));
|
||||
}
|
||||
inline double Cos(double val)
|
||||
{
|
||||
return ::cos(Degree2Radian(val));
|
||||
}
|
||||
|
||||
inline float Tan(float val)
|
||||
{
|
||||
return ::tanf(Degree2Radian(val));
|
||||
}
|
||||
inline double Tan(double val)
|
||||
{
|
||||
return ::tan(Degree2Radian(val));
|
||||
}
|
||||
|
||||
inline float Asin(float val)
|
||||
{
|
||||
return Radian2Degree(::asinf(val));
|
||||
}
|
||||
inline double Asin(double val)
|
||||
{
|
||||
return Radian2Degree(::asin(val));
|
||||
}
|
||||
|
||||
inline float Acos(float val)
|
||||
{
|
||||
return Radian2Degree(::acosf(val));
|
||||
}
|
||||
inline double Acos(double val)
|
||||
{
|
||||
return Radian2Degree(::acos(val));
|
||||
}
|
||||
|
||||
inline float Atan(float val)
|
||||
{
|
||||
return Radian2Degree(::atanf(val));
|
||||
}
|
||||
inline double Atan(double val)
|
||||
{
|
||||
return Radian2Degree(::atan(val));
|
||||
}
|
||||
|
||||
inline float Ceil(float val)
|
||||
{
|
||||
return ::ceil(val);
|
||||
}
|
||||
inline double Ceil(double val)
|
||||
{
|
||||
return ::ceil(val);
|
||||
}
|
||||
|
||||
inline float Floor(float val)
|
||||
{
|
||||
return ::floor(val);
|
||||
}
|
||||
inline double Floor(double val)
|
||||
{
|
||||
return ::floor(val);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
86
source/math/Transform.hpp
Normal file
86
source/math/Transform.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <math/Vec2.hpp>
|
||||
#include <math/Matrix.hpp>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief ¶þά·ÅÉä±ä»»
|
||||
*/
|
||||
template <typename _Ty>
|
||||
class TransformT
|
||||
{
|
||||
public:
|
||||
using ValueType = _Ty;
|
||||
|
||||
float rotation; ///< Ðýת
|
||||
Vec2T<ValueType> position; ///< ×ø±ê
|
||||
Vec2T<ValueType> scale; ///< Ëõ·Å
|
||||
Vec2T<ValueType> skew; ///< ´íÇнǶÈ
|
||||
|
||||
public:
|
||||
TransformT();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief ½«¶þά·ÅÉä±ä»»×ª»»Îª¾ØÕó
|
||||
Matrix3x2T<ValueType> ToMatrix() const;
|
||||
|
||||
bool IsFast() const;
|
||||
|
||||
bool operator==(const TransformT &rhs) const;
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
inline TransformT<_Ty>::TransformT()
|
||||
: position(), rotation(0.f), scale(1.f, 1.f), skew(0.f, 0.f)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
Matrix3x2T<_Ty> TransformT<_Ty>::ToMatrix() const
|
||||
{
|
||||
if (!skew.IsOrigin())
|
||||
{
|
||||
return Matrix3x2T<_Ty>::Skewing(skew) * Matrix3x2T<_Ty>::SRT(position, scale, rotation);
|
||||
}
|
||||
return Matrix3x2T<_Ty>::SRT(position, scale, rotation);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
inline bool TransformT<_Ty>::IsFast() const
|
||||
{
|
||||
return skew.x == 0.f && skew.y == 0.f && scale.x == 1.f && scale.y == 1.f && rotation == 0.f;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
bool TransformT<_Ty>::operator==(const TransformT &rhs) const
|
||||
{
|
||||
return position == rhs.position && rotation == rhs.rotation && scale == rhs.scale && skew == rhs.skew;
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
136
source/math/Vec2.hpp
Normal file
136
source/math/Vec2.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2016-2018 Ember - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <math/Scalar.h>
|
||||
|
||||
namespace ember
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
template <typename _Ty>
|
||||
struct Vec2T
|
||||
{
|
||||
using ValueType = _Ty;
|
||||
|
||||
ValueType x;
|
||||
ValueType y;
|
||||
|
||||
Vec2T()
|
||||
: x(ValueType(0)), y(ValueType(0))
|
||||
{
|
||||
}
|
||||
|
||||
Vec2T(ValueType x, ValueType y)
|
||||
: x(x), y(y)
|
||||
{
|
||||
}
|
||||
|
||||
Vec2T(const Vec2T &other)
|
||||
: x(other.x), y(other.y)
|
||||
{
|
||||
}
|
||||
|
||||
inline ValueType Length() const
|
||||
{
|
||||
return static_cast<ValueType>(math::Sqrt(static_cast<float>(x * x + y * y)));
|
||||
}
|
||||
|
||||
inline bool IsOrigin() const
|
||||
{
|
||||
return (x == 0) && (y == 0);
|
||||
}
|
||||
|
||||
inline void Set(ValueType x, ValueType y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
inline const Vec2T operator+(const Vec2T &other) const
|
||||
{
|
||||
return Vec2T(x + other.x, y + other.y);
|
||||
}
|
||||
|
||||
inline const Vec2T operator-(const Vec2T &other) const
|
||||
{
|
||||
return Vec2T(x - other.x, y - other.y);
|
||||
}
|
||||
|
||||
inline const Vec2T operator*(ValueType val) const
|
||||
{
|
||||
return Vec2T(x * val, y * val);
|
||||
}
|
||||
|
||||
inline const Vec2T operator*(const Vec2T &other) const
|
||||
{
|
||||
return Vec2T(x * other.x, y * other.y);
|
||||
}
|
||||
|
||||
inline const Vec2T operator/(ValueType val) const
|
||||
{
|
||||
return Vec2T(x / val, y / val);
|
||||
}
|
||||
|
||||
inline const Vec2T operator-() const
|
||||
{
|
||||
return Vec2T(-x, -y);
|
||||
}
|
||||
|
||||
inline Vec2T &operator+=(const Vec2T &other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Vec2T &operator-=(const Vec2T &other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Vec2T &operator*=(ValueType val)
|
||||
{
|
||||
x *= val;
|
||||
y *= val;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Vec2T &operator/=(ValueType val)
|
||||
{
|
||||
x /= val;
|
||||
y /= val;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline bool operator==(const Vec2T &other) const
|
||||
{
|
||||
return (x == other.x) && (y == other.y);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Vec2T &other) const
|
||||
{
|
||||
return (x != other.x) || (y != other.y);
|
||||
}
|
||||
};
|
||||
} // namespace math
|
||||
} // namespace ember
|
||||
@@ -102,6 +102,7 @@ void SquirrelEx::Init()
|
||||
|
||||
dbg = sqdbg_attach_debugger(v);
|
||||
sqdbg_listen_socket(dbg, 2222);
|
||||
fclose(file1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ private:
|
||||
//工作目录
|
||||
std::string WorkPath;
|
||||
//热重载
|
||||
bool HotReload = true;
|
||||
bool HotReload = false;
|
||||
std::map<std::string, int> _scriptmap;
|
||||
|
||||
};
|
||||
|
||||
@@ -4318,6 +4318,11 @@ void SQDebugServer::OnRequest_SetBreakpoints(const json_table_t &arguments, int
|
||||
return;
|
||||
}
|
||||
|
||||
//必须切割否则无法取消断点
|
||||
#ifdef SQDBG_SOURCENAME_HAS_PATH
|
||||
StripFileName(&srcname.ptr, &srcname.len);
|
||||
#endif
|
||||
|
||||
RemoveBreakpoints(srcname);
|
||||
|
||||
DAP_START_RESPONSE(seq, "setBreakpoints");
|
||||
@@ -18191,7 +18196,6 @@ void SQDebugServer::RemoveBreakpoints(const string_t &source)
|
||||
for (unsigned int i = 0; i < m_nFunctionBreakpointsIdx;)
|
||||
{
|
||||
breakpoint_t &bp = m_Breakpoints[i];
|
||||
|
||||
if (bp.src.IsEqualTo(src))
|
||||
{
|
||||
FreeBreakpoint(bp);
|
||||
@@ -19968,6 +19972,7 @@ void SQDebugServer::DebugHook(HSQUIRRELVM vm, int type,
|
||||
sqstring_t src;
|
||||
src.Assign(sourcename, srclen);
|
||||
|
||||
|
||||
breakpoint_t *bp = GetBreakpoint(line, src);
|
||||
|
||||
if (bp)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "GameMap.h"
|
||||
#include "Asset/AssetManager.h"
|
||||
#include "Asset/Asset_SoundPack.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "EngineFrame/Component/Animation.h"
|
||||
#include "Actor/Map/GameMapCamera.h"
|
||||
#include "Global/Global_Game.h"
|
||||
#include "Actor/Object/CharacterObject.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
GameMap::GameMap()
|
||||
{
|
||||
@@ -19,15 +20,25 @@ GameMap::GameMap()
|
||||
_LayerMap["max"] = new GameMapLayer();
|
||||
|
||||
// 设置图层渲染顺序
|
||||
_LayerMap["contact"]->SetRenderZOrder(10000);
|
||||
_LayerMap["distantback"]->SetRenderZOrder(50000);
|
||||
_LayerMap["middleback"]->SetRenderZOrder(100000);
|
||||
_LayerMap["bottom"]->SetRenderZOrder(150000);
|
||||
_LayerMap["closeback"]->SetRenderZOrder(200000);
|
||||
_LayerMap["normal"]->SetRenderZOrder(250000);
|
||||
_LayerMap["close"]->SetRenderZOrder(300000);
|
||||
_LayerMap["cover"]->SetRenderZOrder(350000);
|
||||
_LayerMap["max"]->SetRenderZOrder(400000);
|
||||
_LayerMap["contact"]->SetZOrder(10000);
|
||||
_LayerMap["distantback"]->SetZOrder(50000);
|
||||
_LayerMap["middleback"]->SetZOrder(100000);
|
||||
_LayerMap["bottom"]->SetZOrder(150000);
|
||||
_LayerMap["closeback"]->SetZOrder(200000);
|
||||
_LayerMap["normal"]->SetZOrder(250000);
|
||||
_LayerMap["close"]->SetZOrder(300000);
|
||||
_LayerMap["cover"]->SetZOrder(350000);
|
||||
_LayerMap["max"]->SetZOrder(400000);
|
||||
|
||||
AddChild(_LayerMap["contact"]);
|
||||
AddChild(_LayerMap["distantback"]);
|
||||
AddChild(_LayerMap["middleback"]);
|
||||
AddChild(_LayerMap["bottom"]);
|
||||
AddChild(_LayerMap["closeback"]);
|
||||
AddChild(_LayerMap["normal"]);
|
||||
AddChild(_LayerMap["close"]);
|
||||
AddChild(_LayerMap["cover"]);
|
||||
AddChild(_LayerMap["max"]);
|
||||
}
|
||||
|
||||
GameMap::~GameMap()
|
||||
@@ -107,7 +118,7 @@ void GameMap::InitConfiguration(std::string mapName)
|
||||
{
|
||||
BackGroundAni ani;
|
||||
Data.Get();
|
||||
ani.filename = _MapDir + Tool_toLowerCase(Data.Get());
|
||||
ani.filename = Tool_RegRealPath(_MapDir + Tool_toLowerCase(Data.Get()));
|
||||
Data.Get();
|
||||
ani.layer = Data.Get();
|
||||
Data.Get();
|
||||
@@ -119,13 +130,13 @@ void GameMap::InitConfiguration(std::string mapName)
|
||||
}
|
||||
else if (Segment == "[sound]")
|
||||
{
|
||||
std::vector<std::string> soundArry;
|
||||
std::map<std::string, bool> soundArry;
|
||||
while (true)
|
||||
{
|
||||
std::string sounddata = Data.Get();
|
||||
if (sounddata == "[/sound]")
|
||||
break;
|
||||
soundArry.push_back(sounddata);
|
||||
soundArry[sounddata] = true;
|
||||
}
|
||||
_MapInfo["sound"] = soundArry;
|
||||
}
|
||||
@@ -174,13 +185,17 @@ void GameMap::InitConfiguration(std::string mapName)
|
||||
std::string areadata = Data.Get();
|
||||
if (areadata == "[/town movable area]")
|
||||
break;
|
||||
town_movable_area.push_back(std::stoi(areadata));
|
||||
town_movable_area.push_back(std::stoi(areadata));
|
||||
town_movable_area.push_back(std::stoi(areadata));
|
||||
town_movable_area.push_back(std::stoi(areadata));
|
||||
int x1 = std::stoi(areadata);
|
||||
int y1 = std::stoi(Data.Get());
|
||||
int x2 = std::stoi(Data.Get());
|
||||
int y2 = std::stoi(Data.Get());
|
||||
town_movable_area.push_back(x1);
|
||||
town_movable_area.push_back(y1);
|
||||
town_movable_area.push_back(x2);
|
||||
town_movable_area.push_back(y2);
|
||||
MapMoveArea T;
|
||||
T.town = std::stoi(areadata);
|
||||
T.area = std::stoi(areadata);
|
||||
T.town = std::stoi(Data.Get());
|
||||
T.area = std::stoi(Data.Get());
|
||||
town_movable_area_info.push_back(T);
|
||||
}
|
||||
_MapInfo["town_movable_area"] = town_movable_area;
|
||||
@@ -212,39 +227,20 @@ void GameMap::InitTile()
|
||||
int NormalTileCount = 0;
|
||||
// 普通地板高度
|
||||
int NormalTileHeight = 560;
|
||||
std::vector<std::string> tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
|
||||
if (tileArr.size() > 0)
|
||||
{
|
||||
NormalTileCount = tileArr.size();
|
||||
_MapLength = NormalTileCount * 224;
|
||||
for (int i = 0; i < NormalTileCount; i++)
|
||||
{
|
||||
std::string path = tileArr[i];
|
||||
RefPtr<Tile> tile = new Tile(path);
|
||||
tile->SetPos(VecFPos{i * 224, -200 - std::get<int>(_MapInfo["background_pos"])});
|
||||
_LayerMap["bottom"]->AddComponent(tile);
|
||||
}
|
||||
_MapHeight = 560;
|
||||
}
|
||||
std::vector<std::string> tileArr;
|
||||
std::vector<std::string> extileArr;
|
||||
|
||||
tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
|
||||
|
||||
// 拓展地板不一定有
|
||||
if (_MapInfo.count("extended_tile"))
|
||||
{
|
||||
std::vector<std::string> extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
|
||||
if (extileArr.size() > 0)
|
||||
{
|
||||
int ExTileCount = extileArr.size();
|
||||
int Buffer = (ExTileCount / NormalTileCount);
|
||||
_MapHeight += (Buffer < 1 ? 1 : Buffer) * 40;
|
||||
for (int i = 0; i < ExTileCount; i++)
|
||||
{
|
||||
std::string path = extileArr[i];
|
||||
RefPtr<Tile> tile = new Tile(path);
|
||||
int xbuf = i % NormalTileCount * 224;
|
||||
int ybuf = -200 - std::get<int>(_MapInfo["background_pos"]) + NormalTileHeight + 120 * (i / NormalTileCount);
|
||||
tile->SetPos(VecFPos{xbuf, ybuf});
|
||||
_LayerMap["bottom"]->AddComponent(tile);
|
||||
}
|
||||
}
|
||||
extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
|
||||
}
|
||||
|
||||
_Tile = new Tile(this, tileArr, extileArr);
|
||||
_Tile->SetPosition(0, -200 - std::get<int>(_MapInfo["background_pos"]));
|
||||
_LayerMap["bottom"]->AddChild(_Tile);
|
||||
}
|
||||
|
||||
void GameMap::InitBackgroundAnimation()
|
||||
@@ -269,8 +265,8 @@ void GameMap::InitBackgroundAnimation()
|
||||
}
|
||||
for (int i = 0; i < (int)AniList.size(); i++)
|
||||
{
|
||||
AniList[i]->SetPos(VecFPos{i * width, -120});
|
||||
AniList[i]->SetRenderZOrder(-1000000);
|
||||
AniList[i]->SetPosition(i * width, -120);
|
||||
AniList[i]->SetZOrder(-1000000);
|
||||
std::string layer = ani.layer;
|
||||
layer = layer.substr(1, layer.length() - 2);
|
||||
if (_LayerMap.count(layer))
|
||||
@@ -294,8 +290,8 @@ void GameMap::InitMapAnimation()
|
||||
{
|
||||
std::string path = ani.filename;
|
||||
RefPtr<Animation> AniObj = new Animation(path);
|
||||
AniObj->SetPos(VecFPos{ani.XPos, ani.YPos - ani.ZPos});
|
||||
AniObj->SetRenderZOrder(ani.YPos);
|
||||
AniObj->SetPosition(ani.XPos, ani.YPos - ani.ZPos);
|
||||
AniObj->SetZOrder(ani.YPos);
|
||||
std::string layer = ani.layer;
|
||||
layer = layer.substr(1, layer.length() - 2);
|
||||
if (_LayerMap.count(layer))
|
||||
@@ -318,12 +314,30 @@ void GameMap::InitVirtualMovableArea()
|
||||
float w = Info[i + 2];
|
||||
float h = Info[i + 3];
|
||||
if (_DebugMode)
|
||||
_LayerMap["max"]->AddDebugFeasibleAreaInfo(VecFPos(x, y), VecSize(w, h));
|
||||
_LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h), 0);
|
||||
_MovableArea.push_back(SDL_FRect{x, y, w, h});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameMap::InitMoveArea()
|
||||
{
|
||||
std::vector<int> Info = std::get<std::vector<int>>(_MapInfo["town_movable_area"]);
|
||||
if (Info.size() > 0)
|
||||
{
|
||||
for (int i = 0; i < Info.size(); i += 4)
|
||||
{
|
||||
float x = Info[i];
|
||||
float y = Info[i + 1];
|
||||
float w = Info[i + 2];
|
||||
float h = Info[i + 3];
|
||||
if (_DebugMode)
|
||||
_LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h), 1);
|
||||
_MoveArea.push_back(SDL_FRect{x, y, w, h});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameMap::LoadMap(std::string mapName)
|
||||
{
|
||||
// 读取脚本配置
|
||||
@@ -336,49 +350,64 @@ void GameMap::LoadMap(std::string mapName)
|
||||
InitMapAnimation();
|
||||
// 初始化可行区域
|
||||
InitVirtualMovableArea();
|
||||
// 初始化传送区域
|
||||
InitMoveArea();
|
||||
}
|
||||
|
||||
void GameMap::Enter(Scene *scene)
|
||||
void GameMap::Enter()
|
||||
{
|
||||
_Scene = scene;
|
||||
scene->AddChild(_LayerMap["contact"]);
|
||||
scene->AddChild(_LayerMap["distantback"]);
|
||||
scene->AddChild(_LayerMap["middleback"]);
|
||||
scene->AddChild(_LayerMap["bottom"]);
|
||||
scene->AddChild(_LayerMap["closeback"]);
|
||||
scene->AddChild(_LayerMap["normal"]);
|
||||
scene->AddChild(_LayerMap["close"]);
|
||||
scene->AddChild(_LayerMap["cover"]);
|
||||
scene->AddChild(_LayerMap["max"]);
|
||||
auto &Audio = Asset_SoundPack::GetInstance();
|
||||
// 获取背景音乐
|
||||
auto bgmIt = _MapInfo.find("sound");
|
||||
if (bgmIt != _MapInfo.end())
|
||||
{
|
||||
std::map<std::string, bool> bgmlist = std::get<std::map<std::string, bool>>(_MapInfo["sound"]);
|
||||
// 获取正在播放的背景音乐
|
||||
std::map<std::string, int> curmap = Audio.GetBackgroudMusicVector();
|
||||
for (auto &it : curmap)
|
||||
{
|
||||
std::string name = it.first;
|
||||
// 判断正在播放的背景音乐是否与当前地图背景音乐相同
|
||||
if (!bgmlist.count(name))
|
||||
{
|
||||
Audio.StopAudio(name);
|
||||
}
|
||||
}
|
||||
// 播放当前地图背景音乐
|
||||
for (auto &it : bgmlist)
|
||||
{
|
||||
std::string name = it.first;
|
||||
if (!curmap.count(name))
|
||||
Audio.PlayAudio(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameMap::HandleEvents(SDL_Event *e)
|
||||
void GameMap::OnUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
Actor::OnUpdate(deltaTime);
|
||||
|
||||
void GameMap::Update(float deltaTime)
|
||||
{
|
||||
if (_Scene->GetCamera() == nullptr)
|
||||
RefPtr<GameCamera> Cam = Global_Game::GetInstance().GetCamera();
|
||||
if (Cam == nullptr)
|
||||
return;
|
||||
GameMapCamera *Cam = (GameMapCamera *)(_Scene->GetCamera().Get());
|
||||
int targetX = Cam->_currentPosition.x;
|
||||
int targetY = Cam->_currentPosition.y;
|
||||
float targetX = Cam->_currentPosition.x;
|
||||
float targetY = Cam->_currentPosition.y;
|
||||
// 屏幕中心
|
||||
int width_Separate = Game::GetInstance().Screen_W / 2;
|
||||
int height_Separate = Game::GetInstance().Screen_H / 2;
|
||||
float width_Separate = 1280.0f / 1.2f / 2.0f;
|
||||
float height_Separate = 600.0f / 2.0f;
|
||||
|
||||
// 获取摄像机可行区域限制
|
||||
auto limitIt = _MapInfo.find("limit_map_camera_move");
|
||||
if (limitIt != _MapInfo.end())
|
||||
{
|
||||
std::vector<int> limit = std::get<std::vector<int>>(_MapInfo["limit_map_camera_move"]);
|
||||
int X_Limit_Min = limit[0];
|
||||
int X_Limit_Max = limit[1];
|
||||
int Y_Limit_Min = limit[2];
|
||||
int Y_Limit_Max = limit[3];
|
||||
float X_Limit_Min = limit[0];
|
||||
float X_Limit_Max = limit[1];
|
||||
float Y_Limit_Min = limit[2];
|
||||
float Y_Limit_Max = limit[3];
|
||||
// 应用地图边界限制
|
||||
targetX = std::clamp(targetX, width_Separate, _MapLength - width_Separate);
|
||||
targetY = std::clamp(targetY, height_Separate, _MapHeight - height_Separate);
|
||||
targetX = std::clamp(targetX, width_Separate, (float)_MapLength - width_Separate);
|
||||
targetY = std::clamp(targetY, height_Separate, (float)_MapHeight - height_Separate);
|
||||
// 应用自定义摄像机移动限制
|
||||
if (X_Limit_Min != -1)
|
||||
targetX = std::max(targetX, X_Limit_Min);
|
||||
@@ -393,15 +422,17 @@ void GameMap::Update(float deltaTime)
|
||||
// 更新图层位置
|
||||
for (auto &Layer : _LayerMap)
|
||||
{
|
||||
int posX = -targetX + width_Separate;
|
||||
int posY = -targetY + height_Separate + MapOffsetY;
|
||||
float posX = -targetX + width_Separate;
|
||||
float posY = -targetY + height_Separate + MapOffsetY;
|
||||
if (Layer.first == "distantback")
|
||||
{
|
||||
posX *= BackgroundMoveSpeed;
|
||||
posX /= 100;
|
||||
posX /= 100.0f;
|
||||
}
|
||||
Layer.second->SetPos(VecFPos(posX, posY));
|
||||
Layer.second->SetPosition(posX, posY);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GameMap::AddObject(RefPtr<BaseObject> object)
|
||||
@@ -412,14 +443,14 @@ void GameMap::AddObject(RefPtr<BaseObject> object)
|
||||
if (object->m_objecttype == ObjectType::CHARACTER)
|
||||
{
|
||||
CharacterObject *chr = (CharacterObject *)(object.Get());
|
||||
if( chr->_Shadow != nullptr)_LayerMap["bottom"]->AddComponent(chr->_Shadow);
|
||||
Global_Game::GetInstance().GetCamera()->SetFromActor(chr);
|
||||
}
|
||||
}
|
||||
|
||||
VecPos3 GameMap::CheckIsItMovable(VecPos3 CurPos, VecPos3 PosOffset)
|
||||
VecFPos3 GameMap::CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset)
|
||||
{
|
||||
// 初始化结果为原坐标(默认不移动)
|
||||
VecPos3 result = CurPos;
|
||||
VecFPos3 result = CurPos;
|
||||
|
||||
// 如果没有可移动区域限制,直接全量位移
|
||||
if (_MovableArea.empty())
|
||||
@@ -472,4 +503,42 @@ VecPos3 GameMap::CheckIsItMovable(VecPos3 CurPos, VecPos3 PosOffset)
|
||||
result.z += PosOffset.z;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
GameMap::MapMoveArea GameMap::CheckIsItMoveArea(VecFPos3 ChrPos)
|
||||
{
|
||||
|
||||
MapMoveArea invalidArea;
|
||||
invalidArea.town = -2;
|
||||
invalidArea.area = -2;
|
||||
|
||||
if (_MoveArea.size() && _MapInfo.count("town_movable_area_info"))
|
||||
{
|
||||
SDL_FPoint CurPos = {ChrPos.x, ChrPos.y};
|
||||
|
||||
for (int i = 0; i < _MoveArea.size(); i++)
|
||||
{
|
||||
if (SDL_PointInFRect(&CurPos, &_MoveArea[i]))
|
||||
{
|
||||
const std::vector<MapMoveArea> &tma = std::get<std::vector<MapMoveArea>>(_MapInfo["town_movable_area_info"]);
|
||||
return tma[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有矩形都不命中,返回无效值
|
||||
return invalidArea;
|
||||
}
|
||||
|
||||
std::vector<GameMap::MapMoveArea> &GameMap::GetMoveAreaInfo()
|
||||
{
|
||||
return std::get<std::vector<GameMap::MapMoveArea>>(_MapInfo["town_movable_area_info"]);
|
||||
}
|
||||
|
||||
SDL_Rect GameMap::GetMovablePositionArea(int Index)
|
||||
{
|
||||
auto Vertex = std::get<std::vector<int>>(_MapInfo["town_movable_area"]);
|
||||
int FindIndex = Index * 4;
|
||||
SDL_Rect Buf = {Vertex[FindIndex], Vertex[FindIndex + 1], Vertex[FindIndex + 2], Vertex[FindIndex + 3]};
|
||||
return Buf;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
class BaseObject;
|
||||
class GameMapCamera;
|
||||
class GameMap
|
||||
class GameMap : public Actor
|
||||
{
|
||||
public:
|
||||
struct BackGroundAni
|
||||
{
|
||||
std::string filename;
|
||||
@@ -37,13 +38,14 @@ class GameMap
|
||||
|
||||
struct MapMoveArea
|
||||
{
|
||||
int town;
|
||||
int area;
|
||||
int town = 0;
|
||||
int area = 0;
|
||||
};
|
||||
|
||||
using MapInfoBody = std::variant<
|
||||
int,
|
||||
std::string,
|
||||
std::map<std::string, bool>,
|
||||
std::vector<BackGroundAni>,
|
||||
std::vector<MapAni>,
|
||||
std::vector<MapNpc>,
|
||||
@@ -58,20 +60,22 @@ public:
|
||||
std::string _MapPath;
|
||||
// 地图文件夹
|
||||
std::string _MapDir;
|
||||
// 地板画布
|
||||
RefPtr<Tile> _Tile = nullptr;
|
||||
// 地图宽度
|
||||
int _MapLength = 0;
|
||||
// 地图高度
|
||||
int _MapHeight = 0;
|
||||
// 可行区域
|
||||
std::vector<SDL_FRect> _MovableArea;
|
||||
// 传送区域
|
||||
std::vector<SDL_FRect> _MoveArea;
|
||||
// 调试模式
|
||||
bool _DebugMode = false;
|
||||
|
||||
public:
|
||||
// 图层Map 图层类型 显示对象
|
||||
std::unordered_map<std::string, RefPtr<GameMapLayer>> _LayerMap;
|
||||
// 所属场景
|
||||
Scene *_Scene = nullptr;
|
||||
|
||||
// 背景层移动速率
|
||||
int BackgroundMoveSpeed = 103;
|
||||
@@ -81,18 +85,36 @@ public:
|
||||
GameMap(/* args */);
|
||||
~GameMap();
|
||||
|
||||
/**加载地图 (地图路径) */
|
||||
void LoadMap(std::string mapName);
|
||||
/**进入地图执行的操作 */
|
||||
void Enter();
|
||||
/**重载OnUpdate函数 */
|
||||
void OnUpdate(float deltaTime) override;
|
||||
|
||||
public:
|
||||
/**读取脚本配置 */
|
||||
void InitConfiguration(std::string mapName);
|
||||
/**初始化地板 */
|
||||
void InitTile();
|
||||
/**初始化背景动画 */
|
||||
void InitBackgroundAnimation();
|
||||
/**初始化地图动画 */
|
||||
void InitMapAnimation();
|
||||
/**初始化移动区域 */
|
||||
void InitVirtualMovableArea();
|
||||
void Enter(Scene *scene);
|
||||
void HandleEvents(SDL_Event *e);
|
||||
void Update(float deltaTime);
|
||||
/**初始化传送区域 */
|
||||
void InitMoveArea();
|
||||
/**添加对象 */
|
||||
void AddObject(RefPtr<BaseObject> object);
|
||||
|
||||
public:
|
||||
// 检查是否可移动
|
||||
VecPos3 CheckIsItMovable(VecPos3 CurPos, VecPos3 PosOffset);
|
||||
VecFPos3 CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset);
|
||||
// 检查是否进入传送区域
|
||||
MapMoveArea CheckIsItMoveArea(VecFPos3 CurPos);
|
||||
/**获取移动区域信息 */
|
||||
std::vector<GameMap::MapMoveArea> &GetMoveAreaInfo();
|
||||
/**获取移动区域坐标信息 */
|
||||
SDL_Rect GetMovablePositionArea(int Index);
|
||||
};
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
class GameMap;
|
||||
class BaseObject;
|
||||
class GameMapCamera : public Actor
|
||||
{
|
||||
private:
|
||||
// 跟随对象
|
||||
BaseObject *_FromActor = nullptr;
|
||||
|
||||
public:
|
||||
// 摄像机记录的跟随对象坐标
|
||||
VecPos3 FromActorPos = {0, 0, 0};
|
||||
|
||||
// 缩放比率
|
||||
float CameraRate = 1.0;
|
||||
|
||||
// 添加平滑移动相关的成员变量
|
||||
bool _isSmoothMoving = false;
|
||||
VecPos _currentPosition; // 当前摄像机位置
|
||||
VecPos _velocity; // 当前移动速度(用于平滑移动)
|
||||
float _smoothTime = 0.1f; // 平滑时间(秒),可调整
|
||||
int _maxSpeed = 2000; // 最大移动速度,防止过快
|
||||
|
||||
public:
|
||||
GameMapCamera();
|
||||
~GameMapCamera();
|
||||
|
||||
void SetFromActor(BaseObject *actor);
|
||||
void Update(float deltaTime);
|
||||
|
||||
void SetPos(int x, int y, int z);
|
||||
void AddPos(int x, int y, int z);
|
||||
|
||||
//同步坐标相关
|
||||
void SyncPos(float deltaTime);
|
||||
void SyncPosByFromParent(float deltaTime);
|
||||
|
||||
// 平滑阻尼函数(类似Unity的Mathf.SmoothDamp)
|
||||
VecPos SmoothDamp(const VecPos ¤t, const VecPos &target, VecPos ¤tVelocity, float smoothTime, int maxSpeed, float deltaTime);
|
||||
};
|
||||
@@ -1,41 +1,47 @@
|
||||
#include "GameMapLayer.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
GameMapLayer::GameMapLayer()
|
||||
{
|
||||
}
|
||||
|
||||
GameMapLayer::~GameMapLayer()
|
||||
{
|
||||
}
|
||||
|
||||
void GameMapLayer::Render()
|
||||
{
|
||||
Actor::Render();
|
||||
RenderManager *renderer = Game::GetInstance().GetRenderer();
|
||||
|
||||
// 自身坐标
|
||||
float Xpos = GetIterationPos().x + GetPos().x;
|
||||
float Ypos = GetIterationPos().y + GetPos().y;
|
||||
glm::vec2 Pos = this->ConvertToWorld({0, 0});
|
||||
// 可行区域
|
||||
for (auto &info : this->FeasibleAreaInfoList)
|
||||
{
|
||||
SDL_Rect buf;
|
||||
buf.x = info.x + Xpos;
|
||||
buf.y = info.y + Ypos;
|
||||
buf.x = info.x + Pos.x;
|
||||
buf.y = info.y + Pos.y;
|
||||
buf.w = info.w;
|
||||
buf.h = info.h;
|
||||
//TODO: 渲染可行区域
|
||||
glm::vec4 red = {1.0f, 0.0f, 0.0f, 0.4f}; // RGBA:红色,不透明基础色
|
||||
Game::GetInstance().GetRenderer()->DrawRect(&buf, red);
|
||||
}
|
||||
// 移动区域
|
||||
for (auto &info : this->MoveAreaInfoList)
|
||||
{
|
||||
SDL_Rect buf;
|
||||
buf.x = info.x + Pos.x;
|
||||
buf.y = info.y + Pos.y;
|
||||
buf.w = info.w;
|
||||
buf.h = info.h;
|
||||
glm::vec4 red = {0.0f, 0.0f, 1.0f, 0.4f}; // RGBA:红色,不透明基础色
|
||||
Game::GetInstance().GetRenderer()->DrawRect(&buf, red);
|
||||
}
|
||||
}
|
||||
|
||||
void GameMapLayer::AddDebugFeasibleAreaInfo(VecFPos pos, VecSize size)
|
||||
void GameMapLayer::AddDebugFeasibleAreaInfo(Vec2 pos, VecSize size, int Type)
|
||||
{
|
||||
SDL_Rect info;
|
||||
info.x = pos.x;
|
||||
info.y = pos.y;
|
||||
info.w = size.width;
|
||||
info.h = size.height;
|
||||
this->FeasibleAreaInfoList.push_back(info);
|
||||
|
||||
if (Type == 0)
|
||||
this->FeasibleAreaInfoList.push_back(info);
|
||||
else if (Type == 1)
|
||||
this->MoveAreaInfoList.push_back(info);
|
||||
}
|
||||
|
||||
void GameMapLayer::AddObject(RefPtr<Actor> obj)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
|
||||
class BaseObject;
|
||||
@@ -9,15 +9,14 @@ class GameMapLayer : public Actor
|
||||
private:
|
||||
// 可行区域信息
|
||||
std::vector<SDL_Rect> FeasibleAreaInfoList;
|
||||
// 移动区域信息
|
||||
std::vector<SDL_Rect> MoveAreaInfoList;
|
||||
|
||||
public:
|
||||
GameMapLayer(/* args */);
|
||||
~GameMapLayer();
|
||||
|
||||
// 重载Render以实现绘制可行区域
|
||||
// 重载OnRender以实现绘制可行区域
|
||||
void Render() override;
|
||||
// 添加调试可行区域信息
|
||||
void AddDebugFeasibleAreaInfo(VecFPos pos, VecSize size);
|
||||
void AddDebugFeasibleAreaInfo(Vec2 pos, VecSize size, int Type);
|
||||
|
||||
public:
|
||||
void AddObject(RefPtr<Actor> obj); // 添加对象
|
||||
|
||||
67
source_game/Actor/Map/GameTown.cpp
Normal file
67
source_game/Actor/Map/GameTown.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "GameTown.h"
|
||||
#include "Global/Global_Game.h"
|
||||
GameTown::GameTown()
|
||||
{
|
||||
}
|
||||
|
||||
GameTown::~GameTown()
|
||||
{
|
||||
}
|
||||
|
||||
void GameTown::Init(int Index)
|
||||
{
|
||||
GlobalTownScript::TownConfig *Config = Global_Game::GetInstance().GetTownInfo(Index);
|
||||
if (Config)
|
||||
{
|
||||
this->Name_ = Config->TownName;
|
||||
this->Entering_Title = Config->Entering_Title;
|
||||
this->Entering_Cutscene = Config->Entering_Cutscene;
|
||||
this->NeedLevel = Config->NeedLevel;
|
||||
this->NeedQuestID = Config->NeedQuestID;
|
||||
// 构造全部地图
|
||||
for (auto &it : Config->AreaLst)
|
||||
{
|
||||
MapInfo info;
|
||||
info.Map = new GameMap();
|
||||
info.Map->LoadMap(it.second.MapPath);
|
||||
info.Type = it.second.MapType;
|
||||
MapList_.push_back(info);
|
||||
if (info.Type == "gate")
|
||||
{
|
||||
SariaRoomID = it.first;
|
||||
SariaRoomPos = {it.second.GenerateXPos, it.second.GenerateYPos, 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameTown::AddCharacter(RefPtr<CharacterObject> Chr, int Index)
|
||||
{
|
||||
int TargetMapIndex = Index;
|
||||
|
||||
if (Index == -2)
|
||||
{
|
||||
TargetMapIndex = SariaRoomID;
|
||||
}
|
||||
// 如果有当前调用中的地图
|
||||
if (CurMapIndex != -1)
|
||||
{
|
||||
RemoveChild(MapList_[CurMapIndex].Map);
|
||||
}
|
||||
// 如果角色已有父对象
|
||||
if (Chr->GetParent())
|
||||
{
|
||||
Chr->RemoveFromParent();
|
||||
}
|
||||
// 调用赛利亚房间地图
|
||||
AddChild(MapList_[TargetMapIndex].Map);
|
||||
if(Index == -2)Chr->SetPosition(SariaRoomPos);
|
||||
MapList_[TargetMapIndex].Map->Enter();
|
||||
MapList_[TargetMapIndex].Map->AddObject(Chr);
|
||||
CurMapIndex = TargetMapIndex;
|
||||
}
|
||||
|
||||
void GameTown::OnUpdate(float DeltaTime)
|
||||
{
|
||||
Actor::OnUpdate(DeltaTime);
|
||||
}
|
||||
54
source_game/Actor/Map/GameTown.h
Normal file
54
source_game/Actor/Map/GameTown.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "Actor/Map/GameMap.h"
|
||||
#include "Actor/Object/CharacterObject.h"
|
||||
class GameTown : public Actor
|
||||
{
|
||||
public:
|
||||
struct MapInfo
|
||||
{
|
||||
/**地图对象 */
|
||||
RefPtr<GameMap> Map;
|
||||
/**地图类型 */
|
||||
std::string Type;
|
||||
};
|
||||
|
||||
private:
|
||||
/**城镇名称 */
|
||||
std::string Name_;
|
||||
/**进入城镇时的标题Img */
|
||||
std::string Entering_Title;
|
||||
/**进入城镇时的过场Img */
|
||||
std::string Entering_Cutscene;
|
||||
/**需要的任务进入条件 */
|
||||
int NeedQuestID;
|
||||
/**需要的等级进入条件 */
|
||||
int NeedLevel;
|
||||
/**赛利亚房间编号 */
|
||||
int SariaRoomID = -1;
|
||||
/**赛丽亚房间生成坐标 */
|
||||
VecFPos3 SariaRoomPos;
|
||||
|
||||
/**地图集合 */
|
||||
std::vector<MapInfo> MapList_;
|
||||
|
||||
/**当前所在地图 */
|
||||
int CurMapIndex = -1;
|
||||
|
||||
public:
|
||||
GameTown(/* args */);
|
||||
~GameTown();
|
||||
|
||||
/**通过城镇ID初始化 */
|
||||
void Init(int Index);
|
||||
|
||||
public:
|
||||
/**获取当前所在区域 */
|
||||
int GetCurAreaIndex() { return CurMapIndex; };
|
||||
/**获取区域对象 */
|
||||
RefPtr<GameMap> GetArea(int Index) { return MapList_[Index].Map; };
|
||||
/**添加角色 (无区域编号 上线进入城镇 或 使用传送时进入城镇 有区域编号 移动进入的)*/
|
||||
void AddCharacter(RefPtr<CharacterObject> Chr, int AreaIndex = -2);
|
||||
|
||||
void OnUpdate(float DeltaTime) override;
|
||||
};
|
||||
100
source_game/Actor/Map/GameWorld.cpp
Normal file
100
source_game/Actor/Map/GameWorld.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "GameWorld.h"
|
||||
#include "Global/Global_Game.h"
|
||||
#include "EngineCore/Game.h"
|
||||
|
||||
#include "EngineFrame/Component/AnimationMap.h"
|
||||
#include "EngineFrame/Component/Animation.h"
|
||||
GameWorld::GameWorld()
|
||||
{
|
||||
}
|
||||
|
||||
GameWorld::~GameWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void GameWorld::Enter()
|
||||
{
|
||||
SetScale(1.2f, 1.2f);
|
||||
Init();
|
||||
}
|
||||
|
||||
void GameWorld::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
void GameWorld::Init()
|
||||
{
|
||||
// RefPtr<Animation> ani = new Animation("common/tuguan/maineff.ani");
|
||||
// RefPtr<Sprite> sp = new Sprite("sprite/live/else/chn/2022/0510_danjin_jar/22_danjineft/0510_danjin_body.img",0);
|
||||
// RefPtr<AnimationMap> am = new AnimationMap();
|
||||
// // am->AddAnimation(ani);
|
||||
// am->AddChild(sp);
|
||||
// am->CompleteConstruction();
|
||||
// AddChild(am);
|
||||
|
||||
// 构造所有城镇
|
||||
auto &GlobalGame = Global_Game::GetInstance();
|
||||
for (auto obj : GlobalGame.GetTownMap())
|
||||
{
|
||||
RefPtr<GameTown> town = new GameTown;
|
||||
town->Init(obj.first);
|
||||
m_TownMap[obj.first] = town;
|
||||
}
|
||||
|
||||
// 构造角色
|
||||
RefPtr<CharacterObject> obj = new CharacterObject();
|
||||
obj->Construction(0);
|
||||
AddCharacter(obj, 1);
|
||||
}
|
||||
|
||||
void GameWorld::AddCharacter(RefPtr<CharacterObject> Chr, int TownId)
|
||||
{
|
||||
// 游戏世界类赋值我的角色
|
||||
m_MyCharacter = Chr;
|
||||
// 记录当前城镇
|
||||
m_CurTown = TownId;
|
||||
// 进入城镇
|
||||
m_TownMap[TownId]->AddCharacter(Chr);
|
||||
// 渲染并更新城镇
|
||||
AddChild(m_TownMap[TownId]);
|
||||
}
|
||||
|
||||
void GameWorld::MoveCharacter(RefPtr<CharacterObject> Chr, int TownId, int Area)
|
||||
{
|
||||
// 当前所在城镇
|
||||
int curTown = m_CurTown;
|
||||
// 当前所在区域
|
||||
int curArea = m_TownMap[curTown]->GetCurAreaIndex();
|
||||
// 获取目标城镇移动信息表
|
||||
auto MapObj = m_TownMap[TownId]->GetArea(Area);
|
||||
auto MoveInfo = MapObj->GetMoveAreaInfo();
|
||||
// 传送后的目标区域
|
||||
SDL_Rect destArea = {0, 0, 0, 0};
|
||||
// 遍历移动信息表
|
||||
for (size_t i = 0; i < MoveInfo.size(); ++i)
|
||||
{
|
||||
auto info = MoveInfo[i];
|
||||
|
||||
if (info.town == curTown && info.area == curArea)
|
||||
{
|
||||
destArea = MapObj->GetMovablePositionArea(i);
|
||||
}
|
||||
}
|
||||
// 读取出应该存在的坐标以后设置角色的坐标
|
||||
float Xpos = destArea.x + destArea.w / 2;
|
||||
float Ypos = destArea.y + destArea.h / 2;
|
||||
Chr->SetPosition({Xpos, Ypos, 0});
|
||||
// 将角色添加到目标城镇
|
||||
m_TownMap[TownId]->AddCharacter(Chr, Area);
|
||||
// 停止渲染更新旧城镇
|
||||
RemoveChild(m_TownMap[curTown]);
|
||||
// 记录当前城镇
|
||||
m_CurTown = TownId;
|
||||
// 渲染并更新城镇
|
||||
AddChild(m_TownMap[TownId]);
|
||||
}
|
||||
|
||||
GameWorld *GameWorld::GetWorld()
|
||||
{
|
||||
return (GameWorld *)Game::GetInstance().GetScene().Get();
|
||||
}
|
||||
31
source_game/Actor/Map/GameWorld.h
Normal file
31
source_game/Actor/Map/GameWorld.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Scene/Scene.h"
|
||||
#include "Actor/Map/GameTown.h"
|
||||
class GameWorld : public Scene
|
||||
{
|
||||
private:
|
||||
/**城镇Map */
|
||||
std::map<int, RefPtr<GameTown>> m_TownMap;
|
||||
/**我的角色 */
|
||||
RefPtr<CharacterObject> m_MyCharacter;
|
||||
|
||||
/**当前城镇 */
|
||||
int m_CurTown;
|
||||
|
||||
public:
|
||||
GameWorld();
|
||||
~GameWorld();
|
||||
|
||||
void Enter() override;
|
||||
void Exit() override;
|
||||
|
||||
/**初始化 */
|
||||
void Init() override;
|
||||
/**加入角色 */
|
||||
void AddCharacter(RefPtr<CharacterObject> Chr, int TownId);
|
||||
/**移动角色 */
|
||||
void MoveCharacter(RefPtr<CharacterObject> Chr, int TownId,int Area);
|
||||
|
||||
public:
|
||||
static GameWorld *GetWorld();
|
||||
};
|
||||
@@ -1,33 +1,113 @@
|
||||
#include "Tile.h"
|
||||
#include "Tool/Tool_String.h"
|
||||
#include "EngineCore/Game.h"
|
||||
Tile::Tile()
|
||||
{
|
||||
}
|
||||
#include "Actor/Map/GameMap.h"
|
||||
#include "Global/Global_Game.h"
|
||||
|
||||
Tile::Tile(std::string Path) : Sprite()
|
||||
Tile::Tile(GameMap *parentMap, std::vector<std::string> normal, std::vector<std::string> ex)
|
||||
{
|
||||
InitInfo(Path);
|
||||
if (std::get<std::string>(m_data["path"]) == "")
|
||||
m_data["path"] = "sprite/character/common/circlecooltime.img";
|
||||
m_parentMap = parentMap;
|
||||
|
||||
m_texture = new Texture();
|
||||
m_texture->Init(std::get<std::string>(m_data["path"]), std::get<int>(m_data["idx"]));
|
||||
Sprite::Init();
|
||||
this->imgPath = Path;
|
||||
for (size_t i = 0; i < normal.size(); i++)
|
||||
{
|
||||
InitTile(normal[i], i);
|
||||
}
|
||||
for (size_t i = 0; i < ex.size(); i++)
|
||||
{
|
||||
InitExTile(ex[i], i);
|
||||
}
|
||||
|
||||
// 有可能没写地板
|
||||
if (m_BasicTileWidth == 0)
|
||||
m_BasicTileWidth = 224 * normal.size();
|
||||
|
||||
// 通过父对象获取地图大小
|
||||
m_parentMap->_MapLength = m_BasicTileWidth;
|
||||
m_parentMap->_MapHeight = m_BasicTileHeight + m_ExTileHeight;
|
||||
|
||||
Canvas::Init({(int)m_BasicTileWidth, (int)m_BasicTileHeight + (int)m_ExTileHeight + (int)m_tileY});
|
||||
DrawTile();
|
||||
}
|
||||
|
||||
Tile::~Tile()
|
||||
{
|
||||
}
|
||||
|
||||
void Tile::SetPos(VecFPos pos)
|
||||
void Tile::InitTile(std::string Path, int Index)
|
||||
{
|
||||
pos.y += std::get<int>(m_data["pos"]);
|
||||
Sprite::SetPos(pos);
|
||||
// 读取文件
|
||||
TileInfo data;
|
||||
InitInfo(Path, data);
|
||||
// 读取信息
|
||||
float ImgOffset = std::get<int>(data["pos"]);
|
||||
if (ImgOffset > m_tileY)
|
||||
m_tileY = ImgOffset;
|
||||
std::string path = std::get<std::string>(data["path"]);
|
||||
int index = std::get<int>(data["idx"]);
|
||||
// 如果是个空地板 给他默认赋值
|
||||
if (path == "")
|
||||
path = "sprite/character/common/circlecooltime.img";
|
||||
|
||||
// 构造纹理标识符
|
||||
ImgKey key = {path, index};
|
||||
// 判断是否存在标识符对应的纹理,如果不存在则创建
|
||||
if (m_imgMap.find(key) == m_imgMap.end())
|
||||
{
|
||||
RefPtr<Sprite> tex = new Sprite(path, index);
|
||||
m_imgMap[key] = tex;
|
||||
}
|
||||
// 横向地板数量增加
|
||||
m_Tile_X_Count++;
|
||||
// 基础地板宽度增加
|
||||
m_BasicTileWidth += m_imgMap[key]->GetTexture()->getFrameSize().width;
|
||||
// 取基础地板最高的高度
|
||||
if (m_imgMap[key]->GetTexture()->getFrameSize().height > m_BasicTileHeight)
|
||||
m_BasicTileHeight = m_imgMap[key]->GetTexture()->getFrameSize().height;
|
||||
|
||||
DrawInfo info;
|
||||
info.sprite_ = key;
|
||||
info.pos = {Index * 224, ImgOffset};
|
||||
m_drawQueue.push_back(info);
|
||||
}
|
||||
|
||||
void Tile::InitInfo(std::string Path)
|
||||
void Tile::InitExTile(std::string Path, int Index)
|
||||
{
|
||||
// 读取文件
|
||||
TileInfo data;
|
||||
InitInfo(Path, data);
|
||||
// 读取信息
|
||||
float ImgOffset = std::get<int>(data["pos"]);
|
||||
if (ImgOffset > m_tileY)
|
||||
m_tileY = ImgOffset;
|
||||
std::string path = std::get<std::string>(data["path"]);
|
||||
int index = std::get<int>(data["idx"]);
|
||||
// 如果是个空地板 给他默认赋值
|
||||
if (path == "")
|
||||
path = "sprite/character/common/circlecooltime.img";
|
||||
|
||||
// 构造纹理标识符
|
||||
ImgKey key = {path, index};
|
||||
// 判断是否存在标识符对应的纹理,如果不存在则创建
|
||||
if (m_imgMap.find(key) == m_imgMap.end())
|
||||
{
|
||||
RefPtr<Sprite> tex = new Sprite(path, index);
|
||||
m_imgMap[key] = tex;
|
||||
}
|
||||
|
||||
// 如果进了这个函数默认有1格
|
||||
if (m_ExTileHeight == 0)
|
||||
m_ExTileHeight = 120;
|
||||
// Ex地板高度120一格
|
||||
if (((Index / m_Tile_X_Count) * 120) > m_ExTileHeight)
|
||||
m_ExTileHeight = ((Index / m_Tile_X_Count) * 120);
|
||||
|
||||
DrawInfo info;
|
||||
info.sprite_ = key;
|
||||
info.pos = {Index * 224, m_tileY + m_BasicTileHeight + ((Index / m_Tile_X_Count) * 120)};
|
||||
m_drawQueue.push_back(info);
|
||||
}
|
||||
|
||||
void Tile::InitInfo(std::string Path, TileInfo &m_data)
|
||||
{
|
||||
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(Path);
|
||||
m_data["pos"] = 0;
|
||||
@@ -46,3 +126,14 @@ void Tile::InitInfo(std::string Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tile::DrawTile()
|
||||
{
|
||||
BeginDraw();
|
||||
for (auto &info : m_drawQueue)
|
||||
{
|
||||
m_imgMap[info.sprite_]->SetPosition(info.pos);
|
||||
DrawActor(m_imgMap[info.sprite_]);
|
||||
}
|
||||
EndDraw();
|
||||
}
|
||||
|
||||
@@ -1,22 +1,62 @@
|
||||
#pragma once
|
||||
#include "Asset/AssetManager.h"
|
||||
#include "EngineFrame/Component/Canvas.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
class Tile : public Sprite
|
||||
class GameMap;
|
||||
class Tile : public Canvas
|
||||
{
|
||||
|
||||
using TileInfoBody = std::variant<
|
||||
int,
|
||||
std::string>;
|
||||
public:
|
||||
struct ImgKey
|
||||
{
|
||||
std::string img;
|
||||
int index;
|
||||
|
||||
bool operator<(const ImgKey &other) const
|
||||
{
|
||||
if (img != other.img)
|
||||
{
|
||||
return img < other.img; // 字符串按字典序比较
|
||||
}
|
||||
return index < other.index; // 字符串相同则比较index
|
||||
}
|
||||
};
|
||||
struct DrawInfo
|
||||
{
|
||||
ImgKey sprite_;
|
||||
glm::vec2 pos;
|
||||
};
|
||||
|
||||
using TileInfoBody = std::variant<int, std::string>;
|
||||
using TileInfo = std::unordered_map<std::string, TileInfoBody>;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, TileInfoBody> m_data;
|
||||
/**父对象地图 */
|
||||
GameMap *m_parentMap;
|
||||
/**绘制精灵集 */
|
||||
std::map<ImgKey, RefPtr<Sprite>> m_imgMap;
|
||||
/**绘制队列 */
|
||||
std::vector<DrawInfo> m_drawQueue;
|
||||
|
||||
/**基础地板宽度 */
|
||||
float m_BasicTileWidth = 0;
|
||||
/**基础地板高度 */
|
||||
float m_BasicTileHeight = 0;
|
||||
/**Ex地板高度 */
|
||||
float m_ExTileHeight = 0;
|
||||
|
||||
/**横向地板数量 */
|
||||
int m_Tile_X_Count = 0;
|
||||
/**纵向最大偏移 */
|
||||
float m_tileY = 0;
|
||||
|
||||
public:
|
||||
Tile(/* args */);
|
||||
Tile(std::string Path);
|
||||
Tile(GameMap *parentMap, std::vector<std::string> normal, std::vector<std::string> ex);
|
||||
~Tile();
|
||||
|
||||
void SetPos(VecFPos pos) override;
|
||||
void InitTile(std::string Path, int Index);
|
||||
void InitExTile(std::string Path, int Index);
|
||||
void InitInfo(std::string Path, TileInfo &m_data);
|
||||
|
||||
void InitInfo(std::string Path);
|
||||
void DrawTile();
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "ActiveObject.h"
|
||||
void ActiveObject::SetPosition(VecPos3 pos)
|
||||
void ActiveObject::SetPosition(VecFPos3 pos)
|
||||
{
|
||||
BaseObject::SetPosition(pos);
|
||||
}
|
||||
@@ -19,51 +19,36 @@ VecSpeed3 ActiveObject::GetSpeed()
|
||||
return this->Speed;
|
||||
}
|
||||
|
||||
void ActiveObject::Update(float deltaTime)
|
||||
void ActiveObject::OnUpdate(float deltaTime)
|
||||
{
|
||||
int IntegerDelta = static_cast<int>(deltaTime * 1000);
|
||||
const int Gravity = 1020;
|
||||
|
||||
VecFPos3 MovePos;
|
||||
// X轴移动(含余数补偿)
|
||||
if (Speed.x != 0)
|
||||
{
|
||||
int totalX = Speed.x * IntegerDelta + Remainder.x; // 加上上次余数
|
||||
int moveX = totalX / 1000; // 整数部分为实际移动
|
||||
Remainder.x = totalX % 1000; // 保留余数(-999~999)
|
||||
MoveBy(moveX, 0, 0);
|
||||
MovePos.x = Speed.x * deltaTime;
|
||||
}
|
||||
|
||||
// Y轴移动(同上)
|
||||
if (Speed.y != 0)
|
||||
{
|
||||
int totalY = Speed.y * IntegerDelta + Remainder.y;
|
||||
int moveY = totalY / 1000;
|
||||
Remainder.y = totalY % 1000;
|
||||
MoveBy(0, moveY, 0);
|
||||
MovePos.y = Speed.y * deltaTime;
|
||||
}
|
||||
|
||||
// Z轴重力与移动(含余数补偿)
|
||||
if (Position.z > 0 || Speed.z > 0)
|
||||
{
|
||||
// 重力对速度的影响(先更新Speed.z,含余数)
|
||||
int speedZTotal = -Gravity * IntegerDelta + Remainder.z; // 注意负号(减速)
|
||||
Speed.z += speedZTotal / 1000; // 速度的整数部分
|
||||
Remainder.z = speedZTotal % 1000; // 速度的余数
|
||||
int speedZTotal = -1020 * deltaTime;
|
||||
|
||||
// 基于更新后的Speed.z计算移动量(同样含余数)
|
||||
int moveZTotal = Speed.z * IntegerDelta + _zRemainderMove; // 新增_zRemainderMove记录移动余数
|
||||
int moveZ = moveZTotal / 1000;
|
||||
_zRemainderMove = moveZTotal % 1000;
|
||||
MoveBy(0, 0, moveZ);
|
||||
MovePos.z = Speed.z * deltaTime;
|
||||
}
|
||||
else if (Position.z < 0)
|
||||
{
|
||||
Position.z = 0;
|
||||
Speed.z = 0;
|
||||
Remainder.z = 0; // 重置余数
|
||||
_zRemainderMove = 0;
|
||||
SetPosition(Position);
|
||||
}
|
||||
|
||||
BaseObject::Update(deltaTime);
|
||||
MoveBy(MovePos);
|
||||
}
|
||||
|
||||
@@ -7,18 +7,16 @@ class ActiveObject : public BaseObject
|
||||
public:
|
||||
// 三轴速度
|
||||
VecSpeed3 Speed;
|
||||
// 三轴移动余数
|
||||
VecPos3 Remainder;
|
||||
|
||||
int _zRemainderMove = 0;
|
||||
|
||||
public:
|
||||
void
|
||||
SetPosition(VecPos3 pos) override;
|
||||
void SetPosition(VecFPos3 pos) override;
|
||||
void SetYpos(int y) override;
|
||||
|
||||
void SetSpeed(VecSpeed3 speed);
|
||||
VecSpeed3 GetSpeed();
|
||||
|
||||
public:
|
||||
void Update(float deltaTime) override;
|
||||
void OnUpdate(float deltaTime) override;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "BaseObject.h"
|
||||
#include "Actor/Map/GameMap.h"
|
||||
#include "Actor/Map/GameMapCamera.h"
|
||||
|
||||
BaseObject::BaseObject()
|
||||
{
|
||||
Init(); // 调用了RenderBase的Init函数 对象才会被执行回调
|
||||
// 对象要使用中心锚点
|
||||
SetAnchor({0.5f, 0.5f});
|
||||
}
|
||||
|
||||
@@ -12,50 +11,49 @@ BaseObject::~BaseObject()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseObject::Update(float deltaTime)
|
||||
{
|
||||
if (_AffCamera != nullptr)
|
||||
{
|
||||
_AffCamera->SyncPos(deltaTime);
|
||||
}
|
||||
Actor::Update(deltaTime);
|
||||
}
|
||||
|
||||
void BaseObject::SetPosition(VecPos3 pos)
|
||||
void BaseObject::SetPosition(VecFPos3 pos)
|
||||
{
|
||||
if(pos == this->Position)
|
||||
return;
|
||||
if (pos.y != this->Position.y)
|
||||
{
|
||||
SetRenderZOrder(pos.y); // 设置渲染顺序
|
||||
SetZOrder(pos.y); // 设置渲染顺序
|
||||
}
|
||||
this->Position = pos;
|
||||
SetPos(VecFPos{this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition(this->Position.x, this->Position.y - this->Position.z);
|
||||
}
|
||||
|
||||
VecPos3 BaseObject::GetPosition()
|
||||
VecFPos3 BaseObject::GetPosition()
|
||||
{
|
||||
return this->Position;
|
||||
}
|
||||
|
||||
void BaseObject::SetXpos(int x)
|
||||
{
|
||||
if (x == this->Position.x)
|
||||
return;
|
||||
this->Position.x = x;
|
||||
SetPos({this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition(this->Position.x, this->Position.y - this->Position.z);
|
||||
}
|
||||
|
||||
void BaseObject::SetYpos(int y)
|
||||
{
|
||||
if (y == this->Position.y)
|
||||
return;
|
||||
if (y != this->Position.y)
|
||||
{
|
||||
SetRenderZOrder(y); // 设置渲染顺序
|
||||
SetZOrder(y); // 设置渲染顺序
|
||||
}
|
||||
this->Position.y = y;
|
||||
SetPos({this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition(this->Position.x, this->Position.y - this->Position.z);
|
||||
}
|
||||
|
||||
void BaseObject::SetZpos(int z)
|
||||
{
|
||||
if (z == this->Position.z)
|
||||
return;
|
||||
this->Position.z = z;
|
||||
SetPos({this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition(this->Position.x, this->Position.y - this->Position.z);
|
||||
}
|
||||
|
||||
int BaseObject::GetXpos()
|
||||
@@ -73,48 +71,52 @@ int BaseObject::GetZpos()
|
||||
return this->Position.z;
|
||||
}
|
||||
|
||||
void BaseObject::MoveBy(VecPos3 pos)
|
||||
void BaseObject::MoveBy(VecFPos3 pos)
|
||||
{
|
||||
// 只有moveby移动时判断所在地图中是否能够这样移动
|
||||
VecPos3 RealPos = this->_AffMap->CheckIsItMovable(GetPosition(), pos);
|
||||
VecFPos3 RealPos = this->_AffMap->CheckIsItMovable(GetPosition(), pos);
|
||||
if (RealPos == this->Position)
|
||||
return;
|
||||
if (RealPos.y != this->Position.y)
|
||||
{
|
||||
SetRenderZOrder(RealPos.y); // 设置渲染顺序
|
||||
SetZOrder(RealPos.y); // 设置渲染顺序
|
||||
}
|
||||
if (RealPos != this->Position){
|
||||
this->Position = RealPos;
|
||||
SetPos({this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition({this->Position.x, this->Position.y - this->Position.z});
|
||||
}
|
||||
}
|
||||
|
||||
void BaseObject::MoveBy(int x, int y, int z)
|
||||
{
|
||||
// 只有moveby移动时判断所在地图中是否能够这样移动
|
||||
VecPos3 RealPos = this->_AffMap->CheckIsItMovable(GetPosition(), VecPos3({x, y, z}));
|
||||
VecFPos3 RealPos = this->_AffMap->CheckIsItMovable(GetPosition(), VecFPos3({x, y, z}));
|
||||
if (RealPos == this->Position)
|
||||
return;
|
||||
if (RealPos.y != this->Position.y)
|
||||
{
|
||||
SetRenderZOrder(RealPos.y); // 设置渲染顺序
|
||||
SetZOrder(RealPos.y); // 设置渲染顺序
|
||||
}
|
||||
if (RealPos != this->Position)
|
||||
{
|
||||
this->Position = RealPos;
|
||||
SetPos({this->Position.x, this->Position.y - this->Position.z});
|
||||
Actor::SetPosition({this->Position.x, this->Position.y - this->Position.z});
|
||||
}
|
||||
}
|
||||
|
||||
void BaseObject::SetDirection(int dir)
|
||||
{
|
||||
this->Direction = dir;
|
||||
VecFPos sc = GetScale();
|
||||
glm::vec2 sc = GetScale();
|
||||
// 朝右
|
||||
if (dir == 0)
|
||||
{
|
||||
SetScale(VecFPos({SDL_fabsf(sc.x), sc.y}));
|
||||
SetScale(SDL_fabsf(sc.x), sc.y);
|
||||
}
|
||||
// 朝左
|
||||
else if (dir == 1)
|
||||
{
|
||||
SetScale(VecFPos({-SDL_fabsf(sc.x), sc.y}));
|
||||
SetScale(-SDL_fabsf(sc.x), sc.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,36 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "Asset/Common/ObjectVars.h"
|
||||
#include "Global/Global_Enum.h"
|
||||
class GameMap;
|
||||
class GameMapCamera;
|
||||
class BaseObject : public Actor
|
||||
{
|
||||
public:
|
||||
public:
|
||||
ObjectType m_objecttype; // 对象类型
|
||||
VecPos3 Position; // 位置
|
||||
VecFPos3 Position; // 位置
|
||||
int Direction = 0; // 方向
|
||||
GameMap *_AffMap = nullptr; // 所在地图
|
||||
GameMapCamera *_AffCamera = nullptr; // 跟随相机
|
||||
|
||||
public:
|
||||
BaseObject(/* args */);
|
||||
~BaseObject();
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
// 数据储存器
|
||||
ObjectVars _ObjectVars;
|
||||
|
||||
public:
|
||||
virtual void SetPosition(VecPos3 pos);
|
||||
virtual void SetPosition(VecFPos3 pos);
|
||||
virtual void SetXpos(int x);
|
||||
virtual void SetYpos(int y);
|
||||
virtual void SetZpos(int z);
|
||||
|
||||
VecPos3 GetPosition();
|
||||
VecFPos3 GetPosition();
|
||||
int GetXpos();
|
||||
int GetYpos();
|
||||
int GetZpos();
|
||||
|
||||
virtual void MoveBy(VecPos3 pos);
|
||||
virtual void MoveBy(VecFPos3 pos);
|
||||
virtual void MoveBy(int x, int y, int z);
|
||||
|
||||
virtual void SetDirection(int dir);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "CharacterObject.h"
|
||||
#include "Asset/Squirrel/SquirrelManager.h"
|
||||
#include "Actor/Map/GameMap.h"
|
||||
#include "Actor/Map/GameWorld.h"
|
||||
|
||||
CharacterObject::~CharacterObject()
|
||||
{
|
||||
@@ -12,9 +14,6 @@ void CharacterObject::Construction(int job)
|
||||
// 创建装备管理器
|
||||
_EquipmentManager = new Chr_Equipment();
|
||||
_EquipmentManager->Init(this);
|
||||
// // 创建阴影对象
|
||||
// _Shadow = new Chr_Shadow();
|
||||
// _Shadow->Init(this);
|
||||
// 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备)
|
||||
_AnimationManager = new Chr_Animation();
|
||||
_AnimationManager->Init(this);
|
||||
@@ -41,29 +40,45 @@ void CharacterObject::DisableController()
|
||||
|
||||
void CharacterObject::ControllerMsg(CONTROLLER_MSG_TYPE msgType, void *msgData)
|
||||
{
|
||||
// 摇杆移动(左)
|
||||
// 摇杆移动
|
||||
if (msgType == CONTROLLER_MSG_TYPE::CONTROLLER_MSG_TYPE_LEFT_JOYSTICK_MOVE)
|
||||
{
|
||||
VecFPos *pos = (VecFPos *)msgData;
|
||||
Vec2 *pos = (Vec2 *)msgData;
|
||||
std::vector<float> movedata = {pos->x, pos->y};
|
||||
this->GetObjectVars().SetArray("_move_data_", movedata);
|
||||
this->_StateMachine->ChangeState(BASE_STATE::MOVE);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterObject::Update(float deltaTime)
|
||||
void CharacterObject::SetPosition(VecFPos3 pos)
|
||||
{
|
||||
ActiveObject::Update(deltaTime);
|
||||
}
|
||||
|
||||
void CharacterObject::SetPos(VecFPos pos)
|
||||
{
|
||||
BaseObject::SetPos(pos);
|
||||
if(_Shadow)_Shadow->SetPos(this->GetPos());
|
||||
BaseObject::SetPosition(pos);
|
||||
}
|
||||
|
||||
void CharacterObject::SetDirection(int dir)
|
||||
{
|
||||
BaseObject::SetDirection(dir);
|
||||
if(_Shadow)_Shadow->SetDirection(this->GetDirection());
|
||||
}
|
||||
|
||||
void CharacterObject::OnUpdate(float deltaTime)
|
||||
{
|
||||
ActiveObject::OnUpdate(deltaTime);
|
||||
|
||||
// 判断是否要进行区域移动
|
||||
if (!IsTeleportArea)
|
||||
{
|
||||
GameMap::MapMoveArea Info = this->_AffMap->CheckIsItMoveArea(this->GetPosition());
|
||||
if (Info.town != -2 && Info.area != -2)
|
||||
{
|
||||
IsTeleportArea = true;
|
||||
// 调用世界类移动自己
|
||||
GameWorld::GetWorld()->MoveCharacter(this, Info.town, Info.area);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMap::MapMoveArea Info = this->_AffMap->CheckIsItMoveArea(this->GetPosition());
|
||||
if (Info.town == -2 && Info.area == -2)
|
||||
IsTeleportArea = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
#include "Actor/Object/ActiveObject.h"
|
||||
#include "Asset/Character/Chr_Animation.h"
|
||||
#include "Asset/Character/Chr_Equipment.h"
|
||||
#include "Asset/Character/Chr_Controller.h"
|
||||
#include "Asset/Character/Chr_StateMachine.h"
|
||||
#include "Asset/Character/Chr_Shadow.h"
|
||||
#include "Global/Global_Enum.h"
|
||||
class CharacterObject : public ActiveObject
|
||||
{
|
||||
@@ -18,12 +18,12 @@ public:
|
||||
// 角色状态机
|
||||
RefPtr<Chr_StateMachine> _StateMachine = nullptr;
|
||||
|
||||
// 角色阴影对象
|
||||
RefPtr<Chr_Shadow> _Shadow = nullptr;
|
||||
// 职业
|
||||
int Job = 0;
|
||||
// 转职职业 如果是-1则没有转职
|
||||
int GrowType = -1;
|
||||
/** 传送区域Flag */
|
||||
bool IsTeleportArea = false;
|
||||
|
||||
public:
|
||||
~CharacterObject();
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
// 控制器信息
|
||||
void ControllerMsg(CONTROLLER_MSG_TYPE msgType, void* msgData);
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void SetPos(VecFPos pos) override;
|
||||
void SetPosition(VecFPos3 pos) override;
|
||||
void SetDirection(int dir) override;
|
||||
|
||||
void OnUpdate(float deltaTime) override;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
|
||||
if (slotName == "skin_avatar")
|
||||
{
|
||||
// 如果穿戴了皮肤时装 读取variation
|
||||
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName);
|
||||
RefPtr<Equipment> Equip = ((CharacterObject *)GetParent())->_EquipmentManager->GetEquip(slotName);
|
||||
if (Equip)
|
||||
{
|
||||
Animation::ReplaceData Data(0, 0);
|
||||
@@ -34,7 +34,7 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
|
||||
RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data);
|
||||
Ani->SetVisible(false);
|
||||
|
||||
Ani->SetRenderZOrder(Variation.Layer);
|
||||
Ani->SetZOrder(Variation.Layer);
|
||||
this->AddChild(Ani);
|
||||
ActionAnis[actionName].push_back(Ani);
|
||||
|
||||
@@ -49,7 +49,7 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
|
||||
}
|
||||
else
|
||||
{
|
||||
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName);
|
||||
RefPtr<Equipment> Equip = ((CharacterObject *)GetParent())->_EquipmentManager->GetEquip(slotName);
|
||||
if (Equip)
|
||||
{
|
||||
// SDL_Log("CreateSkinmationBySlot %s", slotName.c_str());
|
||||
@@ -67,7 +67,7 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
|
||||
// 构造好Ani以后 统一设置为不可见 然后放入ActionAnis表
|
||||
RefPtr<Animation> Ani = new Animation(AniPath, FormatImgPath, Data);
|
||||
Ani->SetVisible(false);
|
||||
Ani->SetRenderZOrder(Variation.Layer);
|
||||
Ani->SetZOrder(Variation.Layer);
|
||||
this->AddChild(Ani);
|
||||
ActionAnis[actionName].push_back(Ani);
|
||||
}
|
||||
@@ -78,7 +78,6 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
|
||||
void Chr_Animation::Init(CharacterObject *parent)
|
||||
{
|
||||
// 调用RenderBase类的初始化 才能挂上标签
|
||||
RenderBase::Init();
|
||||
parent->AddChild(this);
|
||||
chr_parent = parent;
|
||||
GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job];
|
||||
@@ -116,5 +115,5 @@ void Chr_Animation::SetAction(std::string actionName)
|
||||
CurrentActionTag = actionName;
|
||||
|
||||
// 设置阴影的动作
|
||||
if(chr_parent->_Shadow)chr_parent->_Shadow->SetAction(actionName);
|
||||
// if(chr_parent->_Shadow)chr_parent->_Shadow->SetAction(actionName);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
class CharacterObject;
|
||||
class Chr_Animation : public RenderBase
|
||||
class Chr_Animation : public Actor
|
||||
{
|
||||
// 动作动画集合
|
||||
using ActionAniList = std::map<std::string, std::vector<RefPtr<Animation>>>;
|
||||
|
||||
@@ -28,7 +28,6 @@ float Chr_Controller::ConvertAxisValue(Sint16 rawValue)
|
||||
|
||||
void Chr_Controller::Init(CharacterObject *pCharacter)
|
||||
{
|
||||
addTag(Tag::HANDEL_EVENT);
|
||||
m_pCharacter = pCharacter;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/BaseNode.h"
|
||||
#include "EngineFrame/Base/Node.h"
|
||||
#include "Tool/Common.h"
|
||||
class CharacterObject;
|
||||
class Chr_Controller : public BaseNode
|
||||
class Chr_Controller : public Node
|
||||
{
|
||||
private:
|
||||
CharacterObject *m_pCharacter = nullptr;
|
||||
|
||||
public:
|
||||
VecFPos LeftStick = {0.f, 0.f};
|
||||
VecFPos RightStick = {0.f, 0.f};
|
||||
Vec2 LeftStick = {0.f, 0.f};
|
||||
Vec2 RightStick = {0.f, 0.f};
|
||||
|
||||
// 用于将SDL的轴值(-32768到32767)转换为-1到1之间的浮点数
|
||||
float ConvertAxisValue(Sint16 rawValue);
|
||||
@@ -19,6 +19,6 @@ public:
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
|
||||
// 获取摇杆位置的方法
|
||||
const VecFPos &GetLeftStick() const { return LeftStick; }
|
||||
const VecFPos &GetRightStick() const { return RightStick; }
|
||||
const Vec2 &GetLeftStick() const { return LeftStick; }
|
||||
const Vec2 &GetRightStick() const { return RightStick; }
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Asset/Common/Equipment.h"
|
||||
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
class CharacterObject;
|
||||
class Chr_Equipment : public Component
|
||||
class Chr_Equipment : public Actor
|
||||
{
|
||||
public:
|
||||
// 默认装备
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "Chr_Shadow.h"
|
||||
#include "Global/Global_Game.h"
|
||||
#include "Actor/Object/CharacterObject.h"
|
||||
#include "Asset/Character/Chr_Equipment.h"
|
||||
|
||||
void Chr_Shadow::Init(CharacterObject *parent)
|
||||
{
|
||||
// 调用RenderBase类的初始化 才能挂上标签
|
||||
RenderBase::Init();
|
||||
chr_parent = parent;
|
||||
SetRenderZOrder(1000000);
|
||||
SetPos(parent->GetPos());
|
||||
}
|
||||
|
||||
void Chr_Shadow::SetAction(std::string actionName)
|
||||
{
|
||||
// 先将原动作的Ani设置为不可见
|
||||
for (auto Ani : ActionAnis[CurrentActionTag])
|
||||
{
|
||||
Ani->Reset();
|
||||
Ani->SetVisible(false);
|
||||
}
|
||||
// 再将新动作的Ani设置为可见
|
||||
for (auto Ani : ActionAnis[actionName])
|
||||
{
|
||||
Ani->SetVisible(true);
|
||||
}
|
||||
CurrentActionTag = actionName;
|
||||
}
|
||||
|
||||
void Chr_Shadow::SetDirection(int dir)
|
||||
{
|
||||
VecFPos sc = GetScale();
|
||||
// 朝右
|
||||
if (dir == 0)
|
||||
{
|
||||
SetScale(VecFPos({SDL_fabsf(sc.x), sc.y}));
|
||||
}
|
||||
// 朝左
|
||||
else if (dir == 1)
|
||||
{
|
||||
SetScale(VecFPos({-SDL_fabsf(sc.x), sc.y}));
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Animation.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
class CharacterObject;
|
||||
class Chr_Shadow : public RenderBase
|
||||
{
|
||||
// 动作动画集合
|
||||
using ActionAniList = std::map<std::string, std::vector<RefPtr<Animation>>>;
|
||||
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
// 父对象
|
||||
CharacterObject *chr_parent;
|
||||
// 时装部位对应的动作动画集合
|
||||
ActionAniList ActionAnis;
|
||||
// 当前动作Tag
|
||||
std::string CurrentActionTag = "waiting";
|
||||
|
||||
// 初始化时
|
||||
void Init(CharacterObject *parent);
|
||||
// 设置动作
|
||||
void SetAction(std::string actionName);
|
||||
|
||||
// 设置方向
|
||||
void SetDirection(int dir);
|
||||
};
|
||||
@@ -5,7 +5,6 @@
|
||||
void Chr_StateMachine::Init(CharacterObject *parent)
|
||||
{
|
||||
chr_Parent = parent;
|
||||
addTag(Tag::UPDATE);
|
||||
parent->AddChild(this);
|
||||
}
|
||||
void Chr_StateMachine::ChangeState(int state)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Global/Global_Enum.h"
|
||||
|
||||
#include "EngineFrame/Base/Node.h"
|
||||
class CharacterObject;
|
||||
class Chr_StateMachine : public Component
|
||||
class Chr_StateMachine : public Node
|
||||
{
|
||||
private:
|
||||
// 父对象
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Global/Global_Enum.h"
|
||||
class Equipment : public Component
|
||||
#include "EngineFrame/Base/Actor.h"
|
||||
class Equipment : public Actor
|
||||
{
|
||||
public:
|
||||
// 职业动画结构体
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
void Mon_Animation::Init(MonsterObject *parent)
|
||||
{
|
||||
// 调用RenderBase类的初始化 才能挂上标签
|
||||
RenderBase::Init();
|
||||
parent->AddChild(this);
|
||||
mon_parent = parent;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
class MonsterObject;
|
||||
class Mon_Animation : public RenderBase
|
||||
class Mon_Animation : public Actor
|
||||
{
|
||||
// 动作动画集合
|
||||
using ActionAniList = std::map<std::string, RefPtr<Animation>>;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user