This commit is contained in:
2026-02-08 16:20:50 +08:00
parent 0ae47e5d6a
commit 8b88904ef7
72 changed files with 5963 additions and 2038 deletions

View File

@@ -95,7 +95,9 @@
"numbers": "cpp", "numbers": "cpp",
"semaphore": "cpp", "semaphore": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"netfwd": "cpp" "netfwd": "cpp",
"coroutine": "cpp",
"cfenv": "cpp"
}, },
"Codegeex.RepoIndex": true "Codegeex.RepoIndex": true
} }

View File

@@ -4,6 +4,16 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/DNF)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
if(MINGW) # 你的环境是 MinGWStrawberry 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项目 # 添加子目录引用squirrel项目
add_subdirectory(Library/squirrel) add_subdirectory(Library/squirrel)
# 添加zlib子项目 # 添加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_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_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_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) add_subdirectory(Library/SDL_mixer)
set(SDL2NET_INSTALL OFF CACHE BOOL "Disable SDL2_net installation" FORCE) set(SDL2NET_INSTALL OFF CACHE BOOL "Disable SDL2_net installation" FORCE)
@@ -74,7 +86,7 @@ file(GLOB_RECURSE SOURCES
) )
add_executable(${PROJECT_NAME} ${SOURCES}) add_executable(${PROJECT_NAME} ${SOURCES})
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O1 -g" CACHE STRING "" FORCE)
if (MINGW) if (MINGW)
target_link_options(${PROJECT_NAME} PRIVATE target_link_options(${PROJECT_NAME} PRIVATE
@@ -112,8 +124,8 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
SDL2_ttf SDL2_ttf
SDL2_net SDL2_net
zlibstatic # zlib库 zlibstatic
squirrel_static # squirrel库根据实际目标名调整 squirrel_static
sqstdlib_static sqstdlib_static
mingwex mingwex

View File

@@ -217,5 +217,26 @@
}, },
"source/EngineFrame/Attribute": { "source/EngineFrame/Attribute": {
"description": "属性" "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": "动画组类"
} }
} }

View 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; // 关联的音效IDTAG属性
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 -> 音乐)
};

View 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;
}

View 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);
};

File diff suppressed because it is too large Load Diff

View 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

View 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 (&lt; &gt; &apos; &quot; &amp;)
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

View 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

View File

@@ -3,6 +3,7 @@
#include "EngineFrame/Component/Sprite.h" #include "EngineFrame/Component/Sprite.h"
#include "EngineFrame/Base/Actor.h" #include "EngineFrame/Base/Actor.h"
#include "EngineFrame/Component/Text.h" #include "EngineFrame/Component/Text.h"
#include "Asset/Asset_SoundPack.h"
Game::Game() Game::Game()
{ {
@@ -67,13 +68,6 @@ void Game::Init(std::function<void()> CallBack)
IMG_Init(IMG_INIT_PNG); 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 // 初始化 TTF
if (TTF_Init() == -1) if (TTF_Init() == -1)
@@ -157,9 +151,16 @@ void Game::HandleEvents(SDL_Event *e)
void Game::Update(float deltaTime) void Game::Update(float deltaTime)
{ {
//调用松鼠的更新 // 内存回收机制
m_lastMemoryPrintTime += deltaTime;
if (m_lastMemoryPrintTime >= m_memoryPrintInterval)
{
m_lastMemoryPrintTime = 0;
MemoryReclaims();
}
// 调用松鼠的更新
SquirrelEx::GetInstance().Update(deltaTime); SquirrelEx::GetInstance().Update(deltaTime);
if (m_scene != nullptr) if (m_scene != nullptr)
m_scene->Update(deltaTime); m_scene->Update(deltaTime);
if (m_uiScene != nullptr) if (m_uiScene != nullptr)
m_uiScene->Update(deltaTime); m_uiScene->Update(deltaTime);
@@ -205,6 +206,12 @@ void Game::Clear()
SDL_Quit(); SDL_Quit();
} }
void Game::MemoryReclaims()
{
// 音频内存回收
Asset_SoundPack::GetInstance().Reclaims();
}
void Game::ChangeScene(RefPtr<Scene> scene) void Game::ChangeScene(RefPtr<Scene> scene)
{ {
if (m_scene != nullptr) if (m_scene != nullptr)
@@ -225,6 +232,11 @@ void Game::ChangeUIScene(RefPtr<Scene> scene)
m_uiScene->Enter(); m_uiScene->Enter();
} }
RefPtr<Scene> Game::GetScene()
{
return m_scene;
}
RenderManager *Game::GetRenderer() RenderManager *Game::GetRenderer()
{ {
return m_renderer; return m_renderer;

View File

@@ -51,10 +51,14 @@ public:
void Render(); void Render();
void Clear(); void Clear();
void MemoryReclaims();
// 切换场景 // 切换场景
void ChangeScene(RefPtr<Scene> scene); void ChangeScene(RefPtr<Scene> scene);
// 设定UI层场景对象 // 设定UI层场景对象
void ChangeUIScene(RefPtr<Scene> scene); void ChangeUIScene(RefPtr<Scene> scene);
// 获取当前游戏层场景
RefPtr<Scene> GetScene();
RenderManager *GetRenderer(); RenderManager *GetRenderer();
@@ -79,7 +83,7 @@ private:
#ifdef __SWITCH__ #ifdef __SWITCH__
float m_Settingfps = 5000.0; float m_Settingfps = 5000.0;
#else #else
float m_Settingfps = 5000.0; float m_Settingfps = 144.0;
#endif #endif
// 单帧时间 // 单帧时间
float m_frameTime = 0.f; float m_frameTime = 0.f;
@@ -88,6 +92,10 @@ private:
// 每秒内的帧数计数器 // 每秒内的帧数计数器
u32 m_frameCounter; u32 m_frameCounter;
u32 m_lastFpsPrintTime; u32 m_lastFpsPrintTime;
// 内存回收计时器
u32 m_lastMemoryPrintTime = 0;
// 内存回收间隔
u32 m_memoryPrintInterval = 5000;
public: public:
// 屏幕宽高 // 屏幕宽高

View File

@@ -1,45 +1,41 @@
#include "Actor.h" #include "Actor.h"
#include "EngineFrame/Scene/Scene.h" #include "EngineFrame/Scene/Scene.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
#include "EngineFrame/Component/RenderBase.h"
#include "EngineFrame/Render/RenderManager.h" #include "EngineFrame/Render/RenderManager.h"
#include <algorithm> #include <algorithm>
Actor::Actor()
{
Init();
}
void Actor::Init() void Actor::Init()
{ {
addTag(Tag::ACTOR);
addTag(Tag::RENDER);
addTag(Tag::TRANSFORM);
addTag(Tag::UPDATE);
} }
void Actor::Update(float deltaTime) void Actor::OnAdded(Actor *node)
{ {
if (!Visible)
return; }
BaseNode::Update(deltaTime);
void Actor::SetBlendMode(LE_BlEND_MODE mode)
{
this->_BlendMode = mode;
}
LE_BlEND_MODE Actor::GetBlendMode()
{
return this->_BlendMode;
} }
void Actor::Render() void Actor::Render()
{ {
if (!Visible)
return;
// 如果有裁切视口 // 如果有裁切视口
if (this->_CropViewportFlag) if (this->_CropViewportFlag)
{ {
RenderManager *renderer = Game::GetInstance().GetRenderer(); RenderManager *renderer = Game::GetInstance().GetRenderer();
renderer->SetClipRect(&this->_CropViewport); renderer->SetClipRect(&this->_CropViewport);
BaseNode::Render(); Node::Render();
renderer->CloseClipRect(); renderer->CloseClipRect();
} }
else else
{ {
BaseNode::Render(); Node::Render();
} }
} }

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include "EngineFrame/Base/BaseNode.h" #include "EngineFrame/Base/Node.h"
#include "Tool/IntrusiveList.hpp" #include "Tool/IntrusiveList.hpp"
class Scene; class Scene;
/** /**
@@ -7,24 +7,31 @@ class Scene;
* *
* Actor类是一个基础的游戏对象类可以添加到场景中 * Actor类是一个基础的游戏对象类可以添加到场景中
*/ */
class Actor : public BaseNode class Actor : public Node
{ {
private: protected:
//裁切视口Flag /**裁切视口Flag */
bool _CropViewportFlag = false; bool _CropViewportFlag = false;
//裁切视口 /**裁切视口 */
SDL_Rect _CropViewport = {0, 0, 0, 0}; SDL_Rect _CropViewport = {0, 0, 0, 0};
/**混合模式 */
LE_BlEND_MODE _BlendMode = NONE;
public: public:
Actor(); // 初始化
virtual void Init();
// 被添加时
virtual void OnAdded(Actor *node);
// 设置混合模式
void SetBlendMode(LE_BlEND_MODE mode);
// 获取混合模式
LE_BlEND_MODE GetBlendMode();
public: public:
void Init() override; /**重载渲染函数 */
void Update(float deltaTime) override;
void Render() override; void Render() override;
// 设置裁切视口(放在Actor里 他与他的子对象都会被裁切) /**设置裁切视口(放在Actor里 他与他的子对象都会被裁切) */
void SetCropViewport(SDL_Rect CropViewport); void SetCropViewport(SDL_Rect CropViewport);
// 获取裁切视口 /**获取裁切视口 */
SDL_Rect GetCropViewport(); SDL_Rect GetCropViewport();
}; };

View File

@@ -1,368 +0,0 @@
#include "BaseNode.h"
#include "EngineCore/Game.h"
BaseNode::BaseNode()
{
Game::GetInstance().m_nodeCount++;
}
BaseNode::~BaseNode()
{
Game::GetInstance().m_nodeCount--;
}
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)
{
// 如果有子节点并含有刷新标签,则更新子节点
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::UPDATE))
child->Update(deltaTime);
child = child->GetNext();
}
// 如果有回调函数,则调用回调函数
if (cb_update_.size() > 0)
{
for (auto &cb : cb_update_)
{
cb.second(deltaTime);
}
}
}
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(std::string Key, const UpdateCallback &cb)
{
cb_update_[Key] = cb;
}
void BaseNode::RemoveCallbackOnUpdate(std::string Key)
{
cb_update_.erase(Key);
}
void BaseNode::SetChildIterationTransform()
{
Transform 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))
{
Transform 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(Transform n_transform)
{
if (n_transform == transformIter)
return;
transformIter = n_transform;
CalcRenderInfo();
SetChildIterationTransform();
}
Transform BaseNode::GetIterationTransform()
{
return transformIter;
}
void BaseNode::SetTransform(Transform n_transform)
{
if (n_transform == transform)
return;
transform = n_transform;
CalcRenderInfo();
SetChildIterationTransform();
}
Transform BaseNode::GetTransform()
{
return transform;
}
void BaseNode::SetPos(Vec2 pos)
{
if (pos == this->transform.position)
return;
this->transform.position = pos;
CalcRenderInfo();
SetChildIterationTransform();
}
Vec2 BaseNode::GetPos()
{
return this->transform.position;
}
Vec2 BaseNode::GetWorldPos()
{
return this->transform.position + this->transformIter.position;
}
void BaseNode::SetScale(Vec2 scale)
{
if (scale == this->transform.scale)
return;
this->transform.scale = scale;
CalcRenderInfo();
SetChildIterationTransform();
}
Vec2 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(Vec2 anchor)
{
if (anchor == this->Anchor)
return;
Anchor.x = anchor.x;
Anchor.y = anchor.y;
}
Vec2 BaseNode::GetAnchor()
{
Vec2 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(Vec2 pos)
{
if (pos == this->transformIter.position)
return;
this->transformIter.position = pos;
CalcRenderInfo();
SetChildIterationTransform();
}
Vec2 BaseNode::GetIterationPos()
{
return this->transformIter.position;
}
void BaseNode::SetIterationScale(Vec2 scale)
{
if (scale == this->transformIter.scale)
return;
this->transformIter.scale = scale;
CalcRenderInfo();
SetChildIterationTransform();
}
Vec2 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;
}
void BaseNode::SetBlendMode(LE_BlEND_MODE mode)
{
this->_BlendMode = mode;
}
LE_BlEND_MODE BaseNode::GetBlendMode()
{
return this->_BlendMode;
}

View File

@@ -1,147 +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 "math/Transform.hpp"
#include "math/Math.h"
using namespace ember;
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:
// 更新时的回调函数
std::map<std::string ,UpdateCallback> cb_update_;
// 节点名称
std::string m_Name;
// 子节点列表
IntrusiveList<RefPtr<BaseNode>> m_BaseNodes;
// 指向父对象的指针
BaseNode *m_Parent = nullptr;
// 渲染层级
int m_RenderZOrder = 0;
// 二维仿射变换
Transform transform;
// 迭代的二维仿射变换
Transform transformIter;
// 锚点
Vec2 Anchor = {0.f, 0.f};
// 大小
VecSize Size = {0, 0};
// 透明度
float Alpha = 1.f;
// 混合模式
LE_BlEND_MODE _BlendMode = NONE;
// 是否显示
bool Visible = true;
// 计算渲染信息Flag (为了保证每帧只计算一次)
bool CalcRenderInfoFlag = true;
public:
BaseNode(/* args */);
~BaseNode();
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(std::string Key,const UpdateCallback &cb);
void RemoveCallbackOnUpdate(std::string Key);
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(Transform transform);
// 获取迭代的二维仿射变换
Transform GetIterationTransform();
// 设置二维仿射变换
void SetTransform(Transform transform);
// 获取二维仿射变换
Transform GetTransform();
// 设置迭代的坐标
virtual void SetIterationPos(Vec2 pos);
// 获取迭代的坐标
Vec2 GetIterationPos();
// 设置迭代的缩放
virtual void SetIterationScale(Vec2 scale);
// 获取迭代的缩放
Vec2 GetIterationScale();
// 设置迭代的旋转角度
virtual void SetIterationRotation(float angle);
// 获取迭代的旋转角度
float GetIterationRotation();
// 设置坐标
virtual void SetPos(Vec2 pos);
// 获取坐标
Vec2 GetPos();
// 获取世界坐标
Vec2 GetWorldPos();
// 设置缩放
virtual void SetScale(Vec2 scale);
// 获取缩放
Vec2 GetScale();
// 设置旋转角度
virtual void SetRotation(float angle);
// 获取旋转角度
float GetRotation();
// 设置中心点
virtual void SetAnchor(Vec2 anchor);
// 获取中心点
Vec2 GetAnchor();
// 设置大小
virtual void SetSize(VecSize size);
// 获取大小
VecSize GetSize();
// 设置是否显示
virtual void SetVisible(bool visible);
// 获取是否显示
bool GetVisible();
// 设置透明度
virtual void SetAlpha(float alpha);
// 获取透明度
float GetAlpha();
// 设置混合模式
void SetBlendMode(LE_BlEND_MODE mode);
// 获取混合模式
LE_BlEND_MODE GetBlendMode();
//获取父对象
BaseNode *GetParent();
};

View File

@@ -5,11 +5,18 @@ void Node::Init()
} }
void Node::HandleEvents(SDL_Event *e) 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) inline void Node::Update(float deltaTime)
{ {
if (children_.IsEmpty()) if (children_.IsEmpty())
{ {
UpdateSelf(deltaTime);
return; return;
} }
@@ -34,26 +41,118 @@ inline void Node::Update(float deltaTime)
} }
inline void Node::PreRender() 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() 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::Clear()
{ {
} }
void Node::OnPreRender()
{
}
void Node::OnRender()
{
}
void Node::OnUpdate(float deltaTime)
{
}
void Node::UpdateSelf(float deltaTime) void Node::UpdateSelf(float deltaTime)
{ {
// 如果有回调函数,则调用回调函数 if (!update_pausing_)
if (cb_update_.size() > 0)
{ {
for (auto &cb : cb_update_) OnUpdate(deltaTime);
// 如果有回调函数,则调用回调函数
if (cb_update_.size() > 0)
{ {
cb.second(deltaTime); 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() void Node::RemoveFromParent()
{ {
if (parent_) if (parent_)
@@ -109,7 +208,7 @@ void Node::ShowBorder(bool show)
show_border_ = 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") 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++; Game::GetInstance().m_nodeCount++;
} }
@@ -146,6 +245,8 @@ void Node::UpdateTransform() const
transform_matrix_ *= parent_->transform_matrix_; transform_matrix_ *= parent_->transform_matrix_;
} }
GenerateRenderMatrix();
for (const auto &child : children_) for (const auto &child : children_)
child->dirty_flag_.Set(DirtyFlag::DirtyTransform); child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
} }
@@ -165,6 +266,26 @@ void Node::UpdateTransformUpwards() const
UpdateTransform(); 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 const Matrix3x2 &Node::GetTransformMatrix() const
{ {
UpdateTransformUpwards(); UpdateTransformUpwards();
@@ -188,6 +309,20 @@ const Matrix3x2 &Node::GetTransformMatrixToParent() const
return transform_matrix_to_parent_; 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() void Node::Reorder()
{ {
if (parent_) if (parent_)
@@ -220,287 +355,24 @@ void Node::Reorder()
} }
} }
inline void Node::RemoveAllChildren() bool Node::CheckVisibility() const
{ {
RefPtr<Node> next; if (dirty_flag_.Has(DirtyFlag::DirtyVisibility))
for (RefPtr<Node> child = children_.GetFirst(); child; child = next)
{ {
next = child->GetNext(); dirty_flag_.Unset(DirtyFlag::DirtyVisibility);
RemoveChild(child);
} if (size_.width == 0.f && size_.height == 0.f)
} {
visible_in_rt_ = false;
inline bool Node::IsVisible() const }
{ else
return visible_; {
} // TODO
// visible_in_rt_ = ctx.CheckVisibility(GetBounds(), transform_matrix_ /* GetTransformMatrix() */);
inline int Node::GetZOrder() const visible_in_rt_ = true;
{ }
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::SetName(std::string name)
{
name_ = name;
}
inline void Node::SetPosition(const glm::vec2 &pos)
{
if (transform_.position == pos)
return;
transform_.position = pos;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
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::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();
} }
return visible_in_rt_;
} }
void Node::AddChild(RefPtr<Node> child) void Node::AddChild(RefPtr<Node> child)
@@ -532,7 +404,7 @@ const Node::NodeList &Node::GetAllChildren() const
return children_; return children_;
} }
inline void Node::RemoveChild(RefPtr<Node> child) void Node::RemoveChild(RefPtr<Node> child)
{ {
if (children_.IsEmpty()) if (children_.IsEmpty())
return; return;

View File

@@ -16,13 +16,19 @@ public:
using IntrusiveListValue<RefPtr<Node>>::GetNext; using IntrusiveListValue<RefPtr<Node>>::GetNext;
using IntrusiveListValue<RefPtr<Node>>::GetPrev; using IntrusiveListValue<RefPtr<Node>>::GetPrev;
private: protected:
/**渲染矩阵 */
mutable glm::mat4 render_matrix_;
/**变换属性 */ /**变换属性 */
Y_Transform transform_; Y_Transform transform_;
/**变换矩阵 */ /**变换矩阵 */
mutable Matrix3x2 transform_matrix_; mutable Matrix3x2 transform_matrix_;
mutable Matrix3x2 transform_matrix_inverse_; mutable Matrix3x2 transform_matrix_inverse_;
mutable Matrix3x2 transform_matrix_to_parent_; mutable Matrix3x2 transform_matrix_to_parent_;
private:
/**更新时的回调函数 */ /**更新时的回调函数 */
std::map<std::string, UpdateCallback> cb_update_; std::map<std::string, UpdateCallback> cb_update_;
/**锚点 */ /**锚点 */
@@ -33,6 +39,8 @@ private:
VecSize size_; VecSize size_;
/**透明度 */ /**透明度 */
float opacity_; float opacity_;
/**显示透明度 */
float displayed_opacity_;
/**是否可见 */ /**是否可见 */
bool visible_; bool visible_;
@@ -40,6 +48,10 @@ private:
bool update_pausing_; bool update_pausing_;
/**是否显示边界 */ /**是否显示边界 */
bool show_border_; bool show_border_;
/**是否在渲染区域中 */
mutable bool visible_in_rt_;
/**联级透明度 */
bool cascade_opacity_;
/**名称 */ /**名称 */
std::string name_; std::string name_;
@@ -58,14 +70,22 @@ public:
virtual void Render(); virtual void Render();
virtual void Clear(); virtual void Clear();
void UpdateSelf(float dt); virtual void OnPreRender();
virtual void OnRender();
virtual void OnUpdate(float deltaTime);
void UpdateSelf(float dt);
void PrepareToRender();
public: public:
/// \~chinese /// \~chinese
/// @brief 获取显示状态 /// @brief 获取显示状态
bool IsVisible() const; bool IsVisible() const;
/// \~chinese
/// @brief 是否启用级联透明度
bool IsCascadeOpacityEnabled() const;
/// \~chinese /// \~chinese
/// @brief 获取 Z 轴顺序 /// @brief 获取 Z 轴顺序
int GetZOrder() const; int GetZOrder() const;
@@ -160,12 +180,18 @@ public:
/// \~chinese /// \~chinese
/// @brief 设置角色是否可见 /// @brief 设置角色是否可见
void SetVisible(bool val); virtual void SetVisible(bool val);
virtual void OnSetPosition();
/// \~chinese /// \~chinese
/// @brief 设置名称 /// @brief 设置名称
void SetName(std::string name); void SetName(std::string name);
/// \~chinese
/// @brief 获取名称
std::string GetName() const;
/// \~chinese /// \~chinese
/// @brief 设置坐标 /// @brief 设置坐标
void SetPosition(const glm::vec2 &pos); void SetPosition(const glm::vec2 &pos);
@@ -246,6 +272,10 @@ public:
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1] /// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
void SetOpacity(float opacity); void SetOpacity(float opacity);
/// \~chinese
/// @brief 启用或禁用级联透明度
void SetCascadeOpacityEnabled(bool enabled);
/// \~chinese /// \~chinese
/// @brief 设置二维仿射变换 /// @brief 设置二维仿射变换
void SetTransform(const Y_Transform &transform); void SetTransform(const Y_Transform &transform);
@@ -328,6 +358,10 @@ public:
/// @details 对于节点树 A->B(dirty)->C->D当对 D 执行 UpdateTransformUpwards 时会对 B、C、D 从上到下依次更新 /// @details 对于节点树 A->B(dirty)->C->D当对 D 执行 UpdateTransformUpwards 时会对 B、C、D 从上到下依次更新
void UpdateTransformUpwards() const; void UpdateTransformUpwards() const;
/// \~chinese
/// @brief 更新自己和所有子角色的透明度
void UpdateOpacity();
/// \~chinese /// \~chinese
/// @brief 获取二维变换矩阵 /// @brief 获取二维变换矩阵
const Matrix3x2 &GetTransformMatrix() const; const Matrix3x2 &GetTransformMatrix() const;
@@ -340,10 +374,18 @@ public:
/// @brief 获取变换到父角色的二维变换矩阵 /// @brief 获取变换到父角色的二维变换矩阵
const Matrix3x2 &GetTransformMatrixToParent() const; const Matrix3x2 &GetTransformMatrixToParent() const;
/// \~chinese
/// @brief 生成用于OpenGL渲染的矩阵
virtual void GenerateRenderMatrix() const;
/// \~chinese /// \~chinese
/// @brief 将所有子角色按Z轴顺序排序 /// @brief 将所有子角色按Z轴顺序排序
void Reorder(); void Reorder();
/// \~chinese
/// @brief 检查是否在渲染上下文的视区内
virtual bool CheckVisibility() const;
enum DirtyFlag : uint8_t enum DirtyFlag : uint8_t
{ {
Clean = 0, Clean = 0,
@@ -353,3 +395,310 @@ public:
DirtyVisibility = 1 << 3 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();
}
}

View File

@@ -27,8 +27,6 @@ Animation::~Animation()
void Animation::Init(std::string AniPath) void Animation::Init(std::string AniPath)
{ {
Actor::Init();
AniScriptParser::AniInfo Info = AssetManager::GetInstance().StructAniInfo(AniPath); AniScriptParser::AniInfo Info = AssetManager::GetInstance().StructAniInfo(AniPath);
this->AniPath = AniPath; this->AniPath = AniPath;
this->AnimationFlag = Info.Flag; this->AnimationFlag = Info.Flag;
@@ -45,17 +43,19 @@ void Animation::Init(std::string AniPath)
FrameObj.Img_Path = AdditionalOptions(FrameObj.Img_Path, this->AdditionalOptionsData); FrameObj.Img_Path = AdditionalOptions(FrameObj.Img_Path, this->AdditionalOptionsData);
} }
SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index); SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index);
SpriteObj->SetAnchor(Vec2(0.5f, 0.5f)); SpriteObj->SetPosition(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y);
SpriteObj->SetPos(Vec2(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y));
SpriteObj->SetVisible(false); SpriteObj->SetVisible(false);
} }
else else
{ {
SpriteObj = new Sprite(); SpriteObj = new Sprite();
SpriteObj->SetVisible(false); SpriteObj->SetVisible(false);
SDL_Log("Animation::Init() SpriteObj is nullptr");
} }
SpriteArr.push_back(SpriteObj); 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); AddChild(SpriteObj);
} }
@@ -76,7 +76,7 @@ void Animation::Init(std::string AniPath)
for (auto &Ani : Info.AniList) for (auto &Ani : Info.AniList)
{ {
RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path); RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
AlsAniObj->SetRenderZOrder(Ani.second.layer[1]); AlsAniObj->SetZOrder(Ani.second.layer[1]);
AddChild(AlsAniObj); AddChild(AlsAniObj);
} }
} }
@@ -84,20 +84,16 @@ void Animation::Init(std::string AniPath)
FlushFrame(0); FlushFrame(0);
} }
void Animation::HandleEvents(SDL_Event *e) void Animation::OnUpdate(float deltaTime)
{
}
void Animation::Update(float deltaTime)
{ {
// 可用性检查 // 可用性检查
if (IsUsability && Visible) if (IsUsability && IsVisible())
{ {
float dt_ms = deltaTime * 1000.0f; float dt_ms = deltaTime * 1000.0f;
// 累加当前帧时间 // 累加当前帧时间
CurrentIndexT += dt_ms; CurrentIndexT += dt_ms;
// 插值模式判断 // 插值模式判断
InterpolationLogic(); // InterpolationLogic();
// 循环处理:只要当前时间超过帧延迟,就切换帧(支持一次跳过多帧) // 循环处理:只要当前时间超过帧延迟,就切换帧(支持一次跳过多帧)
while (CurrentIndexT >= NextFrameDelay) 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); FlushFrame(0);
} }
void Animation::Clear()
{
}
void Animation::SetVisible(bool visible) void Animation::SetVisible(bool visible)
{ {
// 设置启用的时候要更新一下当前帧的渲染信息 避免因为延迟造成的坐标闪烁
if (visible) if (visible)
{ {
CurrentFrame->CalcRenderInfoLogic(); CurrentFrame->SetVisible(true);
CurrentFrame->CalcRenderInfo();
} }
Actor::SetVisible(visible); Actor::SetVisible(visible);
} }
@@ -192,7 +182,8 @@ void Animation::FlushFrame(int Index)
if (FlagBuf.count("IMAGE_RATE")) if (FlagBuf.count("IMAGE_RATE"))
{ {
Vec2 Rate = std::get<Vec2>(FlagBuf["IMAGE_RATE"]); Vec2 Rate = std::get<Vec2>(FlagBuf["IMAGE_RATE"]);
CurrentFrame->SetScale(Vec2{Rate.x, Rate.y}); 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")) if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE"))
@@ -202,7 +193,7 @@ void Animation::FlushFrame(int Index)
// 旋转 // 旋转
if (FlagBuf.count("IMAGE_ROTATE")) if (FlagBuf.count("IMAGE_ROTATE"))
{ {
CurrentFrame->SetAnchor(Vec2{0.5f, 0.5f}); // CurrentFrame->SetAnchor(0.5f, 0.5f);
CurrentFrame->SetRotation(std::get<float>(FlagBuf["IMAGE_ROTATE"])); CurrentFrame->SetRotation(std::get<float>(FlagBuf["IMAGE_ROTATE"]));
} }
// 染色 // 染色
@@ -277,10 +268,10 @@ void Animation::InterpolationLogic()
} }
// 坐标 // 坐标
{ {
Vec2 PosData = { glm::vec2 PosData = {
(OldData.Img_Pos.x + (NewData.Img_Pos.x - OldData.Img_Pos.x) * InterRate), (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)}; (OldData.Img_Pos.y + (NewData.Img_Pos.y - OldData.Img_Pos.y) * InterRate)};
CurrentFrame->SetPos(PosData); CurrentFrame->SetPosition(PosData);
} }
// 缩放 // 缩放
{ {
@@ -294,10 +285,9 @@ void Animation::InterpolationLogic()
{ {
NewRateData = std::get<Vec2>(NewData.Flag["IMAGE_RATE"]); NewRateData = std::get<Vec2>(NewData.Flag["IMAGE_RATE"]);
} }
Vec2 RateData = { glm::vec2 RateData = {
OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate, OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate,
OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate}; OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate};
CurrentFrame->SetAnchor(Vec2{0.5f, 0.5f});
CurrentFrame->SetScale(RateData); CurrentFrame->SetScale(RateData);
} }
// 旋转 // 旋转
@@ -315,3 +305,8 @@ void Animation::InterpolationLogic()
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate); CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate);
} }
} }
VecSize Animation::GetMaxSize()
{
return MaxSize;
}

View File

@@ -24,24 +24,26 @@ public:
Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData); Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData);
~Animation(); ~Animation();
/**初始化 */
void Init(std::string AniPath); void Init(std::string AniPath);
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override; void OnUpdate(float deltaTime) override;
void Render() override; void OnAdded(Actor *node) override;
void OnAdded(BaseNode *node) override;
void Clear() override;
void SetVisible(bool visible) override; void SetVisible(bool visible) override;
public: public:
/**刷新帧 */
void FlushFrame(int Index); void FlushFrame(int Index);
/**重置Ani */
void Reset(); void Reset();
/**获取当前帧信息 */
AniScriptParser::AniFrame GetCurrentFrameInfo(); AniScriptParser::AniFrame GetCurrentFrameInfo();
// 设置帧索引 // 设置帧索引
void SetFrameIndex(int Index); void SetFrameIndex(int Index);
void InterpolationLogic(); void InterpolationLogic();
// TODO SetOutline
// TODO SetDye /**获取最大尺寸 */
// TODO SetCrop VecSize GetMaxSize();
public: public:
// Ani是否可用 // Ani是否可用
@@ -76,20 +78,11 @@ public:
std::string AniPath; std::string AniPath;
// 是否描边 // 是否描边
bool IsOutline = false; 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; std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;
Animation::ReplaceData AdditionalOptionsData; Animation::ReplaceData AdditionalOptionsData;
/**最大尺寸
* 所有子精灵最大的尺寸
*/
VecSize MaxSize = {0, 0};
}; };

View File

@@ -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();
}

View File

@@ -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();
};

View 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()
{
}

View 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;
};

View File

@@ -1,16 +1,29 @@
#include "Canvas.h" #include "Canvas.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
#include "EngineFrame/Render/RenderManager.h" #include "EngineFrame/Render/RenderManager.h"
Canvas::Canvas()
{
}
Canvas::Canvas(VecSize size) Canvas::Canvas(VecSize size)
{
Init(size);
}
Canvas::Canvas(int width, int height)
{
Init({width, height});
}
void Canvas::Init(VecSize size)
{ {
m_size = size; m_size = size;
m_renderRect = {0, 0, size.width, size.height}; SetSize(size);
m_rect = {0, 0, (float)size.width, (float)size.height}; // 创建指定大小的纹理
m_texture = new Texture(); m_texture = new Texture();
m_texture->Init(VecSize(Game::GetInstance().Screen_W, Game::GetInstance().Screen_H)); m_texture->Init(m_size);
Actor::Init();
// 构造FBO
glGenFramebuffers(1, &m_fbo); glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// 将目标纹理附加到FBO的颜色附着点 // 将目标纹理附加到FBO的颜色附着点
@@ -24,92 +37,86 @@ Canvas::Canvas(VecSize size)
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
} }
void Canvas::PreRender() void Canvas::BeginDraw()
{
m_rect.x = GetWorldPos().x;
m_rect.y = GetWorldPos().y;
}
void Canvas::Render()
{ {
RenderManager *renderer = Game::GetInstance().GetRenderer(); RenderManager *renderer = Game::GetInstance().GetRenderer();
SDL_FPoint AnchorPos = {0, 0}; // 绑定FBO
if (m_dirty) glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
{ // 清屏
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // 绑定FBO glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 保存原始的正交矩阵 设置纹理对应的正交矩阵 和 视口
glClear(GL_COLOR_BUFFER_BIT); Oom = renderer->GetOrthoMatrix();
for (auto &info : m_drawQueue) renderer->SetOrthoMatrix(glm::ortho(0.0f, (float)m_size.width, 0.0f, (float)m_size.height, -1.0f, 1.0f));
{ Oviewport = renderer->GetViewport();
renderer->DrawTexture(m_imgMap[info.texture], nullptr, &info.rect, 0.f, &AnchorPos, SDL_FLIP_NONE); renderer->SetViewport({0, 0, m_size.width, m_size.height});
}
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");
} }
void Canvas::DrawImg(std::string img, int index, Vec2 pos) void Canvas::EndDraw()
{ {
m_dirty = true; RenderManager *renderer = Game::GetInstance().GetRenderer();
ImgKey key = {img, index}; // 解绑FBO
DrawInfo info; glBindFramebuffer(GL_FRAMEBUFFER, 0);
info.rect.x = pos.x; // 恢复原始的正交矩阵 和 视口
info.rect.y = pos.y; renderer->SetOrthoMatrix(Oom);
info.texture = key; renderer->SetViewport(Oviewport);
if (m_imgMap.find(key) == m_imgMap.end())
{
RefPtr<Texture> tex = new Texture();
tex->Init(img, index);
m_imgMap[key] = tex;
}
info.rect.w = m_imgMap[key]->getSize().width;
info.rect.h = m_imgMap[key]->getSize().height;
m_drawQueue.push_back(info);
} }
void Canvas::DrawImg(std::string img, int index, SDL_FRect rect) void Canvas::DrawActor(RefPtr<Actor> actor)
{ {
m_dirty = true; // 计算矩阵
ImgKey key = {img, index}; actor->PreRender();
DrawInfo info; // 设定矩阵并渲染(Render中会调用OnRender)
info.rect = rect; actor->Render();
info.texture = key;
if (m_imgMap.find(key) == m_imgMap.end())
{
RefPtr<Texture> tex = new Texture();
tex->Init(img, index);
m_imgMap[key] = tex;
}
m_drawQueue.push_back(info);
} }
void Canvas::Clear() void Canvas::Clear()
{ {
m_drawQueue.clear(); m_texture = new Texture();
m_dirty = true; m_texture->Init(m_size);
} }
void Canvas::Blend() void Canvas::OnRender()
{ {
switch (this->_BlendMode) if (!m_texture || !IsVisible())
return;
RenderManager *renderer = Game::GetInstance().GetRenderer();
if (this->_BlendMode != NONE)
{ {
case LINEARDODGE: renderer->SetBlendMode(this->_BlendMode);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); }
break; 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");
// }

View File

@@ -18,37 +18,37 @@ class Canvas : public Actor
return index < other.index; // 字符串相同则比较index return index < other.index; // 字符串相同则比较index
} }
}; };
struct DrawInfo
{
ImgKey texture;
SDL_FRect rect = {0, 0, 0, 0};
};
private: private:
/**纹理 */ /**纹理 */
RefPtr<Texture> m_texture = nullptr; RefPtr<Texture> m_texture = nullptr;
/**大小 */ /**大小 */
VecSize m_size; VecSize m_size;
/**渲染大小 */
SDL_Rect m_renderRect;
SDL_FRect m_rect;
/**脏标记 */
bool m_dirty = true;
/**FBO */ /**FBO */
GLuint m_fbo = 0; GLuint m_fbo = 0;
/**绘制纹理集 */
std::map<ImgKey, RefPtr<Texture>> m_imgMap; /**原始的正交矩阵 */
/**绘制队列 */ glm::mat4 Oom;
std::vector<DrawInfo> m_drawQueue; /**原始的视口 */
SDL_Rect Oviewport;
public: public:
Canvas();
Canvas(VecSize size); Canvas(VecSize size);
Canvas(int width, int height);
void PreRender() override; /**初始化 */
void Render() override; void Init(VecSize size);
void Blend();
void DrawImg(std::string img, int index, Vec2 pos); /**开始绘制 */
void DrawImg(std::string img, int index, SDL_FRect rect); void BeginDraw();
/**结束绘制 */
void EndDraw();
/**绘制角色 */
void DrawActor(RefPtr<Actor> actor);
/**清空画布 */
void Clear(); void Clear();
/**重载OnRender函数 */
void OnRender() override;
}; };

View File

@@ -1,63 +0,0 @@
#include "RenderBase.h"
#include "EngineFrame/Base/Actor.h"
void RenderBase::CalcRenderInfo()
{
this->CalcRenderInfoFlag = true;
}
void RenderBase::Init()
{
// 计算渲染信息
CalcRenderInfo();
}
void RenderBase::SetIterationPos(Vec2 pos)
{
Actor::SetIterationPos(pos);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetIterationScale(Vec2 scale)
{
Actor::SetIterationScale(scale);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetIterationRotation(float angle)
{
if (!Visible)
return;
Actor::SetIterationRotation(angle);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetPos(Vec2 pos)
{
Actor::SetPos(pos);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetScale(Vec2 scale)
{
Actor::SetScale(scale);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetRotation(float angle)
{
Actor::SetRotation(angle);
CalcRenderInfo(); // 更新渲染信息
}
void RenderBase::SetAnchor(Vec2 anchor)
{
Actor::SetAnchor(anchor);
CalcRenderInfo(); // 更新渲染信息
}

View File

@@ -1,45 +0,0 @@
#pragma once
#include "EngineFrame/Base/Actor.h"
class RenderBase : public Actor
{
public:
struct RenderGuidanceInfo
{
SDL_FRect rect;
// 旋转角度
float rotation;
// 翻转Flag
SDL_RendererFlip flip = SDL_FLIP_NONE;
// 锚点坐标
Vec2 AnchorPos;
// 是否显示
bool Visible = true;
// 是否在屏幕内
bool IsInScreen = false;
};
public:
void Init() override;
public:
// 设置迭代的坐标
void SetIterationPos(Vec2 pos) override;
// 设置迭代的缩放
void SetIterationScale(Vec2 scale) override;
// 设置迭代的旋转角度
void SetIterationRotation(float angle) override;
// 设置坐标
void SetPos(Vec2 pos) override;
// 设置缩放
void SetScale(Vec2 scale) override;
// 设置旋转角度
void SetRotation(float angle) override;
// 设置中心点
void SetAnchor(Vec2 anchor) override;
// 计算渲染信息
void CalcRenderInfo() override;
};

View File

@@ -3,17 +3,31 @@
#include "Text.h" #include "Text.h"
#include "EngineFrame/Render/RenderManager.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() void Sprite::Init()
{ {
this->Size = m_texture->getSize(); SetSize(m_texture->getSize());
RenderBase::Init();
} }
void Sprite::SetTexture(RefPtr<Texture> texture) void Sprite::SetTexture(RefPtr<Texture> texture)
{ {
m_texture = texture; m_texture = texture;
Init(); Init();
CalcRenderInfoLogic(); // 第一次计算
} }
Sprite::Sprite(std::string imgPath, int Index) Sprite::Sprite(std::string imgPath, int Index)
@@ -23,7 +37,6 @@ Sprite::Sprite(std::string imgPath, int Index)
m_texture = new Texture(); m_texture = new Texture();
m_texture->Init(imgPath, Index); m_texture->Init(imgPath, Index);
Init(); Init();
CalcRenderInfoLogic(); // 第一次计算
} }
Sprite::Sprite(std::string PngPath) Sprite::Sprite(std::string PngPath)
@@ -31,7 +44,6 @@ Sprite::Sprite(std::string PngPath)
m_texture = new Texture(); m_texture = new Texture();
m_texture->Init(PngPath); m_texture->Init(PngPath);
Init(); Init();
CalcRenderInfoLogic(); // 第一次计算
} }
Sprite::~Sprite() Sprite::~Sprite()
@@ -43,140 +55,19 @@ RefPtr<Texture> Sprite::GetTexture()
return m_texture; return m_texture;
} }
void Sprite::CalcRenderInfoLogic() void Sprite::OnRender()
{ {
// 获取至在最终的父对象检查是否显示 if (!m_texture || !IsVisible())
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 ? -((float)T_Size.width + (float)T_Pos.x) + SDL_fabsf(transform.position.x * 2.0f) : (float)T_Pos.x;
float texturePosY = flipY ? -((float)T_Size.height + (float)T_Pos.y) + SDL_fabsf(transform.position.y * 2.0f) : (float)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;
// 获取当前帧的原始尺寸
float frameWidth = (float)Size.width;
float frameHeight = (float)Size.height;
// 原始锚点偏移(基于帧尺寸)
float origAnchorOffsetX = frameWidth * Anchor.x;
float origAnchorOffsetY = frameHeight * Anchor.y;
// 缩放的绝对值
float absScaleX = SDL_fabsf(scaleX);
float absScaleY = SDL_fabsf(scaleY);
// 缩放后的尺寸
float scaledWidth = frameWidth * absScaleX;
float scaledHeight = frameHeight * absScaleY;
// 缩放后的锚点偏移
float scaledAnchorOffsetX = origAnchorOffsetX * absScaleX;
float scaledAnchorOffsetY = origAnchorOffsetY * absScaleY;
// 计算缩放后的锚点偏移与原锚点偏移的差值
float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
float Xpos = baseX - scaleOffsetX;
float Ypos = baseY - scaleOffsetY;
// 更新渲染信息
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
// 设置纹理透明度
m_texture->setAlpha(this->Alpha);
// 屏幕内检测
float screenWidth = (float)Game::GetInstance().Screen_W;
float screenHeight = (float)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)
return; return;
RenderManager *renderer = Game::GetInstance().GetRenderer(); RenderManager *renderer = Game::GetInstance().GetRenderer();
if (this->_BlendMode != NONE)
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
{ {
SDL_FPoint AnchorPos; renderer->SetBlendMode(this->_BlendMode);
AnchorPos.x = _RenderGuidanceInfo.AnchorPos.x; }
AnchorPos.y = _RenderGuidanceInfo.AnchorPos.y; renderer->DrawTexture(m_texture);
if (this->_BlendMode != NONE)
// 混合 {
if (this->_BlendMode != NONE) renderer->SetBlendMode(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);
}
}
void Sprite::Clear()
{
}
void Sprite::Blend()
{
switch (this->_BlendMode)
{
case LINEARDODGE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
} }
} }

View File

@@ -1,14 +1,14 @@
#pragma once #pragma once
#include <string> #include <string>
#include "Asset/Asset_ImagePack.h" #include "Asset/Asset_ImagePack.h"
#include "EngineFrame/Component/RenderBase.h"
#include "EngineFrame/Render/Texture.h" #include "EngineFrame/Render/Texture.h"
#include "EngineFrame/Base/Actor.h"
class Game; class Game;
/** /**
* @brief Sprite类继承自Component类用于表示游戏中的精灵组件 * @brief Sprite类继承自Component类用于表示游戏中的精灵组件
*/ */
class Sprite : public RenderBase class Sprite : public Actor
{ {
protected: protected:
RefPtr<Texture> m_texture = nullptr; RefPtr<Texture> m_texture = nullptr;
@@ -18,24 +18,18 @@ public:
Sprite(std::string imgPath, int Index); Sprite(std::string imgPath, int Index);
Sprite(std::string PngPath); Sprite(std::string PngPath);
~Sprite(); ~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(); RefPtr<Texture> GetTexture();
public: /**重载生成渲染矩阵函数 */
// 渲染信息 void GenerateRenderMatrix() const override;
RenderGuidanceInfo _RenderGuidanceInfo; /**重载初始化函数 */
void Init() override;
/**重载渲染函数 */
void OnRender() override;
public:
std::string imgPath; std::string imgPath;
int Index; int Index;
public:
// 计算渲染信息
void CalcRenderInfoLogic();
// 混合
void Blend();
}; };

View File

@@ -22,7 +22,7 @@ RenderManager::RenderManager(SDL_Window *window)
int width, height; int width, height;
SDL_GetWindowSize(window, &width, &height); SDL_GetWindowSize(window, &width, &height);
// 设置视口 // 设置视口
glViewport(0, 0, width, height); SetViewport(SDL_Rect{0, 0, width, height});
// 设置窗口尺寸 // 设置窗口尺寸
_windowWidth = width; _windowWidth = width;
_windowHeight = height; _windowHeight = height;
@@ -33,7 +33,7 @@ RenderManager::RenderManager(SDL_Window *window)
_UIOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f); _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); glEnable(GL_BLEND);
@@ -44,6 +44,8 @@ RenderManager::RenderManager(SDL_Window *window)
InitShaderProgram(); InitShaderProgram();
// 初始化绘制2D纹理缓冲程序 // 初始化绘制2D纹理缓冲程序
Init2DTextureProgram(); Init2DTextureProgram();
// 初始化绘制矩形缓冲程序
InitRectProgram();
// 设定默认使用的着色器程序和缓冲程序 // 设定默认使用的着色器程序和缓冲程序
SetCurrentShaderProgram("normal"); SetCurrentShaderProgram("normal");
@@ -79,17 +81,17 @@ void RenderManager::InitShaderProgram()
{ {
if (!groupData.is_object()) if (!groupData.is_object())
{ {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误,跳过\n", groupName.c_str()); SDL_LogError(0, "着色器组 %s 格式错误,跳过\n", groupName.c_str());
continue; continue;
} }
if (!groupData.contains("vertex") || !groupData["vertex"].is_string()) 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; continue;
} }
if (!groupData.contains("fragment") || !groupData["fragment"].is_string()) 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; continue;
} }
std::string vertPath = groupData["vertex"].get<std::string>(); std::string vertPath = groupData["vertex"].get<std::string>();
@@ -99,7 +101,7 @@ void RenderManager::InitShaderProgram()
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath); GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath);
if (vertexShader == 0 || fragmentShader == 0) 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; continue;
} }
@@ -113,7 +115,7 @@ void RenderManager::InitShaderProgram()
{ {
char infoLog[512]; char infoLog[512];
glGetProgramInfoLog(program, 512, nullptr, infoLog); 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; _shaderProgramMap[groupName] = program;
@@ -142,10 +144,10 @@ void RenderManager::Init2DTextureProgram()
glBindVertexArray(VAO); glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); 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); 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); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
@@ -158,126 +160,71 @@ void RenderManager::Init2DTextureProgram()
glUseProgram(_currentShaderProgram); glUseProgram(_currentShaderProgram);
// 获取uniform变量位置 // 获取uniform变量位置
GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel"); GLint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj"); GLint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture"); GLint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1) 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]( GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, nullptr};
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);
// 处理纹理裁剪
float texWidth = (float)textureObj->getSize().width;
float texHeight = (float)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};
AddBufferObject("2DTexture", bufferObject); 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) void RenderManager::SetCurrentShaderProgram(std::string name)
{ {
if (_shaderProgramMap.find(name) != _shaderProgramMap.end()) if (_shaderProgramMap.find(name) != _shaderProgramMap.end())
@@ -285,7 +232,7 @@ void RenderManager::SetCurrentShaderProgram(std::string name)
this->_currentShaderProgram = _shaderProgramMap[name]; this->_currentShaderProgram = _shaderProgramMap[name];
} }
else 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) void RenderManager::SetCurrentBufferObject(std::string name)
@@ -294,8 +241,8 @@ void RenderManager::SetCurrentBufferObject(std::string name)
{ {
this->_currentRenderParams = _RenderParamsMap[name]; this->_currentRenderParams = _RenderParamsMap[name];
} }
else // else
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str()); // SDL_LogError(0, "找不到渲染参数: %s\n", name.c_str());
} }
void RenderManager::ClearScreen() void RenderManager::ClearScreen()
@@ -320,13 +267,147 @@ void RenderManager::CloseClipRect()
glDisable(GL_SCISSOR_TEST); 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)
{ {
_frameRenderCount++; this->opacity_ = opacity;
if (_currentRenderParams.DrawFunc != nullptr) }
_currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata);
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 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和EBOGPU获取顶点数据和格式的关键
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) void RenderManager::SetOrthoMatrixType(int type)
@@ -347,6 +428,17 @@ void RenderManager::SetOrthoMatrix(glm::mat4 matrix)
_OrthoMatrix = 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) GLuint RenderManager::CompileShader(GLenum type, std::string Path)
{ {
std::ifstream Source("shader/" + Path); std::ifstream Source("shader/" + Path);

View File

@@ -22,7 +22,7 @@ public:
GLuint VAO; GLuint VAO;
GLuint VBO; GLuint VBO;
GLuint EBO; GLuint EBO;
std::vector<GLuint> UnimLocs; std::vector<GLint> UnimLocs;
DrawLogicFunc DrawFunc = nullptr; DrawLogicFunc DrawFunc = nullptr;
}; };
@@ -37,6 +37,8 @@ private:
glm::mat4 _UIOrthoMatrix; glm::mat4 _UIOrthoMatrix;
// 渲染的正交投影矩阵 // 渲染的正交投影矩阵
glm::mat4 _OrthoMatrix; glm::mat4 _OrthoMatrix;
/**视口 */
SDL_Rect _viewport;
// 渲染器上下文 // 渲染器上下文
SDL_GLContext _ctx; SDL_GLContext _ctx;
@@ -50,40 +52,64 @@ private:
// 当前使用渲染参数 // 当前使用渲染参数
GL_RenderParams _currentRenderParams; GL_RenderParams _currentRenderParams;
// 渲染透明度
float opacity_ = 1.0f;
// 渲染矩阵
glm::mat4 _currentMatrix;
public: public:
// 单帧渲染调用次数 // 单帧渲染调用次数
int _frameRenderCount = 0; int _frameRenderCount = 0;
public: public:
RenderManager(SDL_Window *window); RenderManager(SDL_Window *window);
~RenderManager(); ~RenderManager();
// 初始化着色器程序 /**初始化着色器程序 */
void InitShaderProgram(); void InitShaderProgram();
// 初始化绘制2D纹理缓冲程序 /**初始化绘制2D纹理缓冲程序 */
void Init2DTextureProgram(); void Init2DTextureProgram();
// 设定当前使用的着色器程序 /**初始化绘制矩形缓冲程序 */
void InitRectProgram();
/**设定当前使用的着色器程序 */
void SetCurrentShaderProgram(std::string name); void SetCurrentShaderProgram(std::string name);
// 设定当前使用的缓冲对象 /**设定当前使用的缓冲对象 */
void SetCurrentBufferObject(std::string name); void SetCurrentBufferObject(std::string name);
// 清空屏幕 /**清空屏幕 */
void ClearScreen(); void ClearScreen();
// 交换缓冲区 /**交换缓冲区 */
void SwapBuffer(); void SwapBuffer();
// 设置裁切区域 /**设置裁切区域 */
void SetClipRect(const SDL_Rect *rect); void SetClipRect(const SDL_Rect *rect);
// 关闭裁切区域 /**关闭裁切区域 */
void CloseClipRect(); 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); void SetOrthoMatrixType(int type);
// 获取渲染的正交投影矩阵 /**获取渲染的正交投影矩阵 */
glm::mat4 GetOrthoMatrix(); glm::mat4 GetOrthoMatrix();
// 设置渲染的正交投影矩阵 /**设置渲染的正交投影矩阵 */
void SetOrthoMatrix(glm::mat4 matrix); void SetOrthoMatrix(glm::mat4 matrix);
/**设置视口 */
void SetViewport(SDL_Rect viewport);
/**获取视口 */
SDL_Rect GetViewport();
private: private:
// 编译着色器 // 编译着色器

View File

@@ -13,15 +13,14 @@ void Scene::Enter()
void Scene::Init() void Scene::Init()
{ {
BaseNode::Init();
addTag(Tag::SCENE);
} }
void Scene::Exit() void Scene::Exit()
{ {
} }
RefPtr<BaseNode> Scene::GetCamera() RefPtr<Node> Scene::GetCamera()
{ {
return nullptr; return nullptr;
} }

View File

@@ -1,11 +1,11 @@
#pragma once #pragma once
#include "EngineFrame/Base/BaseNode.h" #include "EngineFrame/Base/Node.h"
class Scene : public BaseNode class Scene : public Node
{ {
public: public:
Scene(); Scene();
virtual void Enter(); virtual void Enter();
virtual void Exit(); virtual void Exit();
virtual RefPtr<BaseNode> GetCamera(); virtual RefPtr<Node> GetCamera();
void Init(); void Init();
}; };

View File

@@ -31,6 +31,18 @@ int Ifstream_NPK::ReadInt()
return Count; 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() std::string Ifstream_NPK::ReadString()
{ {
@@ -60,7 +72,7 @@ std::string Ifstream_NPK::ReadInfo()
} }
// 读LONG // 读LONG
int Ifstream_NPK::ReadLong() long Ifstream_NPK::ReadLong()
{ {
char *CountBuffer = new char[8]; char *CountBuffer = new char[8];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
@@ -72,6 +84,18 @@ int Ifstream_NPK::ReadLong()
return Count; 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) BYTE *Ifstream_NPK::ReadCustomSize(int Size)
{ {

View File

@@ -22,6 +22,9 @@ public:
// 读整数 // 读整数
int ReadInt(); int ReadInt();
// 读无符号整数
unsigned int ReadUnsignedInt();
// 读字符串 // 读字符串
std::string ReadString(); std::string ReadString();
@@ -29,7 +32,9 @@ public:
std::string ReadInfo(); std::string ReadInfo();
// 读LONG // 读LONG
int ReadLong(); long ReadLong();
// 读取无符号long
unsigned long ReadUnsignedLong();
// 读指定长度数据 // 读指定长度数据
BYTE *ReadCustomSize(int Size); BYTE *ReadCustomSize(int Size);

View File

@@ -1,5 +1,6 @@
#include "GameMap.h" #include "GameMap.h"
#include "Asset/AssetManager.h" #include "Asset/AssetManager.h"
#include "Asset/Asset_SoundPack.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
#include "EngineFrame/Scene/Scene.h" #include "EngineFrame/Scene/Scene.h"
#include "EngineFrame/Component/Animation.h" #include "EngineFrame/Component/Animation.h"
@@ -19,15 +20,25 @@ GameMap::GameMap()
_LayerMap["max"] = new GameMapLayer(); _LayerMap["max"] = new GameMapLayer();
// 设置图层渲染顺序 // 设置图层渲染顺序
_LayerMap["contact"]->SetRenderZOrder(10000); _LayerMap["contact"]->SetZOrder(10000);
_LayerMap["distantback"]->SetRenderZOrder(50000); _LayerMap["distantback"]->SetZOrder(50000);
_LayerMap["middleback"]->SetRenderZOrder(100000); _LayerMap["middleback"]->SetZOrder(100000);
_LayerMap["bottom"]->SetRenderZOrder(150000); _LayerMap["bottom"]->SetZOrder(150000);
_LayerMap["closeback"]->SetRenderZOrder(200000); _LayerMap["closeback"]->SetZOrder(200000);
_LayerMap["normal"]->SetRenderZOrder(250000); _LayerMap["normal"]->SetZOrder(250000);
_LayerMap["close"]->SetRenderZOrder(300000); _LayerMap["close"]->SetZOrder(300000);
_LayerMap["cover"]->SetRenderZOrder(350000); _LayerMap["cover"]->SetZOrder(350000);
_LayerMap["max"]->SetRenderZOrder(400000); _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() GameMap::~GameMap()
@@ -107,7 +118,7 @@ void GameMap::InitConfiguration(std::string mapName)
{ {
BackGroundAni ani; BackGroundAni ani;
Data.Get(); Data.Get();
ani.filename = _MapDir + Tool_toLowerCase(Data.Get()); ani.filename = Tool_RegRealPath(_MapDir + Tool_toLowerCase(Data.Get()));
Data.Get(); Data.Get();
ani.layer = Data.Get(); ani.layer = Data.Get();
Data.Get(); Data.Get();
@@ -119,13 +130,13 @@ void GameMap::InitConfiguration(std::string mapName)
} }
else if (Segment == "[sound]") else if (Segment == "[sound]")
{ {
std::vector<std::string> soundArry; std::map<std::string, bool> soundArry;
while (true) while (true)
{ {
std::string sounddata = Data.Get(); std::string sounddata = Data.Get();
if (sounddata == "[/sound]") if (sounddata == "[/sound]")
break; break;
soundArry.push_back(sounddata); soundArry[sounddata] = true;
} }
_MapInfo["sound"] = soundArry; _MapInfo["sound"] = soundArry;
} }
@@ -174,13 +185,17 @@ void GameMap::InitConfiguration(std::string mapName)
std::string areadata = Data.Get(); std::string areadata = Data.Get();
if (areadata == "[/town movable area]") if (areadata == "[/town movable area]")
break; break;
town_movable_area.push_back(std::stoi(areadata)); int x1 = std::stoi(areadata);
town_movable_area.push_back(std::stoi(areadata)); int y1 = std::stoi(Data.Get());
town_movable_area.push_back(std::stoi(areadata)); int x2 = std::stoi(Data.Get());
town_movable_area.push_back(std::stoi(areadata)); 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; MapMoveArea T;
T.town = std::stoi(areadata); T.town = std::stoi(Data.Get());
T.area = std::stoi(areadata); T.area = std::stoi(Data.Get());
town_movable_area_info.push_back(T); town_movable_area_info.push_back(T);
} }
_MapInfo["town_movable_area"] = town_movable_area; _MapInfo["town_movable_area"] = town_movable_area;
@@ -212,25 +227,19 @@ void GameMap::InitTile()
int NormalTileCount = 0; int NormalTileCount = 0;
// 普通地板高度 // 普通地板高度
int NormalTileHeight = 560; int NormalTileHeight = 560;
std::vector<std::string> tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]); std::vector<std::string> tileArr;
if (tileArr.size() > 0) std::vector<std::string> extileArr;
{
NormalTileCount = tileArr.size();
_MapLength = NormalTileCount * 224;
_MapHeight = 560;
}
if (!_MapInfo.count("extended_tile"))
return;
std::vector<std::string> extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]); tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
if (extileArr.size() > 0)
// 拓展地板不一定有
if (_MapInfo.count("extended_tile"))
{ {
int ExTileCount = extileArr.size(); extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
int Buffer = (ExTileCount / NormalTileCount);
_MapHeight += (Buffer < 1 ? 1 : Buffer) * 40;
} }
_Tile = new Tile(this, tileArr, extileArr); _Tile = new Tile(this, tileArr, extileArr);
_Tile->SetPosition(0, -200 - std::get<int>(_MapInfo["background_pos"]));
_LayerMap["bottom"]->AddChild(_Tile); _LayerMap["bottom"]->AddChild(_Tile);
} }
@@ -256,8 +265,8 @@ void GameMap::InitBackgroundAnimation()
} }
for (int i = 0; i < (int)AniList.size(); i++) for (int i = 0; i < (int)AniList.size(); i++)
{ {
AniList[i]->SetPos(Vec2{i * width, -120}); AniList[i]->SetPosition(i * width, -120);
AniList[i]->SetRenderZOrder(-1000000); AniList[i]->SetZOrder(-1000000);
std::string layer = ani.layer; std::string layer = ani.layer;
layer = layer.substr(1, layer.length() - 2); layer = layer.substr(1, layer.length() - 2);
if (_LayerMap.count(layer)) if (_LayerMap.count(layer))
@@ -281,8 +290,8 @@ void GameMap::InitMapAnimation()
{ {
std::string path = ani.filename; std::string path = ani.filename;
RefPtr<Animation> AniObj = new Animation(path); RefPtr<Animation> AniObj = new Animation(path);
AniObj->SetPos(Vec2{ani.XPos, ani.YPos - ani.ZPos}); AniObj->SetPosition(ani.XPos, ani.YPos - ani.ZPos);
AniObj->SetRenderZOrder(ani.YPos); AniObj->SetZOrder(ani.YPos);
std::string layer = ani.layer; std::string layer = ani.layer;
layer = layer.substr(1, layer.length() - 2); layer = layer.substr(1, layer.length() - 2);
if (_LayerMap.count(layer)) if (_LayerMap.count(layer))
@@ -305,12 +314,30 @@ void GameMap::InitVirtualMovableArea()
float w = Info[i + 2]; float w = Info[i + 2];
float h = Info[i + 3]; float h = Info[i + 3];
if (_DebugMode) if (_DebugMode)
_LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h)); _LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h), 0);
_MovableArea.push_back(SDL_FRect{x, y, w, h}); _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) void GameMap::LoadMap(std::string mapName)
{ {
// 读取脚本配置 // 读取脚本配置
@@ -323,24 +350,41 @@ void GameMap::LoadMap(std::string mapName)
InitMapAnimation(); InitMapAnimation();
// 初始化可行区域 // 初始化可行区域
InitVirtualMovableArea(); InitVirtualMovableArea();
// 初始化传送区域
InitMoveArea();
} }
void GameMap::Enter(Scene *scene) void GameMap::Enter()
{ {
AddChild(_LayerMap["contact"]); auto &Audio = Asset_SoundPack::GetInstance();
AddChild(_LayerMap["distantback"]); // 获取背景音乐
AddChild(_LayerMap["middleback"]); auto bgmIt = _MapInfo.find("sound");
AddChild(_LayerMap["bottom"]); if (bgmIt != _MapInfo.end())
AddChild(_LayerMap["closeback"]); {
AddChild(_LayerMap["normal"]); std::map<std::string, bool> bgmlist = std::get<std::map<std::string, bool>>(_MapInfo["sound"]);
AddChild(_LayerMap["close"]); // 获取正在播放的背景音乐
AddChild(_LayerMap["cover"]); std::map<std::string, int> curmap = Audio.GetBackgroudMusicVector();
AddChild(_LayerMap["max"]); 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::Update(float deltaTime) void GameMap::OnUpdate(float deltaTime)
{ {
Actor::Update(deltaTime);
RefPtr<GameCamera> Cam = Global_Game::GetInstance().GetCamera(); RefPtr<GameCamera> Cam = Global_Game::GetInstance().GetCamera();
if (Cam == nullptr) if (Cam == nullptr)
@@ -384,8 +428,11 @@ void GameMap::Update(float deltaTime)
posX *= BackgroundMoveSpeed; posX *= BackgroundMoveSpeed;
posX /= 100.0f; posX /= 100.0f;
} }
Layer.second->SetPos(Vec2(posX, posY)); Layer.second->SetPosition(posX, posY);
} }
Actor::OnUpdate(deltaTime);
} }
void GameMap::AddObject(RefPtr<BaseObject> object) void GameMap::AddObject(RefPtr<BaseObject> object)
@@ -397,9 +444,6 @@ void GameMap::AddObject(RefPtr<BaseObject> object)
{ {
CharacterObject *chr = (CharacterObject *)(object.Get()); CharacterObject *chr = (CharacterObject *)(object.Get());
Global_Game::GetInstance().GetCamera()->SetFromActor(chr); Global_Game::GetInstance().GetCamera()->SetFromActor(chr);
if (chr->_Shadow)
_LayerMap["bottom"]->AddChild(chr->_Shadow);
} }
} }
@@ -460,3 +504,41 @@ VecFPos3 GameMap::CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset)
return result; 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;
}

View File

@@ -10,6 +10,7 @@ class BaseObject;
class GameMapCamera; class GameMapCamera;
class GameMap : public Actor class GameMap : public Actor
{ {
public:
struct BackGroundAni struct BackGroundAni
{ {
std::string filename; std::string filename;
@@ -37,13 +38,14 @@ class GameMap : public Actor
struct MapMoveArea struct MapMoveArea
{ {
int town; int town = 0;
int area; int area = 0;
}; };
using MapInfoBody = std::variant< using MapInfoBody = std::variant<
int, int,
std::string, std::string,
std::map<std::string, bool>,
std::vector<BackGroundAni>, std::vector<BackGroundAni>,
std::vector<MapAni>, std::vector<MapAni>,
std::vector<MapNpc>, std::vector<MapNpc>,
@@ -66,6 +68,8 @@ public:
int _MapHeight = 0; int _MapHeight = 0;
// 可行区域 // 可行区域
std::vector<SDL_FRect> _MovableArea; std::vector<SDL_FRect> _MovableArea;
// 传送区域
std::vector<SDL_FRect> _MoveArea;
// 调试模式 // 调试模式
bool _DebugMode = false; bool _DebugMode = false;
@@ -81,17 +85,36 @@ public:
GameMap(/* args */); GameMap(/* args */);
~GameMap(); ~GameMap();
/**加载地图 (地图路径) */
void LoadMap(std::string mapName); void LoadMap(std::string mapName);
/**进入地图执行的操作 */
void Enter();
/**重载OnUpdate函数 */
void OnUpdate(float deltaTime) override;
public:
/**读取脚本配置 */
void InitConfiguration(std::string mapName); void InitConfiguration(std::string mapName);
/**初始化地板 */
void InitTile(); void InitTile();
/**初始化背景动画 */
void InitBackgroundAnimation(); void InitBackgroundAnimation();
/**初始化地图动画 */
void InitMapAnimation(); void InitMapAnimation();
/**初始化移动区域 */
void InitVirtualMovableArea(); void InitVirtualMovableArea();
void Enter(Scene *scene); /**初始化传送区域 */
void Update(float deltaTime) override; void InitMoveArea();
/**添加对象 */
void AddObject(RefPtr<BaseObject> object); void AddObject(RefPtr<BaseObject> object);
public: public:
// 检查是否可移动 // 检查是否可移动
VecFPos3 CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset); VecFPos3 CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset);
// 检查是否进入传送区域
MapMoveArea CheckIsItMoveArea(VecFPos3 CurPos);
/**获取移动区域信息 */
std::vector<GameMap::MapMoveArea> &GetMoveAreaInfo();
/**获取移动区域坐标信息 */
SDL_Rect GetMovablePositionArea(int Index);
}; };

View File

@@ -1,35 +1,47 @@
#include "GameMapLayer.h" #include "GameMapLayer.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
void GameMapLayer::Render() void GameMapLayer::Render()
{ {
Actor::Render(); Actor::Render();
// RenderManager *renderer = Game::GetInstance().GetRenderer(); // 自身坐标
glm::vec2 Pos = this->ConvertToWorld({0, 0});
// // 自身坐标 // 可行区域
// float Xpos = GetIterationPos().x + GetPos().x; for (auto &info : this->FeasibleAreaInfoList)
// float Ypos = GetIterationPos().y + GetPos().y; {
// for (auto &info : this->FeasibleAreaInfoList) SDL_Rect buf;
// { buf.x = info.x + Pos.x;
// SDL_Rect buf; buf.y = info.y + Pos.y;
// buf.x = info.x + Xpos; buf.w = info.w;
// buf.y = info.y + Ypos; buf.h = info.h;
// buf.w = info.w; glm::vec4 red = {1.0f, 0.0f, 0.0f, 0.4f}; // RGBA红色不透明基础色
// buf.h = info.h; Game::GetInstance().GetRenderer()->DrawRect(&buf, red);
// //TODO: 渲染可行区域 }
// } // 移动区域
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(Vec2 pos, VecSize size) void GameMapLayer::AddDebugFeasibleAreaInfo(Vec2 pos, VecSize size, int Type)
{ {
SDL_Rect info; SDL_Rect info;
info.x = pos.x; info.x = pos.x;
info.y = pos.y; info.y = pos.y;
info.w = size.width; info.w = size.width;
info.h = size.height; 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) void GameMapLayer::AddObject(RefPtr<Actor> obj)

View File

@@ -9,12 +9,14 @@ class GameMapLayer : public Actor
private: private:
// 可行区域信息 // 可行区域信息
std::vector<SDL_Rect> FeasibleAreaInfoList; std::vector<SDL_Rect> FeasibleAreaInfoList;
// 移动区域信息
std::vector<SDL_Rect> MoveAreaInfoList;
public: public:
// 重载Render以实现绘制可行区域 // 重载OnRender以实现绘制可行区域
void Render() override; void Render() override;
// 添加调试可行区域信息 // 添加调试可行区域信息
void AddDebugFeasibleAreaInfo(Vec2 pos, VecSize size); void AddDebugFeasibleAreaInfo(Vec2 pos, VecSize size, int Type);
public: public:
void AddObject(RefPtr<Actor> obj); // 添加对象 void AddObject(RefPtr<Actor> obj); // 添加对象

View 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);
}

View 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;
};

View 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();
}

View 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();
};

View File

@@ -4,56 +4,29 @@
#include "Actor/Map/GameMap.h" #include "Actor/Map/GameMap.h"
#include "Global/Global_Game.h" #include "Global/Global_Game.h"
// Tile::Tile(std::string Path) : Sprite()
// {
// InitInfo(Path);
// if (std::get<std::string>(m_data["path"]) == "")
// m_data["path"] = "sprite/character/common/circlecooltime.img";
// 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;
// }
Tile::Tile(GameMap *parentMap, std::vector<std::string> normal, std::vector<std::string> ex) Tile::Tile(GameMap *parentMap, std::vector<std::string> normal, std::vector<std::string> ex)
{ {
m_parentMap = parentMap; m_parentMap = parentMap;
m_texture = new Texture();
// 通过父对象获取地图大小
int Width = m_parentMap->_MapLength;
int Height = m_parentMap->_MapHeight;
// 通过大小纹理大小
m_texture->Init(VecSize(Width, Height));
m_rect = {0, 0, (float)Width, (float)Height};
Actor::Init();
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
for (size_t i = 0; i < normal.size(); i++) for (size_t i = 0; i < normal.size(); i++)
{ {
InitTile(normal[i], i); InitTile(normal[i], i);
} }
m_tileX = normal.size();
for (size_t i = 0; i < ex.size(); i++) for (size_t i = 0; i < ex.size(); i++)
{ {
InitExTile(ex[i], i); InitExTile(ex[i], i);
} }
SetPos(Vec2(0, 80 - 200 - std::get<int>(m_parentMap->_MapInfo["background_pos"]))); // 有可能没写地板
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() Tile::~Tile()
@@ -66,6 +39,9 @@ void Tile::InitTile(std::string Path, int Index)
TileInfo data; TileInfo data;
InitInfo(Path, 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"]); std::string path = std::get<std::string>(data["path"]);
int index = std::get<int>(data["idx"]); int index = std::get<int>(data["idx"]);
// 如果是个空地板 给他默认赋值 // 如果是个空地板 给他默认赋值
@@ -77,18 +53,20 @@ void Tile::InitTile(std::string Path, int Index)
// 判断是否存在标识符对应的纹理,如果不存在则创建 // 判断是否存在标识符对应的纹理,如果不存在则创建
if (m_imgMap.find(key) == m_imgMap.end()) if (m_imgMap.find(key) == m_imgMap.end())
{ {
RefPtr<Texture> tex = new Texture(); RefPtr<Sprite> tex = new Sprite(path, index);
tex->Init(path, index);
m_imgMap[key] = tex; 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; DrawInfo info;
info.rect.x = Index * m_imgMap[key]->getSize().width + m_imgMap[key]->getPos().x; info.sprite_ = key;
info.rect.y = m_imgMap[key]->getPos().y; info.pos = {Index * 224, ImgOffset};
info.rect.w = m_imgMap[key]->getSize().width;
info.rect.h = m_imgMap[key]->getSize().height;
info.texture = key;
// 添加到绘制信息列表
m_drawQueue.push_back(info); m_drawQueue.push_back(info);
} }
@@ -98,6 +76,9 @@ void Tile::InitExTile(std::string Path, int Index)
TileInfo data; TileInfo data;
InitInfo(Path, 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"]); std::string path = std::get<std::string>(data["path"]);
int index = std::get<int>(data["idx"]); int index = std::get<int>(data["idx"]);
// 如果是个空地板 给他默认赋值 // 如果是个空地板 给他默认赋值
@@ -109,28 +90,23 @@ void Tile::InitExTile(std::string Path, int Index)
// 判断是否存在标识符对应的纹理,如果不存在则创建 // 判断是否存在标识符对应的纹理,如果不存在则创建
if (m_imgMap.find(key) == m_imgMap.end()) if (m_imgMap.find(key) == m_imgMap.end())
{ {
RefPtr<Texture> tex = new Texture(); RefPtr<Sprite> tex = new Sprite(path, index);
tex->Init(path, index);
m_imgMap[key] = tex; 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; DrawInfo info;
info.rect.x = Index * m_imgMap[key]->getSize().width + m_imgMap[key]->getPos().x; info.sprite_ = key;
info.rect.y = m_imgMap[key]->getPos().y + 560 + ((Index / m_tileX) * 120); info.pos = {Index * 224, m_tileY + m_BasicTileHeight + ((Index / m_Tile_X_Count) * 120)};
info.rect.w = m_imgMap[key]->getSize().width;
info.rect.h = m_imgMap[key]->getSize().height;
info.texture = key;
// 添加到绘制信息列表
m_drawQueue.push_back(info); m_drawQueue.push_back(info);
} }
// void Tile::SetPos(Vec2 pos)
// {
// // pos.y += std::get<int>(m_data["pos"]);
// // Sprite::SetPos(pos);
// }
void Tile::InitInfo(std::string Path, TileInfo &m_data) void Tile::InitInfo(std::string Path, TileInfo &m_data)
{ {
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(Path); ScriptData Data = AssetManager::GetInstance().GetScriptInfo(Path);
@@ -151,46 +127,13 @@ void Tile::InitInfo(std::string Path, TileInfo &m_data)
} }
} }
void Tile::PreRender() void Tile::DrawTile()
{ {
m_rect.x = GetWorldPos().x; BeginDraw();
m_rect.y = GetWorldPos().y; for (auto &info : m_drawQueue)
//计算摄像机位置 知道自己需要渲染多大的区域
// m_srcRect = {0, 0, m_parentMap->_MapLength, m_parentMap->_MapHeight};
// Vec2 Pos = Global_Game::GetInstance().GetCamera() -> _currentPosition;
// m_srcRect = {Pos.x < 1067 ? 0 : Pos.x - 1067, Pos.y, 1067, 600};
}
void Tile::Render()
{
RenderManager *renderer = Game::GetInstance().GetRenderer();
SDL_FPoint AnchorPos = {0, 0};
if (!m_isBuild)
{ {
// 保存原始的正交矩阵 设置纹理对应的正交矩阵 和 视口 m_imgMap[info.sprite_]->SetPosition(info.pos);
auto oldOm = Game::GetInstance().GetRenderer()->GetOrthoMatrix(); DrawActor(m_imgMap[info.sprite_]);
Game::GetInstance().GetRenderer()->SetOrthoMatrix(glm::ortho(0.0f, (float)m_texture->getSize().width, (float)m_texture->getSize().height, 0.0f, -1.0f, 1.0f));
glViewport(0, 0, m_texture->getSize().width, m_texture->getSize().height);
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
// 还原原始的正交矩阵 和 视口
Game::GetInstance().GetRenderer()->SetOrthoMatrix(oldOm);
glViewport(0, 0, Game::GetInstance().Screen_W, Game::GetInstance().Screen_H);
m_isBuild = true;
} }
EndDraw();
renderer->SetCurrentShaderProgram("flip_y");
renderer->DrawTexture(m_texture, nullptr, &m_rect, 0.f, &AnchorPos, SDL_FLIP_NONE);
renderer->SetCurrentShaderProgram("normal");
} }

View File

@@ -1,9 +1,12 @@
#pragma once #pragma once
#include "Asset/AssetManager.h" #include "Asset/AssetManager.h"
#include "EngineFrame/Component/Canvas.h" #include "EngineFrame/Component/Canvas.h"
#include "EngineFrame/Component/Sprite.h"
class GameMap; class GameMap;
class Tile : public Actor class Tile : public Canvas
{ {
public:
struct ImgKey struct ImgKey
{ {
std::string img; std::string img;
@@ -20,46 +23,40 @@ class Tile : public Actor
}; };
struct DrawInfo struct DrawInfo
{ {
ImgKey texture; ImgKey sprite_;
SDL_FRect rect = {0, 0, 0, 0}; glm::vec2 pos;
}; };
public: using TileInfoBody = std::variant<int, std::string>;
using TileInfoBody = std::variant<int,std::string>;
using TileInfo = std::unordered_map<std::string, TileInfoBody>; using TileInfo = std::unordered_map<std::string, TileInfoBody>;
private: private:
/**纹理 */ /**父对象地图 */
RefPtr<Texture> m_texture = nullptr; GameMap *m_parentMap;
/**FBO */ /**绘制精灵集 */
GLuint m_fbo = 0; std::map<ImgKey, RefPtr<Sprite>> m_imgMap;
/**地图父对象 */
GameMap* m_parentMap;
/**绘制纹理集 */
std::map<ImgKey, RefPtr<Texture>> m_imgMap;
/**绘制队列 */ /**绘制队列 */
std::vector<DrawInfo> m_drawQueue; std::vector<DrawInfo> m_drawQueue;
/**渲染大小 */ /**基础地板宽度 */
SDL_Rect m_srcRect; float m_BasicTileWidth = 0;
SDL_FRect m_rect; /**基础地板高度 */
float m_BasicTileHeight = 0;
/**Ex地板高度 */
float m_ExTileHeight = 0;
/**大纹理构造完成Flag */ /**横向地板数量 */
bool m_isBuild = false; int m_Tile_X_Count = 0;
/**纵向最大偏移 */
/**Tile横轴个数 */ float m_tileY = 0;
int m_tileX = 0;
public: public:
Tile(GameMap *parentMap, std::vector<std::string> normal,std::vector<std::string> ex); Tile(GameMap *parentMap, std::vector<std::string> normal, std::vector<std::string> ex);
~Tile(); ~Tile();
void InitTile(std::string Path,int Index); void InitTile(std::string Path, int Index);
void InitExTile(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, TileInfo &m_data);
void PreRender() override; void DrawTile();
void Render() override;
// void SetPos(Vec2 pos) override;
}; };

View File

@@ -19,7 +19,7 @@ VecSpeed3 ActiveObject::GetSpeed()
return this->Speed; return this->Speed;
} }
void ActiveObject::Update(float deltaTime) void ActiveObject::OnUpdate(float deltaTime)
{ {
VecFPos3 MovePos; VecFPos3 MovePos;
@@ -51,6 +51,4 @@ void ActiveObject::Update(float deltaTime)
} }
MoveBy(MovePos); MoveBy(MovePos);
BaseObject::Update(deltaTime);
} }

View File

@@ -11,13 +11,12 @@ public:
int _zRemainderMove = 0; int _zRemainderMove = 0;
public: public:
void void SetPosition(VecFPos3 pos) override;
SetPosition(VecFPos3 pos) override;
void SetYpos(int y) override; void SetYpos(int y) override;
void SetSpeed(VecSpeed3 speed); void SetSpeed(VecSpeed3 speed);
VecSpeed3 GetSpeed(); VecSpeed3 GetSpeed();
public: public:
void Update(float deltaTime) override; void OnUpdate(float deltaTime) override;
}; };

View File

@@ -3,7 +3,7 @@
BaseObject::BaseObject() BaseObject::BaseObject()
{ {
Init(); // 调用了RenderBase的Init函数 对象才会被执行回调 // 对象要使用中心锚点
SetAnchor({0.5f, 0.5f}); SetAnchor({0.5f, 0.5f});
} }
@@ -11,21 +11,16 @@ BaseObject::~BaseObject()
{ {
} }
void BaseObject::Update(float deltaTime)
{
Actor::Update(deltaTime);
}
void BaseObject::SetPosition(VecFPos3 pos) void BaseObject::SetPosition(VecFPos3 pos)
{ {
if(pos == this->Position) if(pos == this->Position)
return; return;
if (pos.y != this->Position.y) if (pos.y != this->Position.y)
{ {
SetRenderZOrder(pos.y); // 设置渲染顺序 SetZOrder(pos.y); // 设置渲染顺序
} }
this->Position = pos; this->Position = pos;
SetPos(Vec2{this->Position.x, this->Position.y - this->Position.z}); Actor::SetPosition(this->Position.x, this->Position.y - this->Position.z);
} }
VecFPos3 BaseObject::GetPosition() VecFPos3 BaseObject::GetPosition()
@@ -38,7 +33,7 @@ void BaseObject::SetXpos(int x)
if (x == this->Position.x) if (x == this->Position.x)
return; return;
this->Position.x = x; 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) void BaseObject::SetYpos(int y)
@@ -47,10 +42,10 @@ void BaseObject::SetYpos(int y)
return; return;
if (y != this->Position.y) if (y != this->Position.y)
{ {
SetRenderZOrder(y); // 设置渲染顺序 SetZOrder(y); // 设置渲染顺序
} }
this->Position.y = 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) void BaseObject::SetZpos(int z)
@@ -58,7 +53,7 @@ void BaseObject::SetZpos(int z)
if (z == this->Position.z) if (z == this->Position.z)
return; return;
this->Position.z = z; 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() int BaseObject::GetXpos()
@@ -84,11 +79,11 @@ void BaseObject::MoveBy(VecFPos3 pos)
return; return;
if (RealPos.y != this->Position.y) if (RealPos.y != this->Position.y)
{ {
SetRenderZOrder(RealPos.y); // 设置渲染顺序 SetZOrder(RealPos.y); // 设置渲染顺序
} }
if (RealPos != this->Position){ if (RealPos != this->Position){
this->Position = RealPos; this->Position = RealPos;
SetPos({this->Position.x, this->Position.y - this->Position.z}); Actor::SetPosition({this->Position.x, this->Position.y - this->Position.z});
} }
} }
@@ -100,28 +95,28 @@ void BaseObject::MoveBy(int x, int y, int z)
return; return;
if (RealPos.y != this->Position.y) if (RealPos.y != this->Position.y)
{ {
SetRenderZOrder(RealPos.y); // 设置渲染顺序 SetZOrder(RealPos.y); // 设置渲染顺序
} }
if (RealPos != this->Position) if (RealPos != this->Position)
{ {
this->Position = RealPos; 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) void BaseObject::SetDirection(int dir)
{ {
this->Direction = dir; this->Direction = dir;
Vec2 sc = GetScale(); glm::vec2 sc = GetScale();
// 朝右 // 朝右
if (dir == 0) if (dir == 0)
{ {
SetScale(Vec2({SDL_fabsf(sc.x), sc.y})); SetScale(SDL_fabsf(sc.x), sc.y);
} }
// 朝左 // 朝左
else if (dir == 1) else if (dir == 1)
{ {
SetScale(Vec2({-SDL_fabsf(sc.x), sc.y})); SetScale(-SDL_fabsf(sc.x), sc.y);
} }
} }

View File

@@ -16,8 +16,6 @@ public:
BaseObject(/* args */); BaseObject(/* args */);
~BaseObject(); ~BaseObject();
void Update(float deltaTime) override;
// 数据储存器 // 数据储存器
ObjectVars _ObjectVars; ObjectVars _ObjectVars;

View File

@@ -1,5 +1,7 @@
#include "CharacterObject.h" #include "CharacterObject.h"
#include "Asset/Squirrel/SquirrelManager.h" #include "Asset/Squirrel/SquirrelManager.h"
#include "Actor/Map/GameMap.h"
#include "Actor/Map/GameWorld.h"
CharacterObject::~CharacterObject() CharacterObject::~CharacterObject()
{ {
@@ -12,9 +14,6 @@ void CharacterObject::Construction(int job)
// 创建装备管理器 // 创建装备管理器
_EquipmentManager = new Chr_Equipment(); _EquipmentManager = new Chr_Equipment();
_EquipmentManager->Init(this); _EquipmentManager->Init(this);
// // 创建阴影对象
// _Shadow = new Chr_Shadow();
// _Shadow->Init(this);
// 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备) // 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备)
_AnimationManager = new Chr_Animation(); _AnimationManager = new Chr_Animation();
_AnimationManager->Init(this); _AnimationManager->Init(this);
@@ -51,19 +50,35 @@ void CharacterObject::ControllerMsg(CONTROLLER_MSG_TYPE msgType, void *msgData)
} }
} }
void CharacterObject::Update(float deltaTime) void CharacterObject::SetPosition(VecFPos3 pos)
{ {
ActiveObject::Update(deltaTime); BaseObject::SetPosition(pos);
}
void CharacterObject::SetPos(Vec2 pos)
{
BaseObject::SetPos(pos);
if(_Shadow)_Shadow->SetPos(this->GetPos());
} }
void CharacterObject::SetDirection(int dir) void CharacterObject::SetDirection(int dir)
{ {
BaseObject::SetDirection(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;
}
} }

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "EngineFrame/Base/Actor.h"
#include "Actor/Object/ActiveObject.h" #include "Actor/Object/ActiveObject.h"
#include "Asset/Character/Chr_Animation.h" #include "Asset/Character/Chr_Animation.h"
#include "Asset/Character/Chr_Equipment.h" #include "Asset/Character/Chr_Equipment.h"
#include "Asset/Character/Chr_Controller.h" #include "Asset/Character/Chr_Controller.h"
#include "Asset/Character/Chr_StateMachine.h" #include "Asset/Character/Chr_StateMachine.h"
#include "Asset/Character/Chr_Shadow.h"
#include "Global/Global_Enum.h" #include "Global/Global_Enum.h"
class CharacterObject : public ActiveObject class CharacterObject : public ActiveObject
{ {
@@ -18,12 +18,12 @@ public:
// 角色状态机 // 角色状态机
RefPtr<Chr_StateMachine> _StateMachine = nullptr; RefPtr<Chr_StateMachine> _StateMachine = nullptr;
// 角色阴影对象
RefPtr<Chr_Shadow> _Shadow = nullptr;
// 职业 // 职业
int Job = 0; int Job = 0;
// 转职职业 如果是-1则没有转职 // 转职职业 如果是-1则没有转职
int GrowType = -1; int GrowType = -1;
/** 传送区域Flag */
bool IsTeleportArea = false;
public: public:
~CharacterObject(); ~CharacterObject();
@@ -39,7 +39,8 @@ public:
// 控制器信息 // 控制器信息
void ControllerMsg(CONTROLLER_MSG_TYPE msgType, void* msgData); void ControllerMsg(CONTROLLER_MSG_TYPE msgType, void* msgData);
void Update(float deltaTime) override; void SetPosition(VecFPos3 pos) override;
void SetPos(Vec2 pos) override;
void SetDirection(int dir) override; void SetDirection(int dir) override;
void OnUpdate(float deltaTime) override;
}; };

View File

@@ -22,21 +22,20 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
if (slotName == "skin_avatar") if (slotName == "skin_avatar")
{ {
// 如果穿戴了皮肤时装 读取variation // 如果穿戴了皮肤时装 读取variation
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName); RefPtr<Equipment> Equip = ((CharacterObject *)GetParent())->_EquipmentManager->GetEquip(slotName);
if (Equip) if (Equip)
{ {
Animation::ReplaceData Data(0, 0); Animation::ReplaceData Data(0, 0);
for (auto &Variation : Equip->JobAni[this->chr_parent->Job]) for (auto &Variation : Equip->JobAni[this->chr_parent->Job])
{ {
Data.Param1 = Variation.ImgFormat[0]; Data.Param1 = Variation.ImgFormat[0];
Data.Param2 = Variation.ImgFormat[1]; Data.Param2 = Variation.ImgFormat[1];
// 构造Ani以后 统一设置为不可见 然后放入ActionAnis表 // 构造Ani
RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data); RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data);
Ani->SetVisible(false); Ani->SetZOrder(Variation.Layer);
// 将构造好的Ani 添加进AniMap
Ani->SetRenderZOrder(Variation.Layer); ActionAnis[actionName]->AddAnimation(Ani);
this->AddChild(Ani);
ActionAnis[actionName].push_back(Ani);
// 构造一下阴影对象 //TODO // 构造一下阴影对象 //TODO
// RefPtr<Animation> ShadowAni = new Animation(path, FormatImgPath, Data); // RefPtr<Animation> ShadowAni = new Animation(path, FormatImgPath, Data);
@@ -49,10 +48,9 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
} }
else else
{ {
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName); RefPtr<Equipment> Equip = ((CharacterObject *)GetParent())->_EquipmentManager->GetEquip(slotName);
if (Equip) if (Equip)
{ {
// SDL_Log("CreateSkinmationBySlot %s", slotName.c_str());
Animation::ReplaceData Data(0, 0); Animation::ReplaceData Data(0, 0);
for (auto &Variation : Equip->JobAni[this->chr_parent->Job]) for (auto &Variation : Equip->JobAni[this->chr_parent->Job])
{ {
@@ -64,12 +62,11 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
// 组装动画路径 // 组装动画路径
std::string AniPath = EquipPath + Variation.AnimationGroup + path.substr(path.find_last_of("/"), path.length()); std::string AniPath = EquipPath + Variation.AnimationGroup + path.substr(path.find_last_of("/"), path.length());
// 构造Ani以后 统一设置为不可见 然后放入ActionAnis表 // 构造Ani
RefPtr<Animation> Ani = new Animation(AniPath, FormatImgPath, Data); RefPtr<Animation> Ani = new Animation(AniPath, FormatImgPath, Data);
Ani->SetVisible(false); Ani->SetZOrder(Variation.Layer);
Ani->SetRenderZOrder(Variation.Layer); // 将构造好的Ani 添加进AniMap
this->AddChild(Ani); ActionAnis[actionName]->AddAnimation(Ani);
ActionAnis[actionName].push_back(Ani);
} }
} }
} }
@@ -77,8 +74,6 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
void Chr_Animation::Init(CharacterObject *parent) void Chr_Animation::Init(CharacterObject *parent)
{ {
// 调用RenderBase类的初始化 才能挂上标签
RenderBase::Init();
parent->AddChild(this); parent->AddChild(this);
chr_parent = parent; chr_parent = parent;
GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job]; GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job];
@@ -89,12 +84,20 @@ void Chr_Animation::Init(CharacterObject *parent)
std::string ActionName = pair.first; std::string ActionName = pair.first;
std::string Path = std::string("character/" + Config.jobTag + "/" + Tool_toLowerCase(pair.second)); std::string Path = std::string("character/" + Config.jobTag + "/" + Tool_toLowerCase(pair.second));
//以动作为Key构造AniMap
ActionAnis[ActionName] = new AnimationMap();
ActionAnis[ActionName]->SetVisible(false);
// 遍历所有时装部位构造Ani // 遍历所有时装部位构造Ani
for (auto &AvatarPartPair : AvatarPart) for (auto &AvatarPartPair : AvatarPart)
{ {
std::string AvatarPartName = AvatarPartPair.first; std::string AvatarPartName = AvatarPartPair.first;
CreateSkinmationBySlot(ActionName, AvatarPartName, Path); CreateSkinmationBySlot(ActionName, AvatarPartName, Path);
} }
// 将所有时装部位的Ani添加到动作AniMap以后完成构造
ActionAnis[ActionName]->CompleteConstruction();
this->AddChild(ActionAnis[ActionName]);
} }
// 设置初始动作 // 设置初始动作
SetAction("rest"); SetAction("rest");
@@ -103,18 +106,9 @@ void Chr_Animation::Init(CharacterObject *parent)
void Chr_Animation::SetAction(std::string actionName) void Chr_Animation::SetAction(std::string actionName)
{ {
// 先将原动作的Ani设置为不可见 // 先将原动作的Ani设置为不可见
for (auto Ani : ActionAnis[CurrentActionTag]) ActionAnis[CurrentActionTag]->Reset();
{ ActionAnis[CurrentActionTag]->SetVisible(false);
Ani->Reset();
Ani->SetVisible(false);
}
// 再将新动作的Ani设置为可见 // 再将新动作的Ani设置为可见
for (auto Ani : ActionAnis[actionName]) ActionAnis[actionName]->SetVisible(true);
{
Ani->SetVisible(true);
}
CurrentActionTag = actionName; CurrentActionTag = actionName;
// 设置阴影的动作
if(chr_parent->_Shadow)chr_parent->_Shadow->SetAction(actionName);
} }

View File

@@ -1,13 +1,14 @@
#pragma once #pragma once
#include "EngineFrame/Component/Animation.h" #include "EngineFrame/Base/Actor.h"
#include "EngineFrame/Component/AnimationMap.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
class CharacterObject; class CharacterObject;
class Chr_Animation : public RenderBase class Chr_Animation : public Actor
{ {
// 动作动画集合 // 动作动画集合
using ActionAniList = std::map<std::string, std::vector<RefPtr<Animation>>>; using ActionAniList = std::map<std::string, RefPtr<AnimationMap>>;
public: public:
inline static const std::unordered_map<std::string, std::string> inline static const std::unordered_map<std::string, std::string>

View File

@@ -28,7 +28,6 @@ float Chr_Controller::ConvertAxisValue(Sint16 rawValue)
void Chr_Controller::Init(CharacterObject *pCharacter) void Chr_Controller::Init(CharacterObject *pCharacter)
{ {
addTag(Tag::HANDEL_EVENT);
m_pCharacter = pCharacter; m_pCharacter = pCharacter;
} }

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "EngineFrame/Base/BaseNode.h" #include "EngineFrame/Base/Node.h"
#include "Tool/Common.h" #include "Tool/Common.h"
class CharacterObject; class CharacterObject;
class Chr_Controller : public BaseNode class Chr_Controller : public Node
{ {
private: private:
CharacterObject *m_pCharacter = nullptr; CharacterObject *m_pCharacter = nullptr;

View File

@@ -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)
{
Vec2 sc = GetScale();
// 朝右
if (dir == 0)
{
SetScale(Vec2({SDL_fabsf(sc.x), sc.y}));
}
// 朝左
else if (dir == 1)
{
SetScale(Vec2({-SDL_fabsf(sc.x), sc.y}));
}
}

View File

@@ -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);
};

View File

@@ -5,7 +5,6 @@
void Chr_StateMachine::Init(CharacterObject *parent) void Chr_StateMachine::Init(CharacterObject *parent)
{ {
chr_Parent = parent; chr_Parent = parent;
addTag(Tag::UPDATE);
parent->AddChild(this); parent->AddChild(this);
} }
void Chr_StateMachine::ChangeState(int state) void Chr_StateMachine::ChangeState(int state)

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "Global/Global_Enum.h" #include "Global/Global_Enum.h"
#include "EngineFrame/Base/Actor.h" #include "EngineFrame/Base/Node.h"
class CharacterObject; class CharacterObject;
class Chr_StateMachine : public Actor class Chr_StateMachine : public Node
{ {
private: private:
// 父对象 // 父对象

View File

@@ -4,7 +4,6 @@
void Mon_Animation::Init(MonsterObject *parent) void Mon_Animation::Init(MonsterObject *parent)
{ {
// 调用RenderBase类的初始化 才能挂上标签 // 调用RenderBase类的初始化 才能挂上标签
RenderBase::Init();
parent->AddChild(this); parent->AddChild(this);
mon_parent = parent; mon_parent = parent;

View File

@@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
class MonsterObject; class MonsterObject;
class Mon_Animation : public RenderBase class Mon_Animation : public Actor
{ {
// 动作动画集合 // 动作动画集合
using ActionAniList = std::map<std::string, RefPtr<Animation>>; using ActionAniList = std::map<std::string, RefPtr<Animation>>;

View File

@@ -78,7 +78,7 @@ static SQInteger SQR_GetZOrder(HSQUIRRELVM v)
SQUserPointer A_obj; SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
sq_pushinteger(v, Aobj->GetRenderZOrder()); sq_pushinteger(v, Aobj->GetZOrder());
return 1; return 1;
} }
@@ -89,7 +89,7 @@ static SQInteger SQR_SetZOrder(HSQUIRRELVM v)
SQInteger Value; SQInteger Value;
sq_getinteger(v, 3, &Value); sq_getinteger(v, 3, &Value);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Aobj->SetRenderZOrder(Value); Aobj->SetZOrder(Value);
return 0; return 0;
} }
@@ -98,7 +98,7 @@ static SQInteger SQR_GetPos(HSQUIRRELVM v)
SQUserPointer A_obj; SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Vec2 Pos = Aobj->GetPos(); glm::vec2 Pos = Aobj->GetPosition();
sq_newtable(v); sq_newtable(v);
sq_pushstring(v, _SC("x"), -1); sq_pushstring(v, _SC("x"), -1);
@@ -117,7 +117,7 @@ static SQInteger SQR_SetPos(HSQUIRRELVM v)
if (sq_gettop(v) == 3) if (sq_gettop(v) == 3)
{ {
Vec2 Pos; glm::vec2 Pos;
sq_pushnull(v); // null iterator sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 3))) while (SQ_SUCCEEDED(sq_next(v, 3)))
{ {
@@ -139,7 +139,7 @@ static SQInteger SQR_SetPos(HSQUIRRELVM v)
sq_pop(v, 1); sq_pop(v, 1);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Aobj->SetPos(Pos); Aobj->SetPosition(Pos);
} }
else if (sq_gettop(v) == 4) else if (sq_gettop(v) == 4)
{ {
@@ -147,7 +147,7 @@ static SQInteger SQR_SetPos(HSQUIRRELVM v)
sq_getfloat(v, 3, &X); sq_getfloat(v, 3, &X);
sq_getfloat(v, 4, &Y); sq_getfloat(v, 4, &Y);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Aobj->SetPos(Vec2(X, Y)); Aobj->SetPosition(glm::vec2(X, Y));
} }
return 0; return 0;
} }
@@ -157,7 +157,7 @@ static SQInteger SQR_GetWorldPos(HSQUIRRELVM v)
SQUserPointer A_obj; SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Vec2 Pos = Aobj->GetWorldPos(); glm::vec2 Pos = Aobj->ConvertToWorld(glm::vec2(0, 0));
sq_newtable(v); sq_newtable(v);
sq_pushstring(v, _SC("x"), -1); sq_pushstring(v, _SC("x"), -1);
@@ -175,7 +175,7 @@ static SQInteger SQR_GetAlpha(HSQUIRRELVM v)
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
sq_pushfloat(v, Aobj->GetAlpha()); sq_pushfloat(v, Aobj->GetOpacity());
return 1; return 1;
} }
static SQInteger SQR_SetAlpha(HSQUIRRELVM v) static SQInteger SQR_SetAlpha(HSQUIRRELVM v)
@@ -185,7 +185,7 @@ static SQInteger SQR_SetAlpha(HSQUIRRELVM v)
SQFloat Value; SQFloat Value;
sq_getfloat(v, 3, &Value); sq_getfloat(v, 3, &Value);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Aobj->SetAlpha(Value); Aobj->SetOpacity(Value);
return 0; return 0;
} }
@@ -194,7 +194,7 @@ static SQInteger SQR_GetScale(HSQUIRRELVM v)
SQUserPointer A_obj; SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Vec2 Pos = Aobj->GetScale(); glm::vec2 Pos = Aobj->GetScale();
sq_newtable(v); sq_newtable(v);
sq_pushstring(v, _SC("x"), -1); sq_pushstring(v, _SC("x"), -1);
sq_pushfloat(v, Pos.x); sq_pushfloat(v, Pos.x);
@@ -212,7 +212,7 @@ static SQInteger SQR_SetScale(HSQUIRRELVM v)
if (sq_gettop(v) == 3) if (sq_gettop(v) == 3)
{ {
Vec2 Pos; glm::vec2 Pos;
sq_pushnull(v); // null iterator sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 3))) while (SQ_SUCCEEDED(sq_next(v, 3)))
{ {
@@ -242,7 +242,7 @@ static SQInteger SQR_SetScale(HSQUIRRELVM v)
sq_getfloat(v, 3, &X); sq_getfloat(v, 3, &X);
sq_getfloat(v, 4, &Y); sq_getfloat(v, 4, &Y);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
Aobj->SetScale(Vec2(X, Y)); Aobj->SetScale(X, Y);
} }
return 0; return 0;
} }
@@ -342,7 +342,7 @@ static SQInteger SQR_GetVisible(HSQUIRRELVM v)
SQUserPointer A_obj; SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj); sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj; Actor *Aobj = (Actor *)A_obj;
sq_pushbool(v, Aobj->GetVisible()); sq_pushbool(v, Aobj->IsVisible());
return 1; return 1;
} }
@@ -391,7 +391,7 @@ static SQInteger SQR_Canvas_DrawImg(HSQUIRRELVM v)
sq_getinteger(v, 4, &Idx); sq_getinteger(v, 4, &Idx);
sq_GetVec2(v, 5, &Pos); sq_GetVec2(v, 5, &Pos);
Canvas *Aobj = (Canvas *)A_obj; Canvas *Aobj = (Canvas *)A_obj;
Aobj->DrawImg(ImgPath, Idx, Pos); // Aobj->DrawImg(ImgPath, Idx, Pos);
return 0; return 0;
} }
@@ -406,7 +406,7 @@ static SQInteger SQR_Canvas_DrawImgRect(HSQUIRRELVM v)
sq_getinteger(v, 4, &Idx); sq_getinteger(v, 4, &Idx);
sq_GetFRect(v, 5, &Rect); sq_GetFRect(v, 5, &Rect);
Canvas *Aobj = (Canvas *)A_obj; Canvas *Aobj = (Canvas *)A_obj;
Aobj->DrawImg(ImgPath, Idx, Rect); // Aobj->DrawImg(ImgPath, Idx, Rect);
return 0; return 0;
} }

View File

@@ -72,9 +72,12 @@ void Global_Game::InitGame()
EquipmentPathMap = GlobalEquipmentScript::InitEquipmentLst(); EquipmentPathMap = GlobalEquipmentScript::InitEquipmentLst();
// 读取怪物配置文件 // 读取怪物配置文件
MonsterPathMap = GlobalMonsterScript::InitMonsterLst(); MonsterPathMap = GlobalMonsterScript::InitMonsterLst();
// 读取城镇配置文件
TownPathMap = GlobalTownScript::InitTownLst();
// 初始化松鼠脚本管理器 // 初始化松鼠脚本管理器
SquirrelManager::GetInstance().Init(); SquirrelManager::GetInstance()
.Init();
// 读取存档 // 读取存档
SavaManager::GetInstance().Init(); SavaManager::GetInstance().Init();
@@ -105,6 +108,30 @@ GlobalMonsterScript::MonsterConfig Global_Game::GetMonsterInfo(int id)
return MonsterConfig; return MonsterConfig;
} }
const std::map<int, std::string> &Global_Game::GetTownMap() const
{
return TownPathMap;
}
GlobalTownScript::TownConfig *Global_Game::GetTownInfo(int id)
{
if (TownInfoMap.count(id))
return TownInfoMap[id];
if (!TownPathMap.count(id))
{
SDL_LogError(0, "城镇ID不存在");
return nullptr;
}
std::string path = TownPathMap[id];
GlobalTownScript::TownConfig *TownConfig = GlobalTownScript::GetTownConfig(path);
if (TownConfig)
{
TownInfoMap[id] = TownConfig;
return TownConfig;
}
return nullptr;
}
RefPtr<GameCamera> Global_Game::GetCamera() RefPtr<GameCamera> Global_Game::GetCamera()
{ {
return _GameCamera; return _GameCamera;

View File

@@ -3,6 +3,7 @@
#include "Global/Script/CharacterConfig.h" #include "Global/Script/CharacterConfig.h"
#include "Global/Script/EquipmentConfig.h" #include "Global/Script/EquipmentConfig.h"
#include "Global/Script/MonsterConfig.h" #include "Global/Script/MonsterConfig.h"
#include "Global/Script/TownConfig.h"
#include "Global/Save/SavaManager.h" #include "Global/Save/SavaManager.h"
#include "Global/GameCamera.h" #include "Global/GameCamera.h"
class Global_Game class Global_Game
@@ -43,6 +44,12 @@ public:
std::map<int, GlobalMonsterScript::MonsterConfig> MonsterInfoMap; // 信息 std::map<int, GlobalMonsterScript::MonsterConfig> MonsterInfoMap; // 信息
GlobalMonsterScript::MonsterConfig GetMonsterInfo(int id); // 获取怪物信息 GlobalMonsterScript::MonsterConfig GetMonsterInfo(int id); // 获取怪物信息
// 城镇相关
std::map<int, std::string> TownPathMap; // 路径
std::map<int, GlobalTownScript::TownConfig *> TownInfoMap; // 信息
const std::map<int, std::string>& GetTownMap() const; // 获取城镇路径
GlobalTownScript::TownConfig *GetTownInfo(int id); // 获取城镇信息
// 游戏摄像机 // 游戏摄像机
RefPtr<GameCamera> _GameCamera = nullptr; RefPtr<GameCamera> _GameCamera = nullptr;

View File

@@ -0,0 +1,58 @@
#include "TownConfig.h"
#include "Asset/AssetManager.h"
#include "Tool/Tool_String.h"
namespace GlobalTownScript
{
std::map<int, std::string> InitTownLst()
{
std::map<int, std::string> TownList;
ScriptData Data = AssetManager::GetInstance().GetScriptInfo("town/town.lst");
while (!Data.IsEnd())
{
std::string Index = Data.Get();
std::string MonsterPath = std::string("town/") + Tool_toLowerCase(Data.Get());
TownList[std::stoi(Index)] = MonsterPath;
}
return TownList;
}
TownConfig *GetTownConfig(std::string TownPath)
{
TownConfig *Config = new TownConfig();
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(TownPath);
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[entering title]")
{
Config->Entering_Title = "sprite/" + Tool_toLowerCase(Data.Get());
}
else if (Segment == "[cutscene image]")
{
Config->Entering_Cutscene = "sprite/" + Tool_toLowerCase(Data.Get());
}
else if (Segment == "[area]")
{
int Index = std::stoi(Data.Get());
std::string MapPath = "map/" + Tool_toLowerCase(Data.Get());
std::string TypeBuffer = Data.Get();
std::string Type = TypeBuffer.substr(1, TypeBuffer.size() - 2);
int GenerateXPos = -1;
int GenerateYPos = -1;
if (Type == "gate")
{
GenerateXPos = std::stoi(Data.Get());
GenerateYPos = std::stoi(Data.Get());
}
Config->AreaLst[Index] = AreaConfig{MapPath, Type, GenerateXPos, GenerateYPos};
}
else if (Segment == "[name]")
{
Config->TownName = Data.Get();
}
}
return Config;
}
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <string>
#include <vector>
#include <map>
namespace GlobalTownScript
{
struct AreaConfig
{
/**地图路径 */
std::string MapPath;
/**地图类型 */
std::string MapType;
/**生成坐标X */
int GenerateXPos = 0;
/**生成坐标Y */
int GenerateYPos = 0;
};
/**城镇配置 */
struct TownConfig
{
/**城镇名称 */
std::string TownName;
/**进入城镇时的标题Img */
std::string Entering_Title;
/**进入城镇时的过场Img */
std::string Entering_Cutscene;
/**需要的任务进入条件 */
int NeedQuestID = -1;
/**需要的等级进入条件 */
int NeedLevel = -1;
/**区域 */
std::map<int, AreaConfig> AreaLst;
};
// 读取城镇列表
std::map<int, std::string> InitTownLst();
// 读取城镇配置
TownConfig *GetTownConfig(std::string TownPath);
}

View File

@@ -1,6 +1,6 @@
#include "Scene/Scene_Loading_UI.h" #include "Scene/Scene_Loading_UI.h"
#include "Scene/Scene_MainUi.h" #include "Scene/Scene_MainUi.h"
#include "Scene/Scene_Test.h" #include "Actor/Map/GameWorld.h"
#include "Scene_Loading_UI.h" #include "Scene_Loading_UI.h"
#include "EngineFrame/Component/Sprite.h" #include "EngineFrame/Component/Sprite.h"
#include "EngineFrame/Component/Text.h" #include "EngineFrame/Component/Text.h"
@@ -15,6 +15,10 @@ void Scene_Loading_UI::Enter()
{ {
Mix_PlayMusic(music, 1); Mix_PlayMusic(music, 1);
} }
else
{
printf("Mix_LoadMUS: %s\n", Mix_GetError());
}
RefPtr<Actor> actor = new Actor; RefPtr<Actor> actor = new Actor;
AddChild(actor); AddChild(actor);
@@ -22,19 +26,19 @@ void Scene_Loading_UI::Enter()
RefPtr<Sprite> BackGroundSp = new Sprite("ImagePacks2/Loading1.png"); RefPtr<Sprite> BackGroundSp = new Sprite("ImagePacks2/Loading1.png");
actor->AddChild(BackGroundSp); actor->AddChild(BackGroundSp);
RefPtr<Sprite> BackGround2Sp = new Sprite("ImagePacks2/Loading0.png"); RefPtr<Sprite> BackGround2Sp = new Sprite("ImagePacks2/Loading0.png");
BackGround2Sp->SetPos(Vec2{0, 686}); BackGround2Sp->SetPosition(0, 686);
actor->AddChild(BackGround2Sp); actor->AddChild(BackGround2Sp);
RefPtr<Sprite> LoadCircleSp = new Sprite("ImagePacks2/Loading2.png"); RefPtr<Sprite> LoadCircleSp = new Sprite("ImagePacks2/Loading2.png");
LoadCircleSp->SetName("LoadCircle"); LoadCircleSp->SetName("LoadCircle");
LoadCircleSp->SetPos(Vec2{1280 - 60, 686 - 60}); LoadCircleSp->SetPosition(1280 - 60, 686 - 60);
LoadCircleSp->SetBlendMode(LINEARDODGE); LoadCircleSp->SetBlendMode(LINEARDODGE);
LoadCircleSp->SetAnchor(Vec2{0.5f, 0.5f}); LoadCircleSp->SetAnchor(0.5f, 0.5f);
actor->AddChild(LoadCircleSp); actor->AddChild(LoadCircleSp);
actor->SetCallbackOnUpdate("Rotate", [LoadCircleSp](float deltaTime) mutable actor->SetCallbackOnUpdate("Rotate", [LoadCircleSp](float deltaTime) mutable
{ {
float angle = LoadCircleSp->GetRotation(); float angle = LoadCircleSp->GetRotation();
LoadCircleSp->SetRotation(angle + 180.0f * deltaTime); }); LoadCircleSp->SetRotation(angle - 180.0f * deltaTime); });
} }
void Scene_Loading_UI::Update(float deltaTime) void Scene_Loading_UI::Update(float deltaTime)
@@ -43,7 +47,7 @@ void Scene_Loading_UI::Update(float deltaTime)
if (Global_Game::GetInstance().InitFlag) if (Global_Game::GetInstance().InitFlag)
{ {
// 设定游戏层场景 // 设定游戏层场景
RefPtr<Scene_Test> scene = new Scene_Test; RefPtr<GameWorld> scene = new GameWorld;
Game::GetInstance().ChangeScene(scene); Game::GetInstance().ChangeScene(scene);
// 设定UI层场景 // 设定UI层场景
RefPtr<Scene_MainUi> sceneUI = new Scene_MainUi; RefPtr<Scene_MainUi> sceneUI = new Scene_MainUi;

View File

@@ -1,122 +0,0 @@
#include "Scene_Test.h"
#include <memory>
#include "EngineCore/Game.h"
#include "EngineFrame/Component/AnimationManager.h"
#include "EngineFrame/Component/Text.h"
#include "EngineFrame/Component/Canvas.h"
#include "Global/Global_Game.h"
Scene_Test::Scene_Test()
{
}
Scene_Test::~Scene_Test()
{
SDL_Log("Scene_Test::我的ID是%d --- 我被释放了!", this->MyId);
}
void Scene_Test::Enter()
{
map = new GameMap;
map->LoadMap("map/cataclysm/town/elvengard/new_elvengard.map");
map->Enter(this);
AddChild(map);
map->SetCallbackOnUpdate("csas", [this](float dt)
{
Vec2 pos = map->GetPos();
pos.x -= 10 * dt;
map->SetPos(pos); });
// RefPtr<CharacterObject> obj = new CharacterObject();
// obj->SetPosition({1000, 300, 0});
// obj->Construction(0);
// map->AddObject(obj);
// RefPtr<MonsterObject> monster = new MonsterObject();
// monster->SetPosition({1200, 301, 0});
// monster->Construction(1);
// monster->SetDirection(1);
// map->AddObject(monster);
return;
// // SDL_Log("Scene_Test::进入测试场景!");
RefPtr<Actor> actor = new Actor;
AddChild(actor);
// RefPtr<Sprite> sprite = new Sprite("ImagePacks2/test_white_background.png");
RefPtr<Sprite> chr = new Sprite("sprite/interface2/hud/hud.img", 0);
chr->SetPos(Vec2{200, 100});
// chr->SetAlpha(0.5);
// chr->SetShadow();
// actor->AddComponent(chr);
RefPtr<Canvas> canvas = new Canvas(VecSize{250, 720});
actor->AddChild(canvas);
canvas->DrawImg("sprite/interface2/hud/hud.img", 0, Vec2{0, 0});
// canvas->AddChild(chr);
// RefPtr<AnimationManager> Am = new AnimationManager;
// RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// Am->AddAnimation(ani4);
// // Am->SetPos(Vec2{200, 100});
// actor->AddChild(Am);
// // sprite2->UnsetClipRect();
// RefPtr<Actor> actor2 = new Actor;
// actor->AddChild(actor2);
// RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// // ani4->SetScale(Vec2{-1.0, 1.0});
// actor->AddChild(ani4);
// RefPtr<Animation> ani3 = new Animation("map/cataclysm/town/elvengard/animation/obj/serialight01_right.ani");
// actor->AddChild(ani3);
// RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// ani4->SetPos(VecPos{300, 500});
// actor->AddChild(ani4);
// for (size_t i = 0; i < 400; i++)
// {
// RefPtr<Actor> actor = new Actor;
// AddChild(actor);
// // RefPtr<Animation> ani3 = new Animation("common/commoneffect/animation/priestslowheal1.ani");
// // actor->AddComponent(ani3);
// // ani3->SetRenderZOrder(1000);
// // RefPtr<Animation> ani = new Animation("common/anton/main.ani");
// // actor->AddComponent(ani);
// // ani->SetRenderZOrder(500);
// RefPtr<Sprite> sprite = new Sprite("sprite/item/avatar/swordman/0sm_acap.img", 0);
// actor->AddComponent(sprite);
// // RefPtr<Animation> ani2 = new Animation("common/anton/face/0/0.ani");
// // actor->AddComponent(ani2);
// // ani2->SetRenderZOrder(1000);
// }
}
void Scene_Test::HandleEvents(SDL_Event *e)
{
Scene::HandleEvents(e);
}
void Scene_Test::Update(float deltaTime)
{
Scene::Update(deltaTime);
}
void Scene_Test::Render()
{
Scene::Render();
}
void Scene_Test::Exit()
{
SDL_Log("Scene_Test::退出测试场景!当前引用计数%d", this->GetRefCount());
}

View File

@@ -1,28 +0,0 @@
#pragma once
#include "EngineFrame/Scene/Scene.h"
#include "Asset/AssetManager.h"
#include "EngineFrame/Component/Animation.h"
#include "Actor/Map/GameMap.h"
#include "Actor/Object/CharacterObject.h"
#include "Actor/Object/MonsterObject.h"
class Scene_Test : public Scene
{
private:
GameMap *map = nullptr;
public:
Scene_Test(/* args */);
~Scene_Test();
public:
void Enter() override;
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override;
void Render() override;
void Exit() override;
public:
int MyId = 0;
};

View File

@@ -16,6 +16,7 @@
#endif #endif
#include "Asset/Asset_ImagePack.h" #include "Asset/Asset_ImagePack.h"
#include "Asset/Asset_SoundPack.h"
#include "Asset/Asset_Script.h" #include "Asset/Asset_Script.h"
#include "squirrel/SquirrelEx.h" #include "squirrel/SquirrelEx.h"
#include "Tool/Logger.h" #include "Tool/Logger.h"
@@ -56,7 +57,7 @@ int main(int argc, char *argv[])
socketInitializeDefault(); socketInitializeDefault();
nxlinkStdio(); // 启用nxlink调试输出 nxlinkStdio(); // 启用nxlink调试输出
curl_global_init(CURL_GLOBAL_DEFAULT); // 初始化libcurl curl_global_init(CURL_GLOBAL_DEFAULT); // 初始化libcurl
chdir("/switch/Lenheart/"); chdir("/switch/DNF/");
#else #else
AllocConsole(); AllocConsole();
SetConsoleTitleA("Yosin & Engine"); SetConsoleTitleA("Yosin & Engine");
@@ -65,8 +66,12 @@ int main(int argc, char *argv[])
// 初始化Image资源系统 // 初始化Image资源系统
Asset_ImagePack::GetInstance(); Asset_ImagePack::GetInstance();
// 初始化音频资源系统
Asset_SoundPack::GetInstance();
// 初始化脚本资源系统 // 初始化脚本资源系统
Asset_Script::GetInstance(); Asset_Script::GetInstance();
// 初始化线程池 // 初始化线程池
ThreadPool::GetInstance(); ThreadPool::GetInstance();
// 初始化日志系统 // 初始化日志系统